/*
 * 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.core;

import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import org.openide.ErrorManager;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.Repository;
import org.netbeans.modules.openide.explorer.PsSettings;

/** Non-public settings storage for a few trivial settings the
 * property sheet needs to store.  Should be migrated to use
 * registry and eliminate this class for post 3.6 - for now,
 * this will do.  See <a href="http://www.netbeans.org/issues/show_bug.cgi?id=36157">
 * issuezilla issue 36157</a> for details.
 *
 * @author  Tim Boudreau */
public class PsSettingsImpl extends PsSettings {
    /** File name for our trivial settings file */
    private static final String FILE_NAME = "pssettings.36"; //NOI18N
    /** Version key for our trivial settings file.  Hopefully it
     * will not exist past 3.6, but in that unlikely event, it can
     * provide some future-proofing */
    private static final String KEY_VERSION = "version"; //NOI18N
    /** The version value I hope we'll never need */
    private static final String VERSION = "1.0"; //NOI18N
    
    /** Some simple debug logging */
    private static Boolean log = null;

    /** Holds a weak reference to the settings file */
    private Reference settingsFile = null;
    
    /** Default constructor for lookup. */
    public PsSettingsImpl() {
        log ("Creating default instance of PsSettingsImpl"); //NOI18N
    }
    
    /** Fetch an integer from the settings, returning the default value if
     * no settings are stored or an error is encountered */
    public int getInt(String key, int defaultValue) {
        String sval = get(key, null);
        if (sval != null) {
            try {
                return Integer.decode(sval).intValue();
            } catch (NumberFormatException nfe) {
                ErrorManager.getDefault().notify (ErrorManager.WARNING, nfe);
            }
        }
        return defaultValue;
    }
    
    /** Put an integer to the settings */
    public void putInt(String key, int value) {
        log ("Putting value " + value + " for " + key); //NOI18N
        try {
            String ival = Integer.toString(value);
            put (key, ival);
        } catch (NumberFormatException nfe) {
            ErrorManager.getDefault().notify(ErrorManager.WARNING, nfe);
        }
    }    

    /** Put a boolean to the settings */
    public void putBoolean (String key, boolean value) {
        log ("Putting value " + value + " for " + key); //NOI18N
        String sval = value ? Boolean.TRUE.toString() : Boolean.FALSE.toString();
        put (key, sval);
    }
    
    /** Fetch an boolean from the settings, returning the default value if
     * no settings are stored or an error is encountered */
    public boolean getBoolean (String key, boolean defaultValue) {
        log ("getBoolean value " + key); //NOI18N
        String sval = get (key, null);
        return sval != null ? Boolean.TRUE.toString().equals(sval) : defaultValue;
    }
    
    /** Put a String to the settings.  All other put methods convert values to
     * strings and delegate to this method */
    public void put (String key, String value) {
        log ("put " + key + " as " + value);  //NOI18N
        FileObject fo = getSettingsFile (true);
        if (fo != null) { //only null if IOException, already logged
            try {
                fo.setAttribute(key, value);
            } catch (IOException ioe) {
                ErrorManager.getDefault().notify (ErrorManager.WARNING, ioe);
            }
        } else {
            log ("  problem finding file object"); //NOI18N
        }
    }
    
    /** Fetch an String from the settings, returning the default value if
     * no settings are stored or an error is encountered.  All other methods
     * delegate here and convert from String. */
    public String get (String key, String defaultValue) {
        log ("get " + key); //NOI18N
        
        FileObject fo = getSettingsFile (false);
        if (fo != null) {
            Object o =  fo.getAttribute(key);
            log ("  found " + o + " for " + key); //NOI18N
            
            if (o instanceof String) {
                return (String) o;
            } else if (o != null) {
                ClassCastException cce = new ClassCastException (
                    fo + " attribute " + key + 
                    " should be an instance of String, not " + o.getClass() + 
                    "(" + o + ")"); //NOI18N
                ErrorManager.getDefault().notify(ErrorManager.WARNING, cce);
            }
        }
        return defaultValue;
    }

    /** Get the settings file whose attributes are piggybacked for setting
     * storage.  Returns the cached object if it is cached.
     */
    private FileObject getSettingsFile(boolean create) {
        FileObject result = null;
        if (settingsFile != null) {
            result = (FileObject) settingsFile.get();
        }
        if (result == null) {
            result = findFileObject(create);
            if (result != null) {
                settingsFile = new WeakReference (result);
            }
        }
        return result;
    }

    /** Locates, possibly creates the file object used for settings storage */
    private FileObject findFileObject (boolean create) {
        try {
            FileSystem fs = Repository.getDefault().getDefaultFileSystem();
            FileObject result = fs.findResource(FILE_NAME);
            if (create && result == null) {
                result = fs.getRoot().createData(FILE_NAME);
                result.setAttribute(KEY_VERSION, VERSION);
            }
            return result;
        } catch (IOException ioe) {
            ErrorManager.getDefault().notify (ErrorManager.WARNING, ioe);
            return null;
        }
    }
    
    /** Debug logging */
    private static void log (String s) {
        if (log == null) {
            log = ErrorManager.getDefault().getInstance(
                PsSettingsImpl.class.getName()).isLoggable (
                ErrorManager.INFORMATIONAL) ? Boolean.TRUE : Boolean.FALSE;
        }
        if (log.booleanValue()) {
            
            ErrorManager.getDefault().getInstance(
                PsSettingsImpl.class.getName()).log (s);
            
        }
    }
}
