/*
 * Copyright (C) 2009-2017 Alistair Neil <info@dazzleships.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package lib;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Alistair Neil <info@dazzleships.net>
 */
public final class SimpleProps {

    private final File fileStore;
    private final String comment;
    private final ArrayList<String> alChanged;
    private boolean boolDefaultEnabled;
    private final Properties defProps = new Properties();
    private Properties appProps;

    /**
     * Constructor, requires
     *
     * @param filepath
     * @param comment
     */
    public SimpleProps(String filepath, String comment) {
        alChanged = new ArrayList<>();
        fileStore = new File(filepath);
        this.comment = comment;
    }

    /**
     * Enable/disable default mode
     *
     * @param enabled
     */
    public void setDefaultModeEnabled(boolean enabled) {
        boolDefaultEnabled = enabled;
    }

    /**
     * Set a long number property
     *
     * @param property
     * @param num
     */
    public void setLong(String property, long num) {
        String value = String.valueOf(num);
        setString(property, value);
    }

    /**
     * Get a long number property
     *
     * @param property
     * @return A long number
     */
    public long getLong(String property) {
        try {
            if (boolDefaultEnabled) {
                return Long.parseLong(defProps.getProperty(property));
            } else {
                return Long.parseLong(appProps.getProperty(property));
            }
        } catch (NumberFormatException ex) {
            Logger.getGlobal().logp(Level.WARNING, this.getClass().getName(), "getLong", "", ex);
            return -1;
        }
    }

    /**
     * Set a integer number property
     *
     * @param property
     * @param num
     */
    public void setInt(String property, int num) {
        String value = String.valueOf(num);
        setString(property, value);
    }

    /**
     * Get an integer number property
     *
     * @param property
     * @return an integer
     */
    public int getInt(String property) {
        try {
            if (boolDefaultEnabled) {
                return Integer.parseInt(defProps.getProperty(property));
            } else {
                return Integer.parseInt(appProps.getProperty(property));
            }
        } catch (NumberFormatException ex) {
            Logger.getGlobal().logp(Level.WARNING, this.getClass().getName(), "getInt", "", ex);
            return -1;
        }
    }

    /**
     * Set a boolean property
     *
     * @param property
     * @param enabled
     */
    public void setBool(String property, boolean enabled) {
        if (enabled) {
            setString(property, "true");
        } else {
            setString(property, "false");
        }
    }

    /**
     * Get a boolean property
     *
     * @param property
     * @return boolean
     */
    public boolean getBool(String property) {
        try {
            String result;
            if (boolDefaultEnabled) {
                result = defProps.getProperty(property).toLowerCase();
            } else {
                result = appProps.getProperty(property).toLowerCase();
            }
            return result.contentEquals("true");
        } catch (Exception ex) {
            Logger.getGlobal().logp(Level.WARNING, this.getClass().getName(), "getBool", "", ex);
            return false;
        }
    }

    /**
     * Set a String property
     *
     * @param key
     * @param value
     * @return String
     */
    public Object setString(String key, String value) {
        value = value.trim();
        if (boolDefaultEnabled) {
            return defProps.setProperty(key, value);
        }
        String prop = appProps.getProperty(key);
        if (prop == null) {
            prop = "null";
        }
        if (prop.contentEquals(value)) {
            if (alChanged.contains(key)) {
                alChanged.remove(key);
            }
        } else {
            if (!alChanged.contains(key)) {
                alChanged.add(key);
            }
        }
        return appProps.setProperty(key, value);
    }

    /**
     * Get a String property
     *
     * @param key
     * @return String or null
     */
    public String getString(String key) {
        try {
            String prop;
            if (boolDefaultEnabled) {
                prop = defProps.getProperty(key);
            } else {
                prop = appProps.getProperty(key);
            }
            if (prop == null) {
                prop = "";
            }
            return prop;
        } catch (Exception ex) {
            Logger.getGlobal().logp(Level.WARNING, this.getClass().getName(), "getString", "", ex);
            return null;
        }
    }

    /**
     * Save to xml file
     */
    public void save() {
        alChanged.clear();
        OutputStream os = null;
        try {
            os = new FileOutputStream(fileStore);
            appProps.storeToXML(os, comment);
        } catch (Exception ex) {
            Logger.getLogger(SimpleProps.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
            } catch (Exception ex) {

            }
        }
    }

    /**
     * Load from xml file
     */
    public void load() {
        InputStream is = null;
        try {
            if (!fileStore.exists()) {
                fileStore.getParentFile().mkdirs();
                fileStore.createNewFile();
                save();
            }
            is = new FileInputStream(fileStore);
            appProps.loadFromXML(is);
        } catch (IOException ex) {
            Logger.getLogger(SimpleProps.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (Exception ex) {
            }
        }
        alChanged.clear();
    }

    /**
     * Delete the properties file store
     *
     * @return true if successful
     */
    public boolean delete() {
        if (fileStore.exists()) {
            return fileStore.delete();
        }
        return false;
    }

    /**
     * Get a comma separated list of properties that were changed
     *
     * @return A String of property keys that were changed
     */
    public String getChangedProperties() {
        return alChanged.toString();
    }

    /**
     * Reset to defaults
     */
    public void resetToDefaults() {
        appProps = new Properties(defProps);
        alChanged.clear();
    }

}
