/***************************************************************************************************

  the array queryFlags store which attribute the user wants 
  flag [0] = name
  flag [1] = ra / dec
  flag [2] = ra / dec in radians
  flag [3] = bj 
  flag [4] = ubj
  flag [5] = bjr
  flag [6] = z1
  flag [7] = q1
  flag [8] = snr
  flag[9] = absolute magnitude
  
****************************************************************************************************/
package voi.ui;
import java.io.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;
import voi.db.*;
import voi.routines.*;
import java.sql.*;

/**
The TdfInterface class is used to create the Query form.
There are 4 main parts to it

1) Select Observed / Required attributes
2) Select Calculated / Derived attributes
3) Enter parameter ranges 
4) submit / reset the query 
**/

public class TdfInterface extends JPanel implements ActionListener
{
// define all the buttons here
	private JPanel attributesPane, calculatedPane, constraintsPane, submitPane, switchPane;
	private TdfButton submitButton, resetButton, selectAllButton, allAttributesButton, inputConstants, 
		submitConstraints, resetConstraints, switchButton;
	private TdfCheckBox name, raDec, raDecRadians, bj, ubj, bjr, z1, q1, snr, absMag;
	private int xwidth, ywidth, panelHeightStep;
	private boolean queryFlags[] = new boolean [13], selectAllFlag = false;

	private TdfLabel attributeLabel, minLabel, maxLabel, andLabel, orLabel, raConstraint, decConstraint, zConstraint, bjConstraint;
	private JTextField raMin, raMax, decMin, decMax, zMin, zMax, bjMin, bjMax;

	private MysqlConnect mysqlConnect;
	private InputParameters cosmo;
	
	private GuiController theApp;

	private Font f = new Font("Garamond", Font.PLAIN, 12);
	private Border edge = BorderFactory.createRaisedBevelBorder ();	// Button Border
	
	final int PANEL_HEIGHT_STEP = 21;				// Determines the height alloted to each pane
									// the numnber depends on the number of components
	final Font TDF_FONT = new Font("Garamond", Font.PLAIN, 12);
	private Index index;						// indices for attributes
	
	/**
	The constructors initialises all the components for the query interface like
	buttons, labels, paneles etc
	**/
	public TdfInterface (GuiController theApp, int xwidth, int ywidth)
	{			
		this.theApp = theApp;
		this.xwidth = xwidth; 					// set the maximum width for the objects
		this.ywidth = ywidth;
	
		setPanelProperties ();
		constructQueryInterface ();		
	}
	
	/**
	This funcion sets some of the properties that are used by the main TdfInterface pane
	**/
	public void setPanelProperties ()
	{
		panelHeightStep = (int) (ywidth/PANEL_HEIGHT_STEP);    		// here 21 is the number of components !
		setLayout (new BoxLayout (this, BoxLayout.Y_AXIS));     // set the layout to boxlayout  		
	}			

	/**
	This module constructs the query framework by invoking the  modules for constructing the
	individual panes
	**/
	public void constructQueryInterface ()
	{
		constructObservedAttributes ();
		constructConstraints ();
		constructDerivedAttributes ();
		constructSubmit ();
		constructSwitchPane ();
	}
	

