/***************************************************************************
 *   Copyright (C) 2009 by Paul Lutus                                      *
 *   lutusp@arachnoid.com                                                  *
 *                                                                         *
 *   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.             *
 ***************************************************************************/
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fftexplorer;

import java.lang.reflect.Field;
import java.util.*;
import java.awt.*;
import java.io.*;
import java.util.Scanner.*;
import javax.swing.*;

/**
 *
 * @author lutusp
 */
final public class InitManager {

    FFTExplorer parent;
    String fileSep;
    String lineSep;
    String appName;
    String userDir;
    String userPath;
    String initPath;
    String fieldPrefix = "sv_";

    public InitManager(FFTExplorer p, boolean isApplet) {
        parent = p;
        lineSep = System.getProperty("line.separator");
        fileSep = System.getProperty("file.separator");
        appName = parent.getClass().getSimpleName();
        if (!isApplet) {
            userDir = System.getProperty("user.home");
            userPath = userDir + fileSep + "." + appName;
            initPath = userPath + fileSep + appName + ".ini";
            testMakeDirs(userPath);
        }
    }

    String[] parsePair(String val) {
        String pair[] = null;
        int p = val.indexOf("=");
        if (p > 0) {
            pair = new String[]{val.substring(0, p), val.substring(p + 1, val.length())};
            for (int i = 0; i < 2 && i < pair.length; i++) {
                pair[i] = pair[i].replaceFirst("^\\s*(.*?)\\s*$", "$1");
            }
        }
        return pair;
    }

    public void setConfig(String data) {
        if (data != null) {
            String values[] = data.split(lineSep);
            for (int i = 0; i < values.length; i++) {
                String item = strip(values[i]);
                item = item.replaceFirst("#.*$", "");
                if (item.length() > 0) {
                    String[] pair = parsePair(item);
                    readWriteField(parent, pair[0], pair[1]);
                }
            }
        }
    }

    public void readConfig() {
        String data = readTextFile(initPath, lineSep);
        setConfig(data);
    }

    // parsing a rectangle'a textual representation
    // is really quite a pain
    Rectangle parseRectangle(String value) {
        Vector<Integer> vi = new Vector<Integer>();
        Rectangle rect = null;
        try {
            String s = value.replaceFirst("^.*x=([-|\\d]+).*y=([-|\\d]+).*width=([-|\\d]+).*height=([-|\\d]+).*$", "$1,$2,$3,$4");
            String s_vals[] = s.split(",");
            for (int j = 0; j < s_vals.length; j++) {
                vi.add(Integer.parseInt(s_vals[j]));
            }
            Iterator<Integer> it = vi.iterator();
            rect = new Rectangle(it.next(), it.next(), it.next(), it.next());
        } catch (Exception e) {
            System.out.println(getClass().getName() + ": error: " + e);
        }
        return rect;
    }

