package turgen.config;
import java.awt.*;
import turgen.*;
import java.util.*;
import java.io.*;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class Configuration {

    /**Properties*/
    private static Properties prop=null;
    
    /**Map of classes*/
    private static HashMap classMap=new HashMap();
    
    /**Vector of classes*/
    private static Vector classList=new Vector();
    
    /**Map Entry-Editor*/
    private static HashMap entry2EditorMap;
    
    /**Configuration panel*/
    private static JPanel configPanel=null;


    /** Obtain configuration panel*/
    public static JPanel getConfigPanel() {

        if (configPanel==null) {
            configPanel=createConfigPanel();
            return configPanel;
        }

        ConfigClass c;
        AbstractConfigEntry ace;

        Iterator cit = classList.iterator();
        while(cit.hasNext()) {
            c = (ConfigClass)cit.next();

            Iterator eit = c.getEntries().iterator();

            while(eit.hasNext()) {
                ace = (AbstractConfigEntry)eit.next();
                ace.fillEntryEditor((JComponent)entry2EditorMap.get(ace));
            }
        
        }

        return null;
        
    }

    public static void registerClass(ConfigClass c) {

        /*Check existence*/
        Object o = classMap.get(c.getId());

        /*Add if class does not exist*/
        if (o==null) {
            classMap.put(c.getId(), c);
            classList.add(c);

            /*Set value for entries in the class*/
            Iterator it = c.getEntries().iterator();
            AbstractConfigEntry ace;

            while(it.hasNext()==true) {
                ace=(AbstractConfigEntry)it.next();
                if (prop==null) ace.setEntryValue(null);
                else ace.setEntryValue(prop.getProperty(c.getId()+"."+ace.getEntryKey()));
            }
        }

    }
    
    /**Load configuration*/
    public static void loadOptions() {
        
        prop = new Properties();
        try {
            FileInputStream fis = new FileInputStream(Turgen.configDir+"turgen.properties");
            prop.load(fis);
            fis.close();
        }
        catch(Exception e) {
            prop=null;
            return;
        }
        
        updateRegistredEntries();
    }
    
    public static String saveOptions() {
        
        String fspec=Turgen.configDir+"turgen.properties";
        String retVal="Configuration has been saved to: "+fspec;
        
        prop = new Properties();

        /*Iterate through all classes and save configuration entries*/
        Iterator cit = classList.iterator();

        ConfigClass c;
        AbstractConfigEntry ace;

        while(cit.hasNext()) {
            c = (ConfigClass)cit.next();
            Iterator eit = c.getEntries().iterator();

            while(eit.hasNext()) {
                ace=(AbstractConfigEntry)eit.next();
                String ev = ace.getEntryValue();
                if (ev!=null) {
                    prop.setProperty(c.getId()+"."+ace.getEntryKey(), ev);
                }
            }
        }
        
        try {
            FileOutputStream fos = new FileOutputStream(fspec);
            prop.store(fos,"ts8");
            fos.close();
        }
        catch(Exception e) {
            return Utils.getExceptionMessage(e);
        }
        return retVal;
    }
    
    /**Update entries according to properties*/
    public static void updateRegistredEntries() {

        Iterator cit = classList.iterator();
        ConfigClass c;
        AbstractConfigEntry ace;

        while (cit.hasNext()) {
            c=(ConfigClass)cit.next();

            Iterator eit = c.getEntries().iterator();
            while(eit.hasNext()) {
                ace = (AbstractConfigEntry)eit.next();

                if (prop==null) ace.setEntryValue(null);
                else ace.setEntryValue(prop.getProperty(c.getId()+"."+ace.getEntryKey()));
            }
        }

    }
    

    /**Create panel that allows user to change configuration*/
    public static JPanel createConfigPanel() {
        
        /*New mapping*/
        entry2EditorMap = new HashMap();


        JPanel mainPanel = new JPanel(new BorderLayout(1,1));
        final JPanel cardsPanel = new JPanel(new CardLayout());

        /*Panel and tabbed pane*/
        JScrollPane jsp = new JScrollPane();
        JList jlsClasses = new JList();
        jsp.setViewportView(jlsClasses);

        ConfigClass c;
        Iterator cit = classList.iterator();

        while(cit.hasNext()) {
            c = (ConfigClass)cit.next();

            JPanel px = new JPanel(new BorderLayout());
            px.add("Center", createClassConfigPanel(c));
            cardsPanel.add(c.getId(),px);
        }

        jlsClasses.setListData(classList);
        

        mainPanel.add("West",jsp);
        mainPanel.add("Center",cardsPanel);

        jlsClasses.addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                ConfigClass c = (ConfigClass)(((JList)e.getSource()).getSelectedValue());
                ((CardLayout)cardsPanel.getLayout()).show(cardsPanel, c.getId());
            }
        });
        
        return mainPanel;
    }
    
    
    /*Vygeneruje panel, pokud mozno inteligentne*/
    public static JScrollPane createClassConfigPanel(ConfigClass c) {

        JPanel pClassConfig = new JPanel();
        pClassConfig.setLayout(new BorderLayout(0,2));

        JLabel lClass = new JLabel(c.getName());
        JList jlsDummy = new JList();

        lClass.setBackground(jlsDummy.getSelectionBackground());
        lClass.setForeground(jlsDummy.getSelectionForeground());
        lClass.setOpaque(true);

        pClassConfig.add("North",lClass);
        JPanel p = new JPanel();
        pClassConfig.add("Center",p);

        GridBagLayout gbl = new GridBagLayout();
        p.setLayout(gbl);
        GridBagConstraints gbc1 = new GridBagConstraints();
        gbc1.gridy=0;
        gbc1.gridx=0;
        gbc1.anchor=GridBagConstraints.WEST;
        gbc1.weightx=0.0;
        gbc1.insets = new Insets(2,2,2,2);
       
        
        GridBagConstraints gbc2 = new GridBagConstraints();
        gbc2.gridy=0;
        gbc2.gridx=1;
        gbc2.anchor=GridBagConstraints.NORTHWEST;
        gbc2.fill=GridBagConstraints.HORIZONTAL;
        gbc2.weightx=1.0;
        gbc2.insets = new Insets(2,2,2,2);
   
        
        Vector v = c.getEntries();
        int l = v.size();
        AbstractConfigEntry cfe;
        
        for(int i=0;i<l;i++) {

            cfe=(AbstractConfigEntry)v.elementAt(i);
            JLabel lbl = new JLabel(cfe.getName()+":");
            p.add(lbl,gbc1);
            JComponent comp = cfe.createEntryEditor();
            
            if (comp instanceof JComboBox || comp instanceof JSpinner) gbc2.fill=GridBagConstraints.NONE; else gbc2.fill=GridBagConstraints.HORIZONTAL;
            entry2EditorMap.put(cfe, comp);
            p.add(comp,gbc2);
            gbc1.gridy+=1;
            gbc2.gridy+=1;
            
        }


        /*Filler*/
        GridBagConstraints gbc3 = new GridBagConstraints();
        gbc3.gridy=gbc1.gridy;
        gbc3.gridx=gbc1.gridx;
        gbc3.gridwidth=2;
        gbc3.anchor=GridBagConstraints.NORTHWEST;
        gbc3.fill=GridBagConstraints.BOTH;
        gbc3.weightx=1.0;
        gbc3.weighty=1.0;

        p.add(new JPanel(),gbc3);

        JScrollPane jsp = new JScrollPane(pClassConfig);
        return jsp;
    }
    
    /**Apply configuration changes made by GUI.
     * @return null when OK, HTML formatted error message when failed
     */
    public static String applyChanges() {
        
        Vector msgVect = new Vector();
        
        String emsg;

        ConfigClass c;
        AbstractConfigEntry ace;

        Iterator cit = classList.iterator();

        while(cit.hasNext()) {
            c = (ConfigClass)cit.next();

            Iterator eit = c.getEntries().iterator();
            while(eit.hasNext()) {
                ace = (AbstractConfigEntry)eit.next();

                JComponent comp = (JComponent)entry2EditorMap.get(ace);
                if (comp!=null) {
                    emsg = ace.verifyEntry(comp);
                    if (emsg!=null) msgVect.add(ace.getEntryDescription()+": "+emsg);
                }
                
            }
        }

        /*Any errors?*/
        if (msgVect.size()>0) return Utils.getHtmlFormatedMessageList(msgVect);

        /*Flush values from editors to entries*/
        cit = classList.iterator();

        while(cit.hasNext()) {
            c = (ConfigClass)cit.next();

            Iterator eit = c.getEntries().iterator();
            while(eit.hasNext()) {
                ace = (AbstractConfigEntry)eit.next();

                JComponent comp = (JComponent)entry2EditorMap.get(ace);
                if (comp!=null) ace.flushValueFromEditor(comp);

            }
        }

        /*Everything OK, returning null*/
        return null;
        
    }
    
    
}