	/**
	This module constructs the observed/Required attributes panel
	It contains the following
	1) checkboxes to select the parameter
	2) buttons to select all and select from a range of parameters
	**/
	public void constructObservedAttributes ()
	{
		// construct the checkboxes
		name = new TdfCheckBox ("Name",TDF_FONT,"IAU format object name",false);
		raDec = new TdfCheckBox ("Ra/Dec (J2000)",TDF_FONT,"Right ascension J2000 [hh mm ss.ss] , Declinations J2000 [+/-dd mm ss.s]",true);
		raDecRadians = new TdfCheckBox ("Ra/Dec (Radians)",
					        new Font ("Garamond", Font.PLAIN, 11), 
						"Ra J2000, Dec J2000 in radians",
						false);
		bj = new TdfCheckBox ("<html><p>b<sub>j</sub></p></html>",TDF_FONT,"<html><p>b<sub>j</sub> magnitude</p></html>",true);
		ubj = new TdfCheckBox ("<html><p>u-b<sub>j</sub></p></html>",TDF_FONT,"<html><p>u-b<sub>j</sub> colour </p></html>",false);
		bjr = new TdfCheckBox ("<html><p>b<sub>j</sub>-r</p></html>",TDF_FONT,
				       "<html><p>b<sub>j</sub>-r colour [including r upper limits as: (b<sub>j</sub> - r<sub>lim</sub> - 10.0</p></html>",
				       false);
		z1 = new TdfCheckBox ("z1",TDF_FONT,"Redshift",true);
		q1 = new TdfCheckBox ("q1",TDF_FONT,"Identification quality X 10 + redshift quality",false);
		snr = new TdfCheckBox ("snr",TDF_FONT,"signal-to-noise ratio in the 4000-5000A band",false);
		TdfLabel dummy = new TdfLabel (" ");		
		/** this label is used as a filler since we are using gridlayout and we need 2 columns per row
		    but the last row just has one **/

		selectAllButton = new TdfButton ("Select All", "Select all the parameters", edge);
		allAttributesButton = new TdfButton ("Complete List","select from entire list", edge);

		// set the properties for the panel 		
		attributesPane = new JPanel ();
		attributesPane.setBorder (new TitledBorder (new EtchedBorder(), "Select Required/Observed Attributes"));
		attributesPane.setLayout (new GridLayout (6,2,10,10));
	//	attributesPane.setMaximumSize(new Dimension(xwidth-11,6*panelHeightStep));

		// add the components to the panel
		attributesPane.add (name);
		attributesPane.add (raDec);
		attributesPane.add (raDecRadians);
		attributesPane.add (bj);
		attributesPane.add (ubj);
		attributesPane.add (bjr);
		attributesPane.add (z1);
		attributesPane.add (q1);
		attributesPane.add (snr);
		attributesPane.add (dummy);
		attributesPane.add (selectAllButton);
		selectAllButton.addActionListener (this);
		attributesPane.add (allAttributesButton);

		add (attributesPane);		
	}


	/**
	This module constructs the constraints/ranges pane.
	It consists of the following :
	Minimum and maximum ranges for
		1) Ra
		2) Dec
		3) Redshift (z)
		4) apparent magnitude (bj)
	**/
	public void constructConstraints ()
	{
		add (new FillerPane (1,xwidth,panelHeightStep));
		
		constraintsPane = new JPanel ();
		attributeLabel 	= new TdfLabel ("Attribute");
		minLabel = new TdfLabel ("Min");
		maxLabel = new TdfLabel ("Max");
		raConstraint = new TdfLabel ("   Ra",TDF_FONT);
		decConstraint = new TdfLabel ("   Dec",TDF_FONT);
		zConstraint = new TdfLabel ("   z1",TDF_FONT);
		bjConstraint = new TdfLabel ("<html><p>&nbsp &nbsp &nbsp b<sub>j</sub></p></html>",TDF_FONT);
		
		raMin = new JTextField ("0 0 0.00");
		raMax = new JTextField ("24 0 0.00");
		decMin = new JTextField ("-90 0 0.00");
		decMax = new JTextField ("+90 0 0.00");
		zMin = new JTextField ("0");
		zMax = new JTextField ("5");
		bjMin = new JTextField ("0");
		bjMax = new JTextField ("25");
		
		constraintsPane.setLayout (new GridLayout (5,3,10,10));
		constraintsPane.setBorder (new TitledBorder (new EtchedBorder (),"Select Parameter Ranges"));
	//	constraintsPane.setMaximumSize(new Dimension(xwidth-10,5*panelHeightStep));
		
		constraintsPane.add (attributeLabel);
		constraintsPane.add (minLabel);
		constraintsPane.add (maxLabel);
		constraintsPane.add (raConstraint);
		constraintsPane.add (raMin);
		constraintsPane.add (raMax);
		constraintsPane.add (decConstraint);
		constraintsPane.add (decMin);
		constraintsPane.add (decMax);
		constraintsPane.add (zConstraint);
		constraintsPane.add (zMin);
		constraintsPane.add (zMax);
		constraintsPane.add (bjConstraint);
		constraintsPane.add (bjMin);
		constraintsPane.add (bjMax);
		
		add (constraintsPane);		
	}
	
	
	/**
	This module constructs the pane for Derived attributes.
	It consists of the following 
	1) Selection of absolute magnitude parameter
	2) Selection of cosmological model by selecting hubble constant, iop parameter & ..... see later
	**/
	public void constructDerivedAttributes ()
	{
		add (new FillerPane (1,xwidth,panelHeightStep));
		
		absMag = new TdfCheckBox ("Absolute Magnitude",TDF_FONT,"Absolute Magnitude for a given redshit, apparent magnitude and cosmological model",true);
		inputConstants = new TdfButton (" Input Cosmological Constants ",
						"Choose the cosmological model by setting parameters appropriately",
						edge);
		
		calculatedPane = new JPanel ();				
		calculatedPane.setLayout (new GridLayout (2,1,10,10));
		calculatedPane.setBorder (new TitledBorder (new EtchedBorder (),"Select Calculated Parameters "));
	//	calculatedPane.setMaximumSize(new Dimension(xwidth-10,2*panelHeightStep));
		calculatedPane.add (absMag);
		calculatedPane.add (inputConstants);
		inputConstants.addActionListener (this);

		add (calculatedPane);						
	}
	
	
	/**
	This module constructs the pane for submitting/resetting the query
	**/
	public void constructSubmit ()
	{
		add (new FillerPane (1,xwidth,panelHeightStep));
		
		submitButton = new TdfButton ("Submit", "Submit the selected query ", edge);
		resetButton = new TdfButton ("Reset", "Reset the query ", edge);

		submitPane = new JPanel ();
		submitPane.setLayout (new GridLayout (1,2,10,10));
	//	submitPane.setBorder (new TitledBorder (new EtchedBorder (),""));
	//	submitPane.setMaximumSize (new Dimension(xwidth-10,(int) (1.5*panelHeightStep)));
		submitPane.add (submitButton);
		submitButton.addActionListener (this);
		submitPane.add (resetButton);
		resetButton.addActionListener (this);
	
		add (submitPane);				
	}

