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

  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
  
****************************************************************************************************/

import java.io.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.event.*;

/**
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;
	private TdfButton submitButton, resetButton, selectAllButton, allAttributesButton, inputConstants, submitConstraints, resetConstraints;
	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
	
	/**
	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/21);    		// 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 ();
		constructDerivedAttributes ();
		constructConstraints ();
		constructSubmit ();
	}
	
	/**
	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",f,"IAU format object name",false);
		raDec = new TdfCheckBox ("Ra/Dec",f,"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>",f,"<html><p>b<sub>j</sub> magnitude</p></html>",true);
		ubj = new TdfCheckBox ("<html><p>u-b<sub>j</sub></p></html>",f,"<html><p>u-b<sub>j</sub> colour </p></html>",false);
		bjr = new TdfCheckBox ("<html><p>b<sub>j</sub>-r</p></html>",f,
				       "<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",f,"Redshift",true);
		q1 = new TdfCheckBox ("q1",f,"Identification quality X 10 + redshift quality",false);
		snr = new TdfCheckBox ("snr",f,"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 (7,2,10,10));
		attributesPane.setMaximumSize(new Dimension(xwidth-11,7*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 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 ()
	{
		absMag = new TdfCheckBox ("Absolute Magnitude",f,"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 (3,1,10,10));
		calculatedPane.setBorder (new TitledBorder (new EtchedBorder (),"Select Calculated Parameters "));
		calculatedPane.setMaximumSize(new Dimension(xwidth-10,3*panelHeightStep));
		calculatedPane.add (absMag);
		calculatedPane.add (inputConstants);
		inputConstants.addActionListener (this);

		add (calculatedPane);						
	}
	
	/**
	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 ()
	{
		constraintsPane = new JPanel ();
		attributeLabel 	= new TdfLabel ("Attribute");
		minLabel = new TdfLabel ("Min");
		maxLabel = new TdfLabel ("Max");
		raConstraint = new TdfLabel ("   Ra",f);
		decConstraint = new TdfLabel ("   Dec",f);
		zConstraint = new TdfLabel ("   z1",f);
		bjConstraint = new TdfLabel ("<html><p>&nbsp &nbsp &nbsp b<sub>j</sub></p></html>",f);
		
		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 (6,3,10,10));
		constraintsPane.setBorder (new TitledBorder (new EtchedBorder (),"Select Parameter Ranges"));
		constraintsPane.setMaximumSize(new Dimension(xwidth-10,6*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 submitting/resetting the query
	**/
	public void constructSubmit ()
	{
		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,1,20,20));
		submitPane.setBorder (new TitledBorder (new EtchedBorder ()," Submit / Reset "));
		submitPane.setMaximumSize (new Dimension(xwidth-10,(int) (1.5*panelHeightStep)));
		submitPane.add (submitButton);
		submitButton.addActionListener (this);
		submitPane.add (resetButton);
		resetButton.addActionListener (this);

		add (submitPane);				
	}

	/**
	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 ()
	{	
		String attrList = "";
		String comma = "";
		if (queryFlags [0] == true)
		{
			attrList = attrList + "name";
			comma = ",";
		}
		if (queryFlags [1] == true)
		{
			attrList = attrList + comma + "ra,decl";
			if (comma == "") comma = ",";
		}
		if (queryFlags [2] == true) 
		{
			attrList = attrList + comma + "ra_rad,dec_rad";  // note that declination is stored as decl in tdf data
			if (comma == "") comma = ",";
		}
		if (queryFlags [3] == true || queryFlags[9])		// if absolute magnitude is set we need aparent magnitude 
		{
			attrList = attrList + comma + "bj";
			if (comma == "") comma = ",";
		}
		if (queryFlags [4] == true) 		
		{
			attrList = attrList + comma + "ubj";
			if (comma == "") comma = ",";
		}
		if (queryFlags [5] == true) 
		{
			attrList = attrList + comma + "bjr";
			if (comma == "") comma = ",";
		}
		if (queryFlags [6] == true || queryFlags [9])		// if absolute magnitude is set then we need red shift		 
		{
			attrList = attrList + comma + "z1";
			if (comma == "") comma = ",";
		}
		if (queryFlags [7] == true) 
		{
			attrList = attrList + comma + "q1";
			if (comma == "") comma = ",";
		}
		if (queryFlags [8] == true) 
		{
			attrList = attrList + comma + "snr";
		}
		
		return attrList; 
		
	}

	/**
	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 ()
	{ 
		String constraints = "";
		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 = constraints + "ra >= " + "'" + ramin + "'";
			if (and.equals(""))
			and = " and ";
		}
		if (!ramax.equals (""))
		{
			constraints = constraints + and + "ra <= " + "'" + ramax + "'";
			if (and.equals(""))
			and = " and ";
		}			
		
		if (!decmin.equals (""))
		{
			constraints = constraints + and + "decl <= " + "'" + decmin + "'";
			if (and.equals(""))
			and = " and ";
		}
		if (!decmax.equals (""))
		{
			constraints = constraints + and + "decl >= " + "'" + decmax + "'";
			if (and.equals(""))
			and = " and ";
		}			

		if (!zmin.equals (""))
		{
			constraints = constraints + and + "z1 >= " + zmin;
			if (and.equals(""))
			and = " and ";
		}
		if (!zmax.equals (""))
		{
			constraints = constraints + and + "z1 <= " + zmax;
			if (and.equals(""))
			and = " and ";			
		}
		
		if (!bjmin.equals (""))
		{
			constraints = constraints + and + "bj >= " + bjmin;
			if (and.equals(""))
			and = " and ";
		}
		if (!bjmax.equals (""))
		{
			constraints = constraints + and + "bj <= " + bjmax;
			if (and.equals(""))
			and = " and ";			
		}
		
		
		System.out.println (constraints);
		return constraints;	
	}
			
		
	/**
	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));
	}

	/**
	This module sets the queryflags depending on whether on whether the atrribute has been selected 
	by the user
	**/
	public void setAttributeFlags ()
	{
		queryFlags [0] = name.checkSelection ();
		queryFlags [1] = raDec.checkSelection ();
		queryFlags [2] = raDecRadians.checkSelection ();
		queryFlags [3] = bj.checkSelection ();
		queryFlags [4] = ubj.checkSelection ();
		queryFlags [5] = bjr.checkSelection ();
		queryFlags [6] = z1.checkSelection ();
		queryFlags [7] = q1.checkSelection ();
		queryFlags [8] = snr.checkSelection ();
		queryFlags [9] = absMag.checkSelection ();
	}
	
	/**
	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 ();
		}
		if (source == resetButton)		// reset button resets the query
		{
			resetForm (false);
			absMag.setSelected (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);			
		}
	}
}
		
		

