/*
 * MiningMart Version 1.0
 * 
 * Copyright (C) 2006 Martin Scholz, Timm Euler, 
 *                    Daniel Hakenjos, Katharina Morik
 *
 * Contact: miningmart@ls8.cs.uni-dortmund.de
 *
 * A list of contributing developers (other than the copyright 
 * holders) can be found at
 * http://mmart.cs.uni-dortmund.de/downloads/download.html
 * 
 * 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 2
 * 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, see the file MM_HOME/LICENSE; if not, write
 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 * Floor, Boston, MA 02110-1301, USA.
 */
package edu.udo.cs.miningmart.gui.stepsettings;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.musoft.limo.application.Application;
import org.musoft.limo.application.Resource;
import org.musoft.limo.model.Model;
import org.musoft.limo.model.ModelConnectionElement;

import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.gui.application.MiningMartApplication;
import edu.udo.cs.miningmart.gui.model.MiningMartStep;
import edu.udo.cs.miningmart.gui.model.StepTransition;
import edu.udo.cs.miningmart.m4.M4Interface;
import edu.udo.cs.miningmart.m4.OpParam;
import edu.udo.cs.miningmart.m4.Operator;
import edu.udo.cs.miningmart.m4.Step;
import edu.udo.cs.miningmart.m4.utils.Print;

/**
 *A <code>JPanel</code> for the settings of a <code>Step</code>. 
 * It contains a <code>StepLoopPanel</code> if the <code>Step</code> is loopable.
 * The most important component is the <code>StepParameterTable</code> for the parameters of the <code>Srtep</code>.
 * Also buttons for saving, canceling and testing are availbale.
 * @author Daniel Hakenjos
 * @version $Id: StepSettingsPanel.java,v 1.4 2006/04/11 14:10:13 euler Exp $
 */
public class StepSettingsPanel extends JPanel implements ActionListener {

	public static final int NOT_TESTED = 0;
	public static final int VALID = 1;
	public static final int NOT_VALID = 2;

	private final static Color COLOR_NOT_TESTED = Resource.getColor("STEPSETTINGS_COLOR_NOT_TESTED");
	private final static Color COLOR_VALID 		= Resource.getColor("STEPSETTINGS_COLOR_VALID");	
  	private final static Color COLOR_NOT_VALID 	= Resource.getColor("STEPSETTINGS_COLOR_NOT_VALID");

	private MiningMartApplication app;
	private MiningMartStep mstep;
	private Step step;
	private Operator operator;

	private JLabel stepname;

	private JButton savebutton;
	private JButton closebutton;
	private JButton cancelbutton;
	private JButton validbutton;
	private JButton showgroupsbutton;
	
	private StepLoopPanel looppanel;
	
	private StepParameterTable paramtable;
	
	private LoopListener looplistener;

	private int validity;
	
	private boolean inputchanged;

	private boolean outputchanged;
	
	private boolean loopcountlower,loopcounthigher;
	
	private int minloopnr_changes_input,minloopnr_changes_output;

    /**
     *Constructs a new <code>StepSettingsPanel</code>.
     */
	public StepSettingsPanel(MiningMartApplication app, MiningMartStep step) {
		super();
		this.app = app;
		this.mstep = step;
		this.step = step.getStep();
		this.operator = this.step.getTheOperator();
		this.validity=NOT_TESTED;
		this.inputchanged=false;
		this.outputchanged=false;
		loopcountlower=false;
		loopcounthigher=false;
		minloopnr_changes_input=Integer.MAX_VALUE;
		minloopnr_changes_output=Integer.MAX_VALUE;

		initComponents();
	}