	public void constructSwitchPane ()
	{
		add (new FillerPane (1,xwidth,panelHeightStep));
		
		switchButton = new TdfButton ("switch to SQL Query mode ","Switch from the From Mode to the SQL Query Mode ", edge);
		switchButton.addActionListener (this);
		switchPane = new JPanel ();
		switchPane.setLayout (new GridLayout (2,1,10,10));
	//	switchPane.setMaximumSize(new Dimension(xwidth-11,3*panelHeightStep));
		
		switchPane.add (switchButton);
		add (switchPane);
	}

	/**
	This module is responsible for resetting the form to its original state
	**/
	public void resetForm (boolean flag)
	{		
		name.setSelected (flag);
		raDec.setSelected (flag);
		raDecRadians.setSelected (flag);
		bj.setSelected (flag);
		ubj.setSelected (flag);
		bjr.setSelected (flag);
		z1.setSelected (flag);
		q1.setSelected (flag);
		snr.setSelected (flag);		
 	}

	
	/**
	This module is responsible for constructing the list of attributes that have been selected by the user
	ie to create the SELECT clause
	The string returned is the parameter list
	**/
	public String selectAttributes ()
	{	
		
		StringBuffer attrList = new StringBuffer ("");
		String comma = "";
		if (queryFlags [index.NAME] == true)
		{
			attrList.append ("name");
			comma = ",";
		}
		if (queryFlags [index.RA_DEC] == true)
		{
			attrList.append (comma).append ("ra,decl");
			if (comma == "") comma = ",";
		}
		if (queryFlags [index.RA_DEC_RADIANS] == true) 
		{
			attrList.append (comma).append ("ra_rad,dec_rad");
			if (comma == "") comma = ",";
		}
		if (queryFlags [index.BJ] == true || queryFlags[index.ABS_MAG])		// if absolute magnitude is set we need aparent magnitude 
		{
			attrList.append (comma).append ("bj");
			if (comma == "") comma = ",";
		}
		if (queryFlags [index.UBJ] == true) 		
		{
			attrList.append (comma).append ("ubj");
			if (comma == "") comma = ",";
		}
		if (queryFlags [index.BJR] == true) 
		{
			attrList.append (comma).append ("bjr");
			if (comma == "") comma = ",";
		}
		if (queryFlags [index.Z1] == true || queryFlags [index.ABS_MAG])		// if absolute magnitude is set then we need red shift		 
		{
			attrList.append (comma).append ("z1");
			if (comma == "") comma = ",";
		}
		if (queryFlags [index.Q1] == true) 
		{
			attrList.append (comma).append ("q1");
			if (comma == "") comma = ",";
		}
		if (queryFlags [index.SNR] == true) 
		{
			attrList.append (comma).append ("snr");
		}
		
		return attrList.toString ();		
		
	}

