/*
 *  Draco Econometrics
 *  Copyright (C) 2006-2009 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.editor.wizard.ui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

import org.pietschy.wizard.InvalidStateException;
import org.pietschy.wizard.PanelWizardStep;

import com.approximatrix.draco.application.plugin.PluginSimpleOption;
import com.approximatrix.draco.application.plugin.SimpleOptionList;
import com.approximatrix.draco.editor.wizard.PluginWizardData;

public class PluginOptionsStep extends PanelWizardStep implements
		ActionListener {
	
	private SimpleOptionList options = null;
	private JPanel addPanel = null;
	private JTextField columnName = null;
	private JButton addButton = null;
	
	private JPanel selectionPanel = null;
	private JButton removeButton = null;
	private JTable oTable = null;
	private JComboBox oType = null;
	
	private PluginWizardData pwd =null;
	
	public PluginOptionsStep(PluginWizardData pwd) {
		super("Plugin Options","Enter the names and types of options that the user can select when executing the plugin.");
		
		this.pwd = pwd;
		
		options = new SimpleOptionList();

		this.setLayout(new BorderLayout());
		this.add(getAddPanel(),BorderLayout.SOUTH);
		this.add(getSelectionPanel(),BorderLayout.CENTER);
		
		this.setComplete(true);
	}

	private JPanel getAddPanel() {
		if(addPanel == null) {
			addPanel = new JPanel();
			addPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), 
					"Add an Option"));
			
			addPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
			
			JLabel label = new JLabel("Label:");
			
			addPanel.add(label);
			
			columnName = new JTextField();
			columnName.setEditable(true);
			columnName.setPreferredSize(new Dimension(175,label.getPreferredSize().height+columnName.getInsets().bottom+columnName.getInsets().top));
			addPanel.add(columnName);
			
			oType = new JComboBox(PluginSimpleOption.GetOptionStrings());
			addPanel.add(oType);
			
			addButton = new JButton("Add");
			addButton.addActionListener(this);
			addPanel.add(addButton);
			
		}
		return addPanel;
	}
	
	private JPanel getSelectionPanel() {
		if(selectionPanel == null) {
			selectionPanel = new JPanel();
			
			oTable = new JTable();
			oTable.setModel(new PluginOptionsTableModel());
			oTable.setRowSelectionAllowed(true);
			oTable.setColumnSelectionAllowed(false);
			oTable.setCellSelectionEnabled(true);
			
			JScrollPane sPane = new JScrollPane(oTable);
			selectionPanel.setLayout(new BorderLayout());
			selectionPanel.add(sPane);
			
			JPanel bPanel = new JPanel();
			bPanel.setLayout(new FlowLayout());
			removeButton = new JButton("Remove");
			removeButton.addActionListener(this);
			bPanel.add(removeButton);
			selectionPanel.add(bPanel,BorderLayout.EAST);
			selectionPanel.setPreferredSize(new Dimension(250,150));
		}
		return selectionPanel;
	}

	public void actionPerformed(ActionEvent e) {
		if(e.getSource() == addButton) {
			if(columnName.getText() != null && columnName.getText().length() > 0) {
				int type = PluginSimpleOption.OptionString2Id(oType.getSelectedItem().toString());
				Object defaultvalue = PluginSimpleOption.GetDefaultOptionValue(type);
				options.add(new PluginSimpleOption(columnName.getText(),type,defaultvalue));
				columnName.setText("");
			}
		} else if(e.getSource() == removeButton) {
			int row_index = oTable.getSelectedRow();
			if(row_index >= 0 && row_index < options.size()) {
				options.remove(row_index);
			}
		}
		
		((PluginOptionsTableModel)oTable.getModel()).fireTableDataChanged();
	}
	
	private class PluginOptionsTableModel extends AbstractTableModel {

		public PluginOptionsTableModel() {
		}
		
		public int getColumnCount() {
			return 3;
		}

		public int getRowCount() {
			return options.size();
		}
		
		@Override
		public String getColumnName(int column) {
			switch(column) {
			case 0:
				return "Option Name";
			case 1:
				return "Type";
			case 2:
				return "Default Value";
			default:
				throw new IllegalArgumentException("Column exceeds model bounds");	
			}
		}

		@Override
		public boolean isCellEditable(int rowIndex, int columnIndex) {
			return !(columnIndex == 1);	
		}

		public Class<?> getColumnClass(int columnIndex) {
			return String.class;
		}
		
		@Override
		public void setValueAt(Object value, int row, int col) {
			PluginSimpleOption o = options.get(row);
			
			if(value == null)
				return;
			
			try {
				switch(col) {
				case 0:
					String label = value.toString();
					if(label.length() > 0)
						o.setString(label);
					break;
				case 1:
					throw new IllegalArgumentException("Cannot set type...");	
				case 2:
					label = value.toString();
					if(label.length() > 0)
						o.setDefaultValue(label);
					break;
				default:
					throw new IllegalArgumentException("Column exceeds model bounds");	
				}
			} catch(ClassCastException cce) {
				throw new IllegalArgumentException("Bad type for row.");
			}
		}

		public Object getValueAt(int row, int col) {
			
			PluginSimpleOption o = options.get(row);
	
			Object ret = null;
			switch(col) {
			case 0:
				ret = o.getLabel();
				break;
			case 1:
				ret = PluginSimpleOption.OptionId2String(o.getType());
				break;
			case 2:
				ret = o.getString();
				break;
			default:
				throw new IllegalArgumentException("Address exceeds model bounds");
			}
			return ret;
		}
		
	}

	@Override
	public void applyState() throws InvalidStateException {
		this.pwd.setOptions(this.options);
	}

}