    String readWriteField(Component comp, String name, String value) {
        try {
            Class pc = comp.getClass();
            //System.out.println("looking for [" + pair[0] + "]");
            Field f = pc.getDeclaredField(name);
            Object obj = f.get(comp); // get the class instance
            String classType = f.getType().toString();
            //System.out.println("name: " + name + ", classtype: " + classType);
            classType = classType.replaceFirst(".*\\.(.*)", "$1");
            boolean write = (value != null);
            if (write) {
                value = strip(value);
            }
            if (classType.equals("int")) {
                if (write) {
                    f.setInt(comp, Integer.parseInt(value));
                } else {
                    value = "" + f.getInt(comp);
                }
            } else if (classType.equals("double")) {
                if (write) {
                    f.setDouble(comp, parent.getDouble(value));
                } else {
                    value = "" + parent.formatNum(f.getDouble(comp));
                }
            } else if (classType.equals("MutableDouble")) {
                if (write) {
                    ((MutableDouble) obj).v = parent.getDouble(value);
                } else {
                    value = "" + ((MutableDouble) obj).v;
                }
            } else if (classType.equals("boolean")) {
                if (write) {
                    f.setBoolean(comp, value.equals("true"));
                } else {
                    value = "" + f.getBoolean(comp);
                }
            } else if (classType.equals("String")) {
                if (write) {
                    f.set(comp, value);
                } else {
                    value = (String) f.get(comp);
                }
            } else if (classType.equals("Rectangle")) {
                if (write) {
                    Rectangle r = parseRectangle(value);
                    if (r != null) {
                        f.set(comp, r);
                    }
                } else {
                    value = (String) f.get(comp).toString();
                }
            } else if (classType.equals("JRadioButton")) {
                JRadioButton button = (JRadioButton) obj;
                if (write) {
                    button.setSelected(value.equals("true"));
                } else {
                    value = "" + button.isSelected();
                }
            } else if (classType.equals("JCheckBox")) {
                JCheckBox cb = (JCheckBox) obj;
                if (write) {
                    cb.setSelected(value.equals("true"));
                } else {
                    value = "" + cb.isSelected();
                }
            } else if (classType.equals("JTextField")) {
                JTextField tf = (JTextField) obj;
                if (write) {
                    tf.setText(value);
                } else {
                    value = tf.getText();
                }
            } else if (classType.equals("JComboBox")) {
                JComboBox box = (JComboBox) obj;
                if (write) {
                    box.setSelectedIndex(Integer.parseInt(value));
                } else {
                    value = "" + box.getSelectedIndex();
                }
            } else if (classType.equals("JSpinner")) {
                JSpinner box = (JSpinner) obj;
                if (write) {
                    box.setValue(Integer.parseInt(value));
                } else {
                    value = "" + box.getValue();
                }
            }else if (classType.equals("JScrollBar")) {
                JScrollBar box = (JScrollBar) obj;
                if (write) {
                    int v = Integer.parseInt(value);
                    box.setValue(v);
                } else {
                    value = "" + box.getValue();
                }
            } else if (classType.equals("JTabbedPane")) {
                JTabbedPane tp = (JTabbedPane) obj;
                if (write) {
                    tp.setSelectedIndex(Integer.parseInt(value));
                } else {
                    value = "" + tp.getSelectedIndex();
                }
            } else if (classType.equals("ColorButton")) {
                ColorButton tp = (ColorButton) obj;
                if (write) {
                    tp.setColor(value);
                } else {
                    value = "" + tp;
                }
            } else if (classType.equals("JFrame")) {
                // only to set screen geometry
                JFrame tp = (JFrame) obj;
                if (obj != null) {
                    if (write) {
                        Rectangle r = parseRectangle(value);
                        if (r != null) {
                            tp.setBounds(r);
                        }
                    } else {
                        value = "" + tp.getBounds();
                    }
                }
            } else {
                System.out.println(getClass().getName() + ": cannot decode value for " + classType + " (" + name + ")");
            }
        } catch (Exception e) {
            System.out.println(getClass().getName() + ":readWriteField: \"" + name + "\": " + e);
            e.printStackTrace();
        }
        return value;
    }

    public void writeConfig() {
        try {
            BufferedWriter bw = new BufferedWriter(new FileWriter(initPath));
            bw.write(getConfig());
            bw.close();
        } catch (IOException e) {
            System.out.println(e);
        }
    }

    public String getConfig() {
        Vector<String> data = new Vector<String>();
        Hashtable<String, Field> fnht = getFieldNames();
        //String name = "", value = "";
        String name, value;
        Field field;
        Enumeration en = fnht.keys();
        while (en.hasMoreElements()) {
            field = fnht.get(en.nextElement());
            name = field.getName();
            value = readWriteField(parent, name, null);
            if (value != null) {
                data.add(name + " = " + value);
            }
        }
        Collections.sort(data, new StringComparatorNoCase());
        String[] array = (String[]) data.toArray(new String[]{});
        return join(array, lineSep) + lineSep;
    }

    Hashtable<String, Field> getFieldNames() {
        Hashtable<String, Field> hash = new Hashtable<String,Field>();
        Field[] fields = parent.getClass().getDeclaredFields();
        String name;
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            name = field.getName();
            if (name.matches("^" + fieldPrefix + ".*")) {
                hash.put(name, field);
            }
        }
        return hash;
    }

    String readTextFile(String path, String lineSep) {
        String s = null;
        File f = new File(path);
        if (f.exists()) {
            StringBuffer sb = new StringBuffer();
            try {
                BufferedReader br = new BufferedReader(new FileReader(f));
                String line;
                while ((line = br.readLine()) != null) {
                    sb.append(line + lineSep);
                }
                br.close();
                s = sb.toString();
            } catch (Exception e) {
                //System.out.println(e);
            }
        }
        return s;
    }

    boolean testMakeDirs(String path) {
        File fpath = new File(path);
        if (fpath.exists()) {
            return false;
        } else {
            fpath.mkdirs();
            return true;
        }
    }

    String join(String[] array, String delim) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < array.length; i++) {
            if (i > 0) {
                sb.append(delim);
            }
            sb.append(array[i]);
        }
        return sb.toString();
    }

    String strip(String s) {
        return s.replaceFirst("^\\s*(.*?)\\s*$", "$1");
    }
}
