/*
 * 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.beans.PropertyEditorSupport;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Map;
import java.util.Random;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.Repository;

import org.openide.options.SystemOption;
import org.openide.util.HelpCtx;
import org.openide.util.NbBundle;

/** Options autoupdate module
*
* @author Petr Hrebejk
*/
public class Settings extends SystemOption //implements ViewerConstants
{

    private static final String PROP_ASK_BEFORE = "askBefore"; // NOI18N
    private static final String PROP_NEGATIVE_RESULTS = "negativeResults"; // NOI18N
    private static final String PROP_PERIOD = "period"; // NOI18N
    private static final String PROP_LAST_CHECK = "lastCheck"; // NOI18N
    private static final String PROP_IDE_IDENTITY = "ideIdentity"; // NOI18N
    private static final String PROP_ACCEPTED_NOTIFICATIONS = "acceptedNotifications"; // NOI18N
    
    public static final int EVERY_STARTUP = 0;
    public static final int EVERY_DAY = 1;
    public static final int EVERY_WEEK = 2;
    public static final int EVERY_2WEEKS = 3;
    public static final int EVERY_MONTH = 4;
    public static final int EVERY_NEVER = 5;
    
    /** NODE_DEFAULT_ACTION property */
    public static final String NODE_DEFAULT_ACTION = "nodeDefaultAction"; // NOI18N

    /** serialVersionUID */
    static final long serialVersionUID = 362844553936969452L;

    private static final Random RANDOM = new Random ();
    private static final ErrorManager err = ErrorManager.getDefault().getInstance("org.netbeans.modules.autoupdate.Settings"); // NOI18N
    private String tempIdeIdentity = null;
    
    /** members to show */
    //private static int period = EVERY_STARTUP;

    /** Ask before check */
    // private static boolean askBefore = true;

    /** Show negative results */
    // private static boolean negativeResults = true;

    /** Last time the web was checked automatically checked for updates */
    // private static Date lastCheck = new Date();

    // do NOT use constructore for setting default values
    protected void initialize () {
        // Set default values of properties
        
        super.initialize ();

        // by the task #39533, user shoudln't be inform about negative results
        setNegativeResults( false );
        setPeriod( EVERY_WEEK );
        // setLastCheck( new Date() );
        setLastCheck( null );        
        
        // task # 41342
        setAskBefore( false );
    }
    
    static Settings getShared() {
        return (Settings)findObject( Settings.class, true );
    }

    /** @return human presentable name */
    public String displayName() {
        return getBundle("CTL_Settings_Name");
    }

    public HelpCtx getHelpCtx () {
        return new HelpCtx ( Settings.class );
    }

    /** Getter for period
    */
    public int getPeriod() {
        return ((Integer)getProperty( PROP_PERIOD )).intValue();
        //return period;
    }

    /** Setter for period
    */
    public void setPeriod( int period ) {
        putProperty( PROP_PERIOD, new Integer( period ), true );
        //this.period = period;
    }
    
    /** Allows subclasses to override the default autoupdate type.
    */
    protected AutoupdateType defaultAutoupdateType() {
        return AutoupdateType.getDefault ();
    }

    public void setIdeIdentity (String identity) {
        putProperty (PROP_IDE_IDENTITY, identity, true);
    }

    public String getIdeIdentity () {
        if (tempIdeIdentity instanceof String) {
            return tempIdeIdentity;
        }
        Object oldIdeIdentity = getProperty (PROP_IDE_IDENTITY);
        String newIdeIdentity = null;
        if (oldIdeIdentity == null) {
            newIdeIdentity = modifyIdeIdentityIfNeeded (Integer.toString (generateNewId ()));
        } else {
            newIdeIdentity = modifyIdeIdentityIfNeeded ((String) oldIdeIdentity);
        }
        tempIdeIdentity = newIdeIdentity;
        if (! newIdeIdentity.equals (oldIdeIdentity)) {
            err.log ("Put new value of PROP_IDE_IDENTITY to " + newIdeIdentity);
            putProperty (PROP_IDE_IDENTITY, newIdeIdentity, true);
        }
        return tempIdeIdentity;
    }
    
    public void setAcceptedNotifications (Map notifications) {
        putProperty (PROP_ACCEPTED_NOTIFICATIONS, notifications, true);
    }

    public Map getAcceptedNotifications () {
        return (Map)getProperty (PROP_ACCEPTED_NOTIFICATIONS);
    }
    
    /** Getter for askBefore
    */
    public boolean isAskBefore () {
        return ((Boolean)getProperty( PROP_ASK_BEFORE )).booleanValue();
        //return askBefore;
    }

    /** Setter for askBefore
    */
    public void setAskBefore (boolean askBefore) {
        //this.askBefore = askBefore;
        putProperty( PROP_ASK_BEFORE, askBefore  ? Boolean.TRUE : Boolean.FALSE, true );
    }