	private void initComponents() {

		JPanel toppanel = new JPanel();
		toppanel.setLayout(new BorderLayout());

		JScrollPane scrollpanel=new JScrollPane(toppanel);
		setLayout(new BorderLayout());
		add(scrollpanel, BorderLayout.CENTER);
		
		JPanel northpanel=new JPanel();
		northpanel.setLayout(new BorderLayout());
		toppanel.add(northpanel, BorderLayout.NORTH);

		JPanel oppanel=new JPanel();
		oppanel.setLayout(new GridLayout(2,1,5,5));
		oppanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		northpanel.add(oppanel,BorderLayout.NORTH);	

		JLabel oplabel1=new JLabel();
		oplabel1.setText(step.getTheOperator().getName());
		Font opfont=new Font("SansSerif",Font.PLAIN,15);
		oplabel1.setFont(opfont);
		oplabel1.setHorizontalAlignment(SwingConstants.CENTER);	
		oppanel.add(oplabel1);

		stepname=new JLabel();
		stepname.setText(step.getName());
		Font stepfont=new Font("SansSerif",Font.PLAIN,13);
		stepname.setFont(stepfont);
		stepname.setHorizontalAlignment(SwingConstants.CENTER);	
		stepname.setForeground(Color.BLUE);
		oppanel.add(stepname);

		try{
		if ((operator.isLoopable())&&(!step.usesLoopsForCoordination())){
			looppanel = new StepLoopPanel(app, step);
			northpanel.add(looppanel, BorderLayout.CENTER);
		}
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}

		JPanel southpanel = new JPanel();
		southpanel.setLayout(new BorderLayout());
		toppanel.add(southpanel, BorderLayout.SOUTH);

		JPanel buttonpanel = new JPanel();
		buttonpanel.setLayout(new GridLayout(2, 1));
		buttonpanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		southpanel.add(buttonpanel, BorderLayout.EAST);
		
		JPanel buttonpanel1=new JPanel();
		buttonpanel1.setLayout(new FlowLayout(FlowLayout.RIGHT));
//		buttonpanel1.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		buttonpanel.add(buttonpanel1);

		JPanel buttonpanel2=new JPanel();
		buttonpanel2.setLayout(new FlowLayout(FlowLayout.RIGHT));
//		buttonpanel2.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
		buttonpanel.add(buttonpanel2);

		savebutton = new JButton(Resource.getString("STEPSETTINGS_SAVE"));
		savebutton.setEnabled(false);
		buttonpanel2.add(savebutton);

		cancelbutton = new JButton(Resource.getString("STEPSETTINGS_CANCEL"));
		cancelbutton.setEnabled(false);
		buttonpanel2.add(cancelbutton);

		closebutton = new JButton(Resource.getString("STEPSETTINGS_CLOSE"));
		closebutton.addActionListener(this);
		buttonpanel2.add(closebutton);
		
		if (hasCoordinates()){
			showgroupsbutton = new JButton(Resource.getString("STEPSETTINGS_SHOW_GROUPS"));
			showgroupsbutton.addActionListener(this);
			buttonpanel1.add(showgroupsbutton);
		}

		validbutton = new JButton(Resource.getString("STEPSETTINGS_VALID"));
		buttonpanel1.add(validbutton);
		setValidity(NOT_TESTED);
		
		if (app.getViewMode()==Application.EDITOR){
			savebutton.addActionListener(this);
			cancelbutton.addActionListener(this);
			validbutton.addActionListener(this);
		}else{
			savebutton.setEnabled(false);
			cancelbutton.setEnabled(false);
			validbutton.setEnabled(false);
		}
		
		paramtable=new StepParameterTable(app,this.step, (app.getViewMode()==Application.EDITOR),new ParameterChangeListener());
		paramtable.createEditorAndRenderer();
		JScrollPane scrollpane=new JScrollPane(paramtable);
		toppanel.add(scrollpane,BorderLayout.CENTER);
		
		try{
			if ((operator.isLoopable())&&(!step.usesLoopsForCoordination())){
				looplistener=new LoopListener(this,paramtable);
				looppanel.getIteratorList().addIteratorListener(looplistener);
				looppanel.addNrOfLoopsListener(looplistener);
			}
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
	}
	
	/**
	 * Sets the name of the step in the <code>JLabel</code>.
	 */
	public void setStepName(String name){
		stepname.setText(name);		
	}
	
	/**
	 * Gets the <code>MiningMartStep</code>.
	 */
	public MiningMartStep getMiningMartStep(){
		return this.mstep;
	}
	
	private boolean hasCoordinates(){
		try{
			Iterator iter=step.getTheOperator().getOpParamsIterator();	
			OpParam opParam;
			while (iter.hasNext()){
				opParam=(OpParam) iter.next();
				if (opParam.isCoordinated())
					return true;
			}
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
		return false;	
		
	}

	/**
	 * Gets the validity of the operator.
	 */
	public int getValidity() {
		return validity;
	}

	/**
	 * Sets the validity of the operator.
	 * Be sure that you tested the validity before.
	 * @see #testValidity()
	 */
	public void setValidity(int v) {
		validity = v;
		switch (validity) {
			case NOT_TESTED :
				{
					validbutton.setBackground(COLOR_NOT_TESTED);
					break;
				}
			case VALID :
				{
					validbutton.setBackground(COLOR_VALID);
					break;
				}
			case NOT_VALID :
				{
					validbutton.setBackground(COLOR_NOT_VALID);
					break;
				}
			default :
				{
					validbutton.setBackground(Color.WHITE);
				}
		}
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return Resource.getString("STEPSETTINGS");
	}

	/**
	 * @see java.awt.event.ActionListener#actionPerformed(ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		String command = e.getActionCommand();

		if (command.equals(Resource.getString("STEPSETTINGS_SAVE"))) {
			//Save the entered parameters and create BaseAttrributes and/or Concepts
			saveParameter();
		} else if (command.equals(Resource.getString("STEPSETTINGS_CANCEL"))) {
			//Reload the parameters
			cancelEditing();
		} else if (command.equals(Resource.getString("STEPSETTINGS_CLOSE"))) {
			//Removes the tab
			app.removeStepSettingsPanel();
		} else if (command.equals(Resource.getString("STEPSETTINGS_SHOW_GROUPS"))) {
			//shows the grousp of the operator
			GroupsDialog dialog=new GroupsDialog(app,step,paramtable.getEditor());
		} else if (command.equals(Resource.getString("STEPSETTINGS_VALID"))) {
			//tests the validity
			testValidity(false);
		}
	}
	
	/**
	 * Enables the save and cancel button.
	 */
	public void enableCancelSave(boolean bool){
		cancelbutton.setEnabled(bool);
		savebutton.setEnabled(bool);
	}

	/**
	 * The values before editing will be displayed.
	 * They are also set to the step.
	 * This method only calls <code>cancelEditing()</code> in <code>StepParameterTable</code>.
	 * @see edu.udo.cs.miningmart.m4.Step#setParameter(OpParam,Collection,int)
	 * @see edu.udo.cs.miningmart.gui.stepsettings.StepParameterTabel#cancelEditing()
	 */	 
	public void cancelEditing(){
		if (looppanel!=null){
			looppanel.setNumberOfLoops(((StepParameterModel) paramtable.getModel()).getOldNrOfLoops());
		}
		try{
			paramtable.cancelEditing();
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			JOptionPane.showMessageDialog(app,
				error.getMessage(),
				Resource.getString("STEPSETTINGS_SETTING_INPUT"),
				JOptionPane.ERROR_MESSAGE);
				return;
		}

		app.saveModel();
		this.inputchanged=false;
		this.outputchanged=false;
		loopcountlower=false;
		loopcounthigher=false;
		minloopnr_changes_input=Integer.MAX_VALUE;
		minloopnr_changes_output=Integer.MAX_VALUE;
		savebutton.setEnabled(false);
		cancelbutton.setEnabled(false);

	}

	/**
	 * Tests the validity of the input parameter.
	 * @see edu.udo.cs.miningmart.m4.Step#setParameter(OpParam,Colection,int)
	 * @see edu.udo.cs.miningmart.m4.Step#checkInputParameterEntries()
     */
	public boolean testValidity(boolean save) {
		boolean isValid = false;

		try{		
			paramtable.setParameterCollectionsInStep(save);
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			JOptionPane.showMessageDialog(app,
				error.getMessage(),
				Resource.getString("STEPSETTINGS_SETTING_INPUT"),
				JOptionPane.ERROR_MESSAGE);
				setValidity(NOT_VALID);
				return false;
		}

		int loop = step.getLoopCount();
		if (loop == 0) {
			loop = 1;
		}
		if (((StepParameterModel) paramtable.getModel()).getNrOfLoops()<loop){
			loopcountlower=true;
		}
		if (((StepParameterModel) paramtable.getModel()).getNrOfLoops()>loop){
			loopcounthigher=true;
		}

		
		try{
			isValid=step.checkInputParameterEntries();
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			JOptionPane.showMessageDialog(app,
				error.getMessage(),
				Resource.getString("STEPSETTINGS_CHECK_INPUT"),
				JOptionPane.ERROR_MESSAGE);
				isValid=false;
		}

		if (isValid) {
			setValidity(VALID);
		} else {
			setValidity(NOT_VALID);
		}

		return isValid;
	}

		
		

	/**
	 * Saves the entered parameter.
	 * 1) Tests the validity of the input-parameter.
	 * 2) Creates the output
	 * 3) Saves the model.
	 * @see #testValidity()
	 * @see edu.udo.cs.miningmart.m4.Step#renameOutput()
	 * @see edu.udo.cs.miningmart.m4.Step#updateOutput()
	 * @see edu.udo.cs.miningmart.m4.Step#createOutput()
	 * @see edu.udo.cs.miningmart.gui.application.MiningMartApplication#saveModel()
	 */	
	public void saveParameter(){
		if (testValidity(true)){
			//makes Output
			
			//Die Tabelle wurde editiert und Loop-Zahl verringert
			//Wenn die Aenderungen hoehere Loop-Zahlen betreffen, so sind dies keine Aenderungen!
			//System.out.println("NrOfLoops: "+((StepParameterModel) paramtable.getModel()).getNrOfLoops());
			//System.out.println("minloopnr_changes_input: "+minloopnr_changes_input);
			//System.out.println("minloopnr_changes_output: "+minloopnr_changes_output);
			
			if (((StepParameterModel) paramtable.getModel()).getNrOfLoops()<minloopnr_changes_input)
				inputchanged=false;
				
			if (((StepParameterModel) paramtable.getModel()).getNrOfLoops()<minloopnr_changes_output)
				outputchanged=false;

				
			try{
				paramtable.makeOutput(inputchanged, outputchanged,loopcountlower, loopcounthigher);
			}catch(M4Exception error){
				M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
				JOptionPane.showMessageDialog(app,
					error.getMessage(),
					Resource.getString("STEPSETTINGS_MAKE_OUTPUT"),
					JOptionPane.ERROR_MESSAGE);
			}
			Model model=((Model) mstep.getParent());
			ModelConnectionElement conn;
			for(int i=0;i<model.getConnectionCount();i++){
				conn=model.getConnection(i);
				if (conn.getStart().getName().equals(step.getName())){
					((StepTransition) conn).refreshName();
				}
			}
			
			app.saveModel();
			this.inputchanged=false;
			this.outputchanged=false;
			loopcountlower=false;
			loopcounthigher=false;
			minloopnr_changes_input=Integer.MAX_VALUE;
			minloopnr_changes_output=Integer.MAX_VALUE;
			savebutton.setEnabled(false);
		}else{
			//der input ist nicht korrekt
			// trotzdem speichern?
			boolean save_input =
				JOptionPane.showConfirmDialog(
					app,
					Resource.getString("STEPSETTINGS_SAVE_MSG1")+"\n"+Resource.getString("STEPSETTINGS_SAVE_MSG2")+"\n"+Resource.getString("STEPSETTINGS_SAVE_MSG3"),
					Resource.getString("STEPSETTINGS_SAVE_TITLE"),
					JOptionPane.YES_NO_OPTION,
					JOptionPane.WARNING_MESSAGE)
					== JOptionPane.YES_OPTION;

			if (save_input){
				app.saveModel();
			}			
		}
		
	}
	
	private class ParameterChangeListener implements ChangeListener{
		public ParameterChangeListener(){
		}
		
		public void stateChanged(ChangeEvent event) {
//			System.out.println("Changes occurred.");
			setValidity(StepSettingsPanel.NOT_TESTED);
			savebutton.setEnabled(true);
			cancelbutton.setEnabled(true);
			ParameterEditor parameditor=(ParameterEditor) event.getSource();
			if (parameditor.getTheOpParam().isInput()){
				try {
					if (step.inputChangeCanAffectOutput(parameditor.getTheOpParam())) {
						inputchanged=true;
					}
				}
				catch (M4Exception error) {
					M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
					JOptionPane.showMessageDialog(app,
						error.getMessage(),
						Resource.getString("STEPSETTINGS"),
						JOptionPane.ERROR_MESSAGE);
				}
				minloopnr_changes_input=Math.min(minloopnr_changes_input,parameditor.getLoopNumber());
			}else{
				outputchanged=true;
				minloopnr_changes_output=Math.min(minloopnr_changes_output,parameditor.getLoopNumber());
			}
		}

	}

}
/*
$Log: StepSettingsPanel.java,v $
Revision 1.4  2006/04/11 14:10:13  euler
Updated license text.

Revision 1.3  2006/04/06 16:31:12  euler
Prepended license remark.

Revision 1.2  2006/03/02 16:49:59  euler
Many bugfixes

Revision 1.1  2006/01/03 09:54:15  hakenjos
Initial version!

*/
