/*
 * The contents of this file are subject to the terms of the Common Development
 * and Distribution License (the License). You may not use this file except in
 * compliance with the License.
 * 
 * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
 * or http://www.netbeans.org/cddl.txt.
 * 
 * When distributing Covered Code, include this CDDL Header Notice in each file
 * and include the License file at http://www.netbeans.org/cddl.txt.
 * If applicable, add the following below the CDDL Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.autoupdate;

import java.io.File;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.openide.modules.Dependency;
import org.openide.modules.ModuleInfo;
import org.openide.modules.SpecificationVersion;
import org.openide.util.NbBundle;
import org.w3c.dom.*;

/** This class represents one module l10n update available on the web
 *
 * @author  Ales Kemr
 * @version 
 */
class L10NUpdate extends ModuleUpdate {

    private static final String ATTR_LONG_DESC = "OpenIDE-Module-Long-Description"; // NOI18N
    /** Holds value of property langcode. */
    private String langcode;
    
    /** Holds value of property brandingcode. */
    private String brandingcode;
    
    /** Holds value of property specversion. */
    private SpecificationVersion specversion;
    
    /** Holds value of property majorversion. */
    private int majorversion;
    
    /** Holds value of property l10nname. */
    private String l10nname;
    
    /** Holds value of property l10ndesc. */
    private String l10ndesc;
    
    private L10NModuleInfo remoteinfo;
    
    L10NUpdate( URL xmlURL, Node node, Element documentElement ) {
        super( xmlURL, node, documentElement );
    }

    /** Creates new L10NUpdate for downloaded .nbm file */
    L10NUpdate( File nbmFile, Node node, Element documentElement ) {
        super( nbmFile, node, documentElement );
    }
    
    ModuleInfo readRemoteInfo() throws IllegalArgumentException {
        NodeList nodeList = ((Element)getNode()).getElementsByTagName( ModuleUpdate.ELEMENT_L10N );

        if ( nodeList.getLength() > 0 ) {
            Node n = nodeList.item( 0 );
            
            langcode = getAttribute( n, "langcode" ); // NOI18N
            brandingcode = getAttribute( n, "brandingcode" ); // NOI18N
            specversion = new SpecificationVersion ( getAttribute( n, "module_spec_version" ) ); // NOI18N
            String mvAttr = getAttribute( n, "module_major_version" ); // NOI18N
            if ( mvAttr != null ) {
                majorversion = Integer.parseInt( mvAttr );
            }
            else {
                majorversion = -1;
            }
            l10nname = getAttribute( n, "OpenIDE-Module-Name" ); // NOI18N
            l10ndesc = getAttribute( n, ATTR_LONG_DESC );
            if ( getDescription() == null || getDescription().equals ("") )   // NOI18N
                setDescription( l10ndesc );
        }
        
        remoteinfo = new L10NModuleInfo();
        remoteinfo.setName( l10nname );
        remoteinfo.setCodeNameBase( getInfoCodenamebase() );
        remoteinfo.setMajorversion( majorversion );
        remoteinfo.setSpecificationVersion( specversion );
        remoteinfo.setDependency( getInfoCodenamebase(), majorversion );
        
        return remoteinfo;
    }
    
    ModuleInfo readLocalInfo() {
        ModuleInfo localmodule = super.readLocalInfo();
        L10NModuleInfo localinfo = null;
        
        if ( localmodule != null ) {
            if ( l10nname == null  || l10nname.equals ("") )   // NOI18N
                remoteinfo.setName( localmodule.getDisplayName() );
            if ( getDescription() == null || getDescription().equals ("") )   // NOI18N
                setDescription( (String) localmodule.getLocalizedAttribute( ATTR_LONG_DESC ) );
            
            // get spec vers from update_tracking
            SafeModule.ModuleStatus status = SafeModule.getModuleStatus( getInfoCodenamebase() );
            if ( status != null ) {
                String jarpath = status.getJarPath() + "locale/" + status.getJarName();    // NOI18N
                if ( brandingcode != null && brandingcode.length() > 0 ) {
                    jarpath = jarpath + "_" + brandingcode;    // NOI18N
                }
                if ( langcode != null && langcode.length() > 0 ) {
                    jarpath = jarpath + "_" + langcode;    // NOI18N
                }
                jarpath = jarpath + ".jar";   // NOI18N
                SpecificationVersion specvers = getTrackingSpecVersion( jarpath );
                localinfo = new L10NModuleInfo();
                localinfo.setName( remoteinfo.getDisplayName() );
                localinfo.setCodeNameBase( getInfoCodenamebase() );
                if ( specvers != null ) {
                    localinfo.setSpecificationVersion( specvers );
                }
            }
            markNamesWithL10N();
        }
        
        return localinfo;
    }
    
