package gov.nasa.jsc.plum.PlumUtil;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Iterator;
import java.util.TreeMap;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;


/**
 * @author randrews
 *
 * This is a panel that contains controls to modify (legally) one Row object.
 * It also implements an ActionListener for the button or whatever that saves the data.
 */
public class RowPanel extends JPanel implements ActionListener{

    private JButton save,comment;
    private ResultSet row;
    private TreeMap values;
    private Connection conn;
    private String tblname;
    private DatabaseWindow parent;
    private String indexfield; // Used for the comment button.
    
    public RowPanel(ResultSet row,Connection conn,String tblname){
        this.row=row;
        this.conn=conn;
        this.tblname=tblname;
        parent=null;
        if(tblname==null)tblname="";
        values=new TreeMap();
        try {
            drawPanel();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public RowPanel(ResultSet row,Connection conn,String tblname,String indexfield){
        this(row,conn,tblname);
        this.indexfield=indexfield;
        comment=new JButton("Comment");
        comment.addActionListener(this);
        GridBagConstraints c=new GridBagConstraints();
        c.gridx=0;c.gridy=2;
        c.fill=GridBagConstraints.BOTH;
        add(comment,c);
    }
    
    public RowPanel(ResultSet row,Connection conn){
        this(row,conn,"");
    }
    
    protected void drawPanel() throws Exception{
        TreeMap labels=new TreeMap();
        TreeMap combos=new TreeMap();
        try{
            ResultSet res=conn.createStatement().executeQuery("select * from labels where tblname=\""+tblname+"\"");
            while(res.next())
            {
                labels.put(res.getString("field"),res.getObject("label"));
                String linktable=res.getString("linktable"),linkfield=res.getString("linkfield");
                if(linktable!=null && linkfield!=null)
                    combos.put(res.getString("field"),"select distinct "+linkfield+" from "+linktable);
            }
        } catch(Exception e){
            e.printStackTrace();
        }

        ResultSetMetaData md=row.getMetaData();
        JPanel labelsPanel=new JPanel();
        JPanel controlsPanel=new JPanel();
        labelsPanel.setLayout(new GridLayout(md.getColumnCount(),1));
        controlsPanel.setLayout(new GridLayout(md.getColumnCount(),1));
        
        TreeMap widgets=new TreeMap();
        
        for(int n=0;n!=md.getColumnCount();n++)
        {
            int type=md.getColumnType(n+1);
            String field=md.getColumnName(n+1);
            String label=(String) labels.get(field);
            if(labels.containsKey(field) && label==null) // If the label is null (but exists), don't draw it
                continue;
  
            if(label==null)
                label=field;
            
            JComponent entry=null;
            Object value=row.getObject(field);

            if(value instanceof byte[]) // Takes care of blobs
                value=new String((byte[])value);

            if(combos.containsKey(field)) // Make things combo boxes
            {
                entry=new JComboBox();
                ResultSet values=conn.createStatement().executeQuery(combos.get(field).toString());
                while(values.next())
                    ((JComboBox)entry).addItem(values.getObject(1));
                ((JComboBox)entry).setSelectedItem(value);
            }
            else if(value instanceof Boolean || type==Types.BOOLEAN || type==Types.TINYINT) // Make checkboxes
            {
                entry=new JCheckBox();
                if(value!=null)
                    ((JCheckBox) entry).setSelected(((Boolean)value).booleanValue());
                else ((JCheckBox)entry).setSelected(false);
            }
            else if(value instanceof String || type==Types.VARCHAR || type==Types.BLOB) // Make normal text fields or formatted.
            {
                entry=new JTextField("");
                if(value!=null)
                    ((JTextField)entry).setText((String)value);
                ((JTextField)entry).setColumns(25);                
            }
            else
            {
                entry=new JFormattedTextField(new Double(0.0));
                if(value!=null)
                    ((JFormattedTextField)entry).setValue(value);
                ((JFormattedTextField)entry).setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);
                ((JFormattedTextField)entry).setColumns(25);
            }

            widgets.put(label,entry);
            values.put(field,entry);
        }
        
        JPanel fields=new JPanel();
        fields.setLayout(new GridBagLayout());
        GridBagConstraints c=new GridBagConstraints();
        c.gridx=0;c.gridy=0;c.anchor=GridBagConstraints.WEST;
        
        Iterator i=widgets.keySet().iterator();
        while(i.hasNext()){
            String label=(String) i.next();
            c.gridx=0;
            c.weightx=0;
            fields.add(new JLabel(label),c);
            c.gridx=1;
            c.weightx=1;
            fields.add((Component)widgets.get(label),c);
            c.gridy++;
        }
        
        save=new JButton("Save");
        save.addActionListener(this);

        setLayout(new GridBagLayout());
        
        JScrollPane scroll=new JScrollPane(fields);
        Dimension size=scroll.getPreferredSize();
        if(size.height>600)
        {
            size.height=600;
            scroll.setPreferredSize(size);
        }
        
        c.gridx=0;c.gridy=0;
        c.anchor=GridBagConstraints.CENTER;
        c.fill=GridBagConstraints.BOTH;
        c.weightx=1;c.weighty=1;
        add(scroll,c);
        c.gridy=1;
        c.weightx=0;c.weighty=0;
        add(save,c);
    }
    
    public void updateRow() throws Exception{
        Iterator i=values.keySet().iterator();
        while(i.hasNext())
        {
            String key=(String) i.next();
            Object obj=values.get(key);
            Object newval=null;
            if(obj instanceof JCheckBox)
            {
                JCheckBox cb=(JCheckBox) obj;
                newval=new Boolean(cb.isSelected());
            }
            else if(obj instanceof JFormattedTextField)
            {
                JFormattedTextField tf=(JFormattedTextField) obj;
                newval=tf.getValue();
            }
            else if(obj instanceof JTextField)
            {
                JTextField tf=(JTextField)obj;
                newval=tf.getText();
            }
            else if(obj instanceof JComboBox)
            {
                JComboBox cb=(JComboBox)obj;
                newval=cb.getSelectedItem();
            }
            row.updateObject(key,newval);
//            System.out.println(key+": "+newval);
        }
    }
    
    public void actionPerformed(ActionEvent e){
        if(e.getSource()==save)
            new AsynchSaver().start();
        else if(e.getSource()==comment)
        {
            try {
                CommentWindow window=new CommentWindow(conn,tblname,indexfield,row.getObject(indexfield).toString());
                window.setVisible(true);
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        }
    }

    /**
     * This returns the value currently in a control on a rowpanel
     * @param field name of field to grab
     * @return the value in that field. It's what in the field control, not necessarily what's in the database.
     */
    public Object get(String field){
        Object obj=values.get(field);
        if(obj instanceof JCheckBox)
        {
            JCheckBox cb=(JCheckBox) obj;
            return new Boolean(cb.isSelected());
        }
        else if(obj instanceof JFormattedTextField)
        {
            JFormattedTextField tf=(JFormattedTextField) obj;
            return tf.getValue();
        }
        else if(obj instanceof JTextField)
        {
            JTextField tf=(JTextField)obj;
            return tf.getText();
        }
        else if(obj instanceof JComboBox)
        {
            JComboBox cb=(JComboBox)obj;
            return cb.getSelectedItem();
        }
        return null;
    }
    
    /**
     * This function sets the value that is currently in a control on a rowpanel
     * @param field The field name to se tthe value of
     * @param value The new value to set
     */
    public void set(String field,Object value){
        Object obj=values.get(field);
        if(obj instanceof JCheckBox)
        {
            JCheckBox cb=(JCheckBox) obj;
            cb.setSelected(((Boolean)value).booleanValue());
        }
        else if(obj instanceof JFormattedTextField)
        {
            JFormattedTextField tf=(JFormattedTextField) obj;
            tf.setValue(value);
        }
        else if(obj instanceof JTextField)
        {
            JTextField tf=(JTextField)obj;
            tf.setText((String) value);
        }
        else if(obj instanceof JComboBox)
        {
            JComboBox cb=(JComboBox)obj;
            cb.setSelectedItem(value);
        }    
    }
    
    protected class AsynchSaver extends Thread{
        public void run(){
            try{
//                System.out.println("min before: "+row.getObject("min"));
                updateRow();
                row.updateRow();
//                System.out.println("min after: "+row.getObject("min"));
                if(parent!=null)
                    parent.updateWindows();
            } catch(Exception e1){
                e1.printStackTrace();
            }
        }
    }
    
    /**
     * @return Returns the row.
     */
    public ResultSet getRow() {
        return row;
    }
    /**
     * @param row The row to set.
     */
    public void setRow(ResultSet row) {
        this.row = row;
        // TODO do something here to update the table
    }

    public void setParent(DatabaseWindow parent){
        this.parent=parent;
    }
}