	/**
	This module is responsible for creating the constraints clause in the query
	i.e. the where part
	The string returned is the condition part of the (WHERE ***)
	**/
	public String selectConstraints ()
	{ 		
		StringBuffer constraints = new StringBuffer ("");
		String and = "";
		
		String ramin = raMin.getText ();
		String ramax = raMax.getText ();
		String decmin = decMin.getText ();
		String decmax = decMax.getText ();
		String zmin = zMin.getText ();
		String zmax = zMax.getText ();
		String bjmin = bjMin.getText ();
		String bjmax = bjMax.getText ();

		if (!ramin.equals (""))
		{
			constraints.append ("ra >= ").append ("'").append (ramin).append ("'");
			if (and.equals(""))
			and = " and ";
		}
		if (!ramax.equals (""))
		{
			constraints.append (and).append ("ra <= ").append ("'").append (ramax).append ("'");
			if (and.equals(""))
			and = " and ";
		}			
		
		if (!decmin.equals (""))
		{
			constraints.append (and).append ("decl <= ").append ("'").append (decmin).append ("'");
			if (and.equals(""))
			and = " and ";
		}
		if (!decmax.equals (""))
		{
			constraints.append (and).append ("decl >= ").append ("'").append (decmax).append ("'");
			if (and.equals(""))
			and = " and ";
		}			

		if (!zmin.equals (""))
		{
			constraints.append (and).append ("z1 >= ").append (zmin);
			if (and.equals(""))
			and = " and ";
		}
		if (!zmax.equals (""))
		{
			constraints.append (and).append ("z1 <= ").append (zmax);
			if (and.equals(""))
			and = " and ";			
		}
		
		if (!bjmin.equals (""))
		{
			constraints.append (and).append ("bj >= ").append (bjmin);
			if (and.equals(""))
			and = " and ";
		}
		if (!bjmax.equals (""))
		{
			constraints.append (and).append ("bj <= ").append (bjmax);	
			if (and.equals(""))
			and = " and ";			
		}
		
		System.out.println (constraints);
		return constraints.toString ();

	}
			
		
	/**
	This module is resposible for constructing the query and connecting to the MysqlConnect module
	The mysqlConnect accepts three paramaters 
	1) attrlist as a string
	2) constraints as a string
	3) queryFlags which tells the module which parameters are requested for proper o/p display
	**/
	public void constructQuery ()
	{
		String attrList = selectAttributes ();		
		String constraints = selectConstraints ();
                mysqlConnect = new MysqlConnect ();
                theApp.showResults (mysqlConnect.submitQuery (attrList, constraints, queryFlags));
		if (mysqlConnect.validQuery ())
		{
			theApp.getToolBar ().enableAll (true);
		}
	}

	/**
	This module sets the queryflags depending on whether on whether the atrribute has been selected 
	by the user
	**/
	public void setAttributeFlags ()
	{
		queryFlags [index.NAME] = name.checkSelection ();
		queryFlags [index.RA_DEC] = raDec.checkSelection ();
		queryFlags [index.RA_DEC_RADIANS] = raDecRadians.checkSelection ();
		queryFlags [index.BJ] = bj.checkSelection ();
		queryFlags [index.UBJ] = ubj.checkSelection ();
		queryFlags [index.BJR] = bjr.checkSelection ();
		queryFlags [index.Z1] = z1.checkSelection ();
		queryFlags [index.Q1] = q1.checkSelection ();
		queryFlags [index.SNR] = snr.checkSelection ();
		queryFlags [index.ABS_MAG] = absMag.checkSelection ();
	}
	
	public ResultSet getResults ()
	{
		return mysqlConnect.getResults ();
	}
	
	public boolean[] getQueryFlags ()
	{
		return queryFlags;	
	}
	
	/**
	This module performs the actions required when the various buttons are pressed
	**/	
	public void actionPerformed (ActionEvent ae)
	{	
		Object source = ae.getSource ();
		if (source == submitButton)		// this removes the previous results and creats a new one
		{
			theApp.removeComponents ();
			setAttributeFlags ();
			constructQuery ();
			theApp.getToolBar ().enableAll (true);
		}
		if (source == resetButton)		// reset button resets the query
		{
			resetForm (false);
			absMag.setSelected (false);
			theApp.removeComponents ();
			theApp.getToolBar ().enableAll (false);
		}
		if (source == selectAllButton)		// toggles if all are selected else it selects all
		{
			if (!selectAllFlag)
			resetForm (true);
			else resetForm (false);
			selectAllFlag = !selectAllFlag;
		}
		if (source == inputConstants)		// sets the cosmological model 
		{
			cosmo = new InputParameters ();
			cosmo.create ();
			double h0 = cosmo.geth0 (); 
			double q0 = cosmo.getq0 ();
			double aop = cosmo.getaop ();
			Magnitude.setParameters (h0, q0, aop);			
		}
		if (source == switchButton)
		{
			theApp.switchToQueryMode ();	
		}
	}
}
		
		