    private void markNamesWithL10N() {
        String desc = "";
        if ( langcode != null && langcode.length() > 0 ) {
            String lang = new Locale( langcode, "" ).getDisplayLanguage();  // NOI18N
            desc = NbBundle.getMessage( L10NUpdate.class, "TXT_L10N_Prefix",  // NOI18N
                              lang );
        }
        if ( brandingcode != null && brandingcode.length() > 0 ) {
            if ( langcode != null && langcode.length() > 0 )
                desc = desc + ", ";    // NOI18N
            desc = desc + NbBundle.getMessage( L10NUpdate.class, "TXT_L10N_Branding",  // NOI18N
                              brandingcode );
        }
        if ( desc.length() > 0 ) {
            desc = desc + NbBundle.getMessage (L10NUpdate.class, "TXT_L10N_DescEnd"); // NOI18N
        }
        
        desc = desc + getDescription();
        setDescription( desc );
        
        if ( l10nname == null  || l10nname.equals ("") ) { // NOI18N
            String dname = remoteinfo.getDisplayName() + " (";
            if ( langcode != null && langcode.length() > 0 ) {
                dname = dname + langcode;    // NOI18N
            }
            if ( brandingcode != null && brandingcode.length() > 0 ) {
                if ( langcode != null && langcode.length() > 0 )
                    dname = dname + " ";    // NOI18N
                dname = dname + brandingcode;
            }
            dname = dname + ")";
            remoteinfo.setName( dname );  // NOI18N
        }
    }
    
    private SpecificationVersion getTrackingSpecVersion(String jarpath) {
        Iterator it = org.netbeans.updater.UpdateTracking.clusters (true).iterator ();
        while (it.hasNext ()) {
            File clusterDir = (File)it.next ();
            org.netbeans.updater.UpdateTracking tracking;
            tracking = org.netbeans.updater.UpdateTracking.getTracking (clusterDir, false);
            if (tracking == null) {
                // skip directory without update_tracking info
                continue;
            }
            
            String specversU = tracking.getL10NSpecificationVersion( getInfoCodenamebase(), true, jarpath );
            String specversI = tracking.getL10NSpecificationVersion( getInfoCodenamebase(), false, jarpath );
            if ( specversU == null && specversI == null )
                continue;
        
            SpecificationVersion svU = ( specversU != null ) ? new SpecificationVersion( specversU ) : null;
            SpecificationVersion svI = ( specversI != null ) ? new SpecificationVersion( specversI ) : null;

            if ( svI != null && svU == null)
                return svI;
            else if ( svI == null && svU != null )
                return svU;

            if ( svI.compareTo( svU ) > 0 )
                return svI;
            else
                return svU;
        }
        return null;
    }
    
    private String getAttribute(Node n, String attribute) {
        Node attr = n.getAttributes().getNamedItem( attribute );
        return attr == null ? null : attr.getNodeValue();
    }
    
    /** Getter for property langcode.
     * @return Value of property langcode.
     *
     */
    String getLangcode() {
        return langcode;
    }
    
    /** Getter for property brandingcode.
     * @return Value of property brandingcode.
     *
     */
    String getBrandingcode() {
        return brandingcode;
    }
    
    /** Getter for property majorversion.
     * @return Value of property majorversion.
     *
     */
    int getMajorversion() {
        return majorversion;
    }
    