    /** Getter for negativeResults
    */
    public boolean isNegativeResults () {
        return ((Boolean)getProperty( PROP_NEGATIVE_RESULTS )).booleanValue();
        //return negativeResults;
    }

    /** Setter for negativeResults
    */
    public void setNegativeResults (boolean negativeResults) {
        putProperty( PROP_NEGATIVE_RESULTS, negativeResults  ? Boolean.TRUE : Boolean.FALSE, true );
        //this.negativeResults = negativeResults;
    }

    /** Getter for last check
    */
    public Date getLastCheck() {
        return ((Date)getProperty( PROP_LAST_CHECK ));

    }

    /** Setter for last check
    */
    public void setLastCheck( Date lastCheck ) {
        putProperty( PROP_LAST_CHECK, lastCheck, true );
        //this.lastCheck = lastCheck;
    }
    
    public void fireNodeDefaultAction() {
        firePropertyChange(NODE_DEFAULT_ACTION, null, null);
    }

    private static String getBundle( String key ) {
        return NbBundle.getMessage( Settings.class, key );
    }
    
    /** property editor for period property
    */
    public static class PeriodPropertyEditor extends PropertyEditorSupport {

        /** Array of tags
        */
        private static final String[] tags = {
            getBundle( "CTL_PeriodEditor_Startup" ),
            getBundle( "CTL_PeriodEditor_Day" ),
            getBundle( "CTL_PeriodEditor_Week" ),
            getBundle( "CTL_PeriodEditor_2Weeks" ),
            getBundle( "CTL_PeriodEditor_Month" ),
            getBundle( "CTL_PeriodEditor_Never" ) } ;

        private static final int [] values = {
            Settings.EVERY_STARTUP,
            Settings.EVERY_DAY,
            Settings.EVERY_WEEK,
            Settings.EVERY_2WEEKS,
            Settings.EVERY_MONTH,
            Settings.EVERY_NEVER };

        /** @return names of the supported member Acces types */
        public String[] getTags() {
            return tags;
        }

        /** @return text for the current value */
        public String getAsText () {
            long value = ((Integer)getValue()).intValue();

            for (int i = 0; i < values.length ; i++)
                if (values[i] == value)
                    return tags[i];

            return getBundle( "CTL_PeriodEditor_Unsupported" );
        }

        /** @param text A text for the current value. */
        public void setAsText (String text) {
            for (int i = 0; i < tags.length ; i++)
                if (tags[i] == text) {
                    setValue(new Integer(values[i]));
                    return;
                }

            setValue( new Integer(0) );
        }
    }            

    /** property editor for last check property
    */
    public static class LastCheckPropertyEditor extends PropertyEditorSupport {

        private static final SimpleDateFormat sdf = new SimpleDateFormat();


        /** @return text for the current value */
        public String getAsText () {            
            Date dt = (Date)getValue();
            return (dt == null) ? "" : sdf.format( dt ); // NOI18N
        }

        /** @param text A text for the current value. */
        public void setAsText (String text) {

            try {
                Date newValue = sdf.parse( text );
                setValue( newValue );
            }
            catch ( java.text.ParseException e ) {
                // leave the old value if the user types some nocense
            }
        }
    }

    // helper methods
    private static String modifyIdeIdentityIfNeeded (String oldIdeIdentity) {
        String [] ideIdentityArr = oldIdeIdentity.split ("\\d"); // NOI18N
        String id = null;
        String oldPrefix = null;
        if (ideIdentityArr.length == 0) {
            id = oldIdeIdentity;
            oldPrefix = "";
        } else {
            assert ideIdentityArr.length == 1 : "ideIdentityArr cannot be greater then 1!";
            oldPrefix = ideIdentityArr [0];
            id = oldIdeIdentity.substring (oldPrefix.length ());
        }
        err.log ("Old IDE Identity Prefix: " + oldPrefix); // NOI18N
        err.log ("Old IDE Identity ID: " + id); // NOI18N
        String newPrefix = "";
        try {
            FileObject fo = Repository.getDefault().getDefaultFileSystem().findResource("/productid"); // NOI18N
            if (fo != null) {
                InputStream is = fo.getInputStream();
                try {
                    BufferedReader r = new BufferedReader(new InputStreamReader(is));
                    newPrefix = r.readLine().trim();
                } finally {
                    is.close();
                }
            }
        } catch (IOException ignore) {
            // IGNORE
        }
        if (!newPrefix.equals (oldPrefix)) {
            err.log ("New IDE Identity Prefix: " + newPrefix); // NOI18N
        } else {
            err.log ("No new prefix."); // NOI18N
        }
        return newPrefix + id;
    }

    private static int generateNewId () {
        int id = RANDOM.nextInt ();
        if (id < 0) {
            id = - (id + 1);
        }
        return id;
    }
    
}
