/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2007 Approximatrix, LLC
 *  http://www.approximatrix.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 3 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, see <http://www.gnu.org/licenses/>.
 */

package com.approximatrix.draco.fit.ui;
import javax.swing.JOptionPane;

import com.approximatrix.draco.datamodel.IndepDepTableModel;
import com.approximatrix.draco.datamodel.StatTableModel;
import com.approximatrix.draco.fit.LSFit;
import com.approximatrix.draco.fit.RunLS;
import com.approximatrix.draco.fit.RunTSLS;
import com.approximatrix.draco.general.ui.InfoWindow;
import com.approximatrix.draco.io.XMLio.AnalysisLoadStore;


/**
 * @author armstrongj
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class TSLeastSquaresFit extends LeastSquaresFit {
	
	/** The string for requesting topical help */
	private static final String HELP_KEY = "tslsfit";
	
	InstrumentTableModel indepdeptable = null;
	
	RunTSLS analysis = null;
	
	public TSLeastSquaresFit() {
		super();
		
	}
	
	public TSLeastSquaresFit(StatTableModel information) {
		super(information);
		initialize();
	}
	
	public void initialize() {
		// Make necessary changes
		String[] indep_items = new String[super.getCurrentModel().getColumnCount()];
		for(int i=0;i<super.getCurrentModel().getColumnCount();i++) {
			indep_items[i] = super.getCurrentModel().getColumnName(i);
		}	
		//super.getWindowManager().closeWindow(this);
		setTitle("Two-Stage Least Squares");
		//super.getWindowManager().updateWindowNames();
		//super.getWindowManager().openWindow(this);
	
		indepdeptable = new InstrumentTableModel(indep_items);
		super.getTable().setModel(indepdeptable);
		
		// Intercept menus
		reset_menus();
	}
	
	private void do_fit() {
		
		String dep = indepdeptable.getDependentVariable();
		String[] indep_cols = indepdeptable.getIndependentVariables();
		
		if(dep == null) {
			JOptionPane.showMessageDialog(this,"Please select a dependent variable",  "Data Error", JOptionPane.ERROR_MESSAGE);
			return;
		}
		if(indep_cols == null) {
			JOptionPane.showMessageDialog(this,"Please select an independent variable",  "Data Error", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		// If we got this far, we must actually be running the analysis
		super.getTable().setEnabled(false); // To block any further changes
		getLs_options_menu().setEnabled(false);
		
		int var_type = RunLS.VAR_OLS;
		if(super.getVar_wht_radmenu().isSelected()) {
			var_type = RunLS.VAR_WHITE;
		}
		
		boolean include_constant = super.getLs_options_include_constant().isSelected();
		boolean ignore_condition = super.getLs_options_ignore_conditioning().isSelected();
		
		analysis = new RunTSLS(indep_cols,
							   dep,
						   	   indepdeptable.getInstruments(),
						   	   super.getCurrentModel(),
						   	   var_type,
						   	   include_constant,
						   	   ignore_condition);
		
		this.performAnalysis(analysis);
	}
	
	private class InstrumentTableModel extends IndepDepTableModel {
		
		private Boolean[] instruments = null;
		private String inst_name = "Instrument";
		
		public InstrumentTableModel(String[] strings) {
			super(strings);
			setupInstruments();	
		}
		
		public InstrumentTableModel(String[] strings, boolean[] indep, boolean[] dep) {
			super(strings, indep, dep);
			setupInstruments();	
		}
		
		private void setupInstruments() {
			instruments = new Boolean[super.getRowCount()];
			for(int i=0;i<instruments.length;i++) {
				instruments[i] = new Boolean(false);
			}
		}
		
		public String getColumnName(int col) {
			if(col < super.getColumnCount()) {
				return super.getColumnName(col);
			} else {
				return inst_name;
			}
		}
		
		public int getColumnCount() {
			return super.getColumnCount() + 1;
		}
		
		public Object getValueAt(int row, int col) {
			if(col<super.getColumnCount()) {
				return super.getValueAt(row,col);
			} else {
				return (Object)instruments[row];
			}
		}
		
		public void setValueAt(Object value, int row, int col) {
			if(col<super.getColumnCount()) {
				super.setValueAt(value,row,col);
			} else {
				instruments[row] = (Boolean)value;
			}
		}
		
		public String[] getInstruments() {
			int counter = 0;
			for(int i=0;i<super.getRowCount();i++) {
				if(instruments[i].booleanValue()) {
					counter++;
				}
			}
			
			if(counter == 0) return null;
			int j=0;
			
			String[] return_val = new String[counter];
			for(int i=0;i<super.getRowCount();i++) {
				if(instruments[i].booleanValue()) {
					return_val[j] = (String)super.getValueAt(i,0);
					j++;
				}
			}
			
			return return_val;
			
		}
		
		public Class getColumnClass(int col) {
			if(col<super.getColumnCount()) {
				return super.getColumnClass(col);
			} else {
				return Boolean.class;
			}
		}
		
		public boolean isCellEditable(int row, int col) {
			if(col<super.getColumnCount()) {
				return super.isCellEditable(row,col);
			} else {
				return true;
			}
		}
		
		public void setInstrumentChecked(String name) {
			int i = super.getRowNumber(name);
			if(i >= 0) {
				instruments[i] = new Boolean(true);
			}
		}
		
	}
	
	private void reset_menus() {
		// Perform regression
		super.getM_compute_regress().removeActionListener(super.getM_compute_regress().getActionListeners()[0]);
		super.getM_compute_regress().addActionListener(new java.awt.event.ActionListener() { 
			public void actionPerformed(java.awt.event.ActionEvent e) {    
				if(analysis == null) {
					do_fit();
				} else { // && !super.ac_use_checkmenu.isSelected()) {
					TSLeastSquaresFit.this.displayResults();
					//String results = analysis.getResults();
					//TSLeastSquaresFit.this.getMainWindow().openWindow(new InfoWindow(results,false));
				
				}
			}
		});
		
		// Hide all autocorrelation info
		super.getLs_options_ac_menu().setEnabled(false);
		
		// Hide extended statistics
		super.getLs_options_extout_menu().setEnabled(false);
	}
	
	/** Used for restoring an LSFit analysis to a dialog
	 * 
	 * @param values a valid, loaded AnalysisLoadStore dataset
	 */
	public void setAnalysis(AnalysisLoadStore data) {
		// Sets up the super's analysis also (needed for some functions)
		super.setAnalysis(data);
		
		analysis = new RunTSLS();
		analysis.setLoadedAnalysis(data, super.getCurrentModel());
		
		// Get the table model for this analysis
		InstrumentTableModel viewmodel = (InstrumentTableModel)super.getTable().getModel();
		
		// Fill in the check boxes
		String[] indep = analysis.getIndependentVariables();
		for(int i=0;i<indep.length;i++) viewmodel.setIndepenedentChecked(indep[i]);
		viewmodel.setDepenedentChecked(analysis.getDependentVariable());
		
		if(data.getName() != null)
			this.setTitle(data.getName());
		
		// Fill in the instrument check boxes
		String[] instruments = analysis.getInstruments();
		for(int i=0;i<instruments.length;i++) viewmodel.setInstrumentChecked(instruments[i]);
		viewmodel.fireTableDataChanged();

		// Make the table unchangeable
		super.getTable().setEnabled(false); // To block any further changes
		super.getLs_options_menu().setEnabled(false);
	}
	
	/** Retuns the analysis as an LSFit object (overloads LeastSquaresFit implementation)
	 * 
	 * @return a valid, complete LSFit object
	 */
	public LSFit getAnalysis() {
		return analysis;
	}
	
	/** Returns the help key for the Two-Stage Least Squares Fit window
	 * 
	 * @return the proper help key, defined by HELP_KEY
	 * @see #HELP_KEY
	 * @see com.approximatrix.draco.application.ChildFrame#getHelpKey()
	 */
	public String getHelpKey() {
		return HELP_KEY;
	}
	
}