    /** Getter for property l10nname.
     * @return Value of property l10nname.
     *
     */
    String getL10nname() {
        return l10nname;
    }
    
    /** Getter for property l10ndesc.
     * @return Value of property l10ndesc.
     *
     */
    String getL10ndesc() {
        return l10ndesc;
    }
    
    // overwritten from ModuleUpdate
    
    /** Tests if there is an update available */
    boolean isUpdateAvailable() {
        if ( getLocalModule() != null && 
                ( getLocalModule().getSpecificationVersion() == null
                 || getLocalModule().getSpecificationVersion().compareTo( remoteinfo.getSpecificationVersion() ) < 0
                ) ) {
            return true;
        }
        
        return false;
    }
    
    boolean isRemoteModuleAvailable( List modules ) {
        Iterator it = modules.iterator();
        while ( it.hasNext() ) {
            ModuleUpdate module = (ModuleUpdate) it.next();
            if ( module.getCodeNameBase().equals( remoteinfo.getCodeNameBase() )
                    && module.getRemoteModule().getSpecificationVersion().compareTo( remoteinfo.getSpecificationVersion()) <= 0) { // < bug 6174967/>
                if ( remoteinfo.getDisplayName() == null || remoteinfo.getDisplayName().equals ("") )   // NOI18N
                    remoteinfo.setName( module.getRemoteModule().getDisplayName() );
                if ( getDescription() == null || getDescription().equals ("") )   // NOI18N
                    setDescription( (String) module.getRemoteModule().getLocalizedAttribute( ATTR_LONG_DESC ) );
                markNamesWithL10N();
                return true;
            }
        }
        
        return false;
    }
    
    class L10NModuleInfo extends ModuleInfo {
        
        private SpecificationVersion specversion;
        private String name;
        private Set dep;
        private String codenamebase;
        private int majorversion;
        
        public L10NModuleInfo() {
        }
        
        void setSpecificationVersion(SpecificationVersion specversion) {
            this.specversion = specversion;
        }
        
        void setName(String name) {
            this.name = name;
        }
        
        void setCodeNameBase(String codenamebase) {
            this.codenamebase = codenamebase;
        }
        
        void setMajorversion(int majorversion) {
            this.majorversion = majorversion;
        }
        
        void setDependency(String codenamebase, int majorversion) {
            String body = codenamebase;
            if ( majorversion > 0 )
                body = body + "/" + majorversion; // NOI18N
            dep = Dependency.create( Dependency.TYPE_MODULE, body );
        }
        
        // implement ModuleInfo
        
        public SpecificationVersion getSpecificationVersion() {
            return specversion;
        }
        
        public String getDisplayName() {
            return name;
        }
        
        /** Get some attribute, for example OpenIDE-Module-Name.
         * Not all manifest attributes need be supported here.
         * Attributes not present in the manifest may be available.
         *
         */
        public Object getAttribute(String attr) {
            return null;
        }
        
        /** The full code name, with release version after slash if defined.  */
        public String getCodeName() {
            return codenamebase + "/" + majorversion; // NOI18N;
        }
        
        /** The code name of the module, sans release version.  */
        public String getCodeNameBase() {
            return codenamebase;
        }
        
        /** The release version (-1 if undefined).  */
        public int getCodeNameRelease() {
            return majorversion;
        }
        
        /** Get a list of all dependencies this module has.  */
        public Set getDependencies() {
            return dep;
        }
        
        /** Get an attribute with localization.
         * That is, if there is a suitable locale variant of the attribute
         * name, return its value rather than the value of the base attribute.
         *
         */
        public Object getLocalizedAttribute(String attr) {
            return null;
        }
        
        /** Whether the module is currently enabled.  */
        public boolean isEnabled() {
            return false;
        }
        
        /** Determine if the provided class
         * was loaded as a part of this module, and thus will only be
         * loadable later if this module is enabled.
         * If in doubt, return <code>false</code>.
         * @since 1.28
         *
         */
        public boolean owns(Class clazz) {
            return false;
        }
        
    }
    
}
