/*
 * 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.concepteditor;

import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Vector;

import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

import org.musoft.limo.application.Application;
import org.musoft.limo.application.Resource;
import org.musoft.limo.drawing.ModelDrawingView;

import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.gui.application.MiningMartApplication;
import edu.udo.cs.miningmart.gui.model.MiningMartConcept;
import edu.udo.cs.miningmart.gui.util.M4ObjectComparator;
import edu.udo.cs.miningmart.m4.BaseAttribute;
import edu.udo.cs.miningmart.m4.Concept;
import edu.udo.cs.miningmart.m4.ConceptualDatatypes;
import edu.udo.cs.miningmart.m4.Feature;
import edu.udo.cs.miningmart.m4.M4Interface;
import edu.udo.cs.miningmart.m4.MultiColumnFeature;
import edu.udo.cs.miningmart.m4.utils.Print;

/**
 * This is a<code>JTable</code> to display all <code>Feature</code>s of a <code>Concept</code> in this table.
 * 
 * @author Daniel Hakenjos
 * @version $Id: FeatureTable.java,v 1.3 2006/04/11 14:10:17 euler Exp $
 */
public class FeatureTable extends JTable {
	
	public static final int BASEATTRIBUTE_MODE = 0;

	public static final int MCFEATURE_MODE		= 1;
	
	public static final int DEFAULT_MODE			= 0;
	
	private MiningMartApplication app;
	
	private MiningMartConcept mmartconcept;
	
	private Concept concept;
	
	private int feature_mode;
	
	private Vector features;
	
	private Vector mcfeateditor;
	
	private FeatureTableModel tablemodel;
	
	private Feature selectedFeature;
	
	private JTextArea descriptionArea;
	
	private int viewMode;
	
	private boolean listenDescription;
	
	public FeatureTable(MiningMartApplication app, MiningMartConcept mmartconcept, int feature_mode){
		this.app=app;
		this.viewMode=app.getViewMode();
		this.mmartconcept=mmartconcept;
		this.concept=mmartconcept.getConcept();
		if ((feature_mode<0)||(feature_mode>1)){
			feature_mode=DEFAULT_MODE;
		}
		this.feature_mode=feature_mode;
		this.selectedFeature=null;
		this.listenDescription=false;
		
		descriptionArea=new JTextArea();
		descriptionArea.setEditable(false);
		descriptionArea.getDocument().addDocumentListener(
			new DocumentListener(){

				public void insertUpdate(DocumentEvent e) {
					setDocu();
				}

				public void removeUpdate(DocumentEvent e) {
					setDocu();
				}
				
				private void setDocu(){	
					if (!listenDescription)
						return;
								
					int selectedRow = getSelectedRow();

					if (selectedRow==-1)
						return;
					
					try {
						((Feature) features.get(selectedRow)).setDocumentation(descriptionArea.getText());
					} catch (M4Exception error) {
						M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
					}					
					
				}

				public void changedUpdate(DocumentEvent e) {
				}
				
			}
		);
		
		
		features=new Vector();
		try{
			Collection fcoll=concept.getFeatures();
			LinkedList flist=new LinkedList();
			flist.addAll(fcoll);
			Collections.sort(flist,new M4ObjectComparator());			
			Iterator iter=flist.iterator();
			while (iter.hasNext()){
				Feature feat=(Feature) iter.next();
				if ((feat instanceof BaseAttribute)&&(feature_mode==BASEATTRIBUTE_MODE)){
					features.add(feat);
					continue;
				}
				if ((feat instanceof MultiColumnFeature)&&(feature_mode==MCFEATURE_MODE)){
					features.add(feat);
					continue;
				}
			
			}
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
		
		setSelectionMode(javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);

		ListSelectionModel rowSM = getSelectionModel();
		rowSM.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				//Ignore extra messages.
				if (e.getValueIsAdjusting()) return;

				ListSelectionModel lsm =
					(ListSelectionModel)e.getSource();
				if (lsm.isSelectionEmpty()) {
					//no rows are selected
					listenDescription=false;
					descriptionArea.setText("");
					descriptionArea.setEditable(false);
				} else {
					if (viewMode==Application.EDITOR){
						descriptionArea.setEditable(true);
					}else{
						descriptionArea.setEditable(false);
					}
					int selectedRow = lsm.getMinSelectionIndex();
					Feature feat=(Feature) features.get(selectedRow);
					String doc=new String("");
					try{
						doc=feat.getDocumentation();
					}catch(M4Exception error){
						M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
						doc="";
					}
					listenDescription=false;
					descriptionArea.setText(doc);					
					listenDescription=true;
				}
			}
		});

		getTableHeader().setReorderingAllowed(false);
		setRowHeight(getRowHeight() + 4);

		this.tablemodel = new FeatureTableModel();
		this.setModel(tablemodel);
		
		createEditorAndRenderer();
	}

	/**
	 * Gets the JTextArea for the description of a BaseAttribute.
	 */	
	public JTextArea getDescriptionArea(){
		return descriptionArea;
	}
	
	public void newFeature(){
		int row=this.getSelectedRow();
		
		try{
			Feature feat=null;
			if (feature_mode==BASEATTRIBUTE_MODE){
				feat=concept.createBaseAttribute(concept.getValidName(Resource.getString("BASEATTRIBUTE"),BaseAttribute.class),BaseAttribute.TYPE_DB,ConceptualDatatypes.CDTYPES[0]);
				((BaseAttribute) feat).setType(BaseAttribute.TYPE_DB);
				((BaseAttribute) feat).setConceptualDataTypeName(ConceptualDatatypes.CDTYPES[0]);
			}
			if (feature_mode==MCFEATURE_MODE){
				feat=concept.createMultiColumnFeature(concept.getValidName(Resource.getString("MCFEATURE"),MultiColumnFeature.class));
			}
				
		

			if (feature_mode==MCFEATURE_MODE){
				MCFeatureEditor editor=new MCFeatureEditor(app,(MultiColumnFeature) feat);
				editor.actionPerformed(null);
				if (((MultiColumnFeature) feat).getBaseAttributes().size()<2){
					concept.removeFeature(feat);
					feat.deleteSoon();
					return;
				}
				mcfeateditor.add(editor);
			}

			features.add(feat);

			app.getModel().setDirty(true);
			tablemodel.fireTableDataChanged();
			((ModelDrawingView) app.getDrawingView()).repaint();
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
		
	}
	
	public void newBaseAttributes(){
		NewBaseAttributesDialog dialog =new NewBaseAttributesDialog(app);
		
		if (dialog.getExitAction()==NewBaseAttributesDialog.OK){
			
			try{
				String name=dialog.getName();
				int nr=dialog.getNumberOfBaseAttributes();
				String atttype=dialog.getAttributeType();
				String datatype=dialog.getConceptualDatatype();
		
				BaseAttribute newBA;
				String thename;
				for(int b=0;b<nr;b++){
				
					thename=concept.getValidName(name,BaseAttribute.class);
				
					newBA=concept.createBaseAttribute(thename,atttype,datatype);
					newBA.setType(atttype);
					newBA.setConceptualDataTypeName(datatype);
				
					features.add(newBA);

				}
				
			}catch(M4Exception error){
				M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			}
			
			app.getModel().setDirty(true);
			tablemodel.fireTableDataChanged();
			((ModelDrawingView) app.getDrawingView()).repaint();
		}
	}
	
	public void deleteSelectedFeature(){
		int[] row=this.getSelectedRows();
		
		
		for(int r=row.length-1;r>=0;r--){

			if (row[r]==-1){
				continue;
			}
			
			Feature feat=(Feature) features.get(row[r]);
		
			try{
				concept.removeFeature(feat);
				feat.deleteSoon();
			}catch(M4Exception error){
				M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
				continue;
			}

			features.remove(row[r]);		

			if (feature_mode==MCFEATURE_MODE){
				mcfeateditor.remove(row[r]);
			}
		}

		app.getModel().setDirty(true);
		tablemodel.fireTableDataChanged();
		((ModelDrawingView) app.getDrawingView()).repaint();
	}
	
	
	private class FeatureTableModel extends AbstractTableModel{
		
		public FeatureTableModel(){
		}
		
		/* (non-Javadoc) 
		 * @see javax.swing.table.TableModel#getColumnClass(int)
		 */
		public Class getColumnClass(int columnIndex) {
			if (feature_mode==BASEATTRIBUTE_MODE){
				return String.class;
			}
			if (feature_mode==MCFEATURE_MODE){
				if (columnIndex==0){
					return String.class;
				}
				if (columnIndex==1){
					return super.getColumnClass(columnIndex);
				}
			}
			return super.getColumnClass(columnIndex);
		}

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getColumnCount()
		 */
		public int getColumnCount() {
			if (feature_mode==BASEATTRIBUTE_MODE)
				return 3;
			if (feature_mode==MCFEATURE_MODE)
				return 2;
			return 1;
		}

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getRowCount()
		 */
		public int getRowCount() {
			return features.size();
		}

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getValueAt(int, int)
		 */
		public Object getValueAt(int rowIndex, int columnIndex) {
			Feature feat=(Feature) features.get(rowIndex);
			try{
				if (columnIndex==0){
					return feat.getName();
				}
				if (columnIndex==1){
					if (feat instanceof BaseAttribute){
						return ((BaseAttribute) feat).getType();
					}
					if (feat instanceof MultiColumnFeature){
						return ((MultiColumnFeature) feat).getBaseAttributes();
					}
				}
				if (columnIndex==2){
					if (feat instanceof BaseAttribute){
						return ((BaseAttribute) feat).getConceptualDataTypeName();
					}
				}
			}catch(M4Exception error){
				M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			}
			return "";
		}
		
		

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getColumnName(int)
		 */
		public String getColumnName(int column) {
			if (feature_mode==BASEATTRIBUTE_MODE){
				if (column==0){
					return Resource.getString("ATTR_NAME");
				}
				if (column==1){
					return Resource.getString("FEATURE_TYPE");
				}
				if (column==2){
					return Resource.getString("FEATURE_DATATYPE");
				}
			}
			if (feature_mode==MCFEATURE_MODE){
				if (column==0){
					return Resource.getString("ATTR_NAME");
				}
				if (column==1){
					return Resource.getString("BASEATTRIBUTES");
				}
			}
			return ":-)";
		}
		
		

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#isCellEditable(int, int)
		 */
		public boolean isCellEditable(int rowIndex, int columnIndex) {
			if (app.getViewMode()==Application.EDITOR){
				return true;
			}
			if((feature_mode==MCFEATURE_MODE)&&(columnIndex==1)){
				return true;
			}
			return false;
		}

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
		 */
		public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
			if (app.getViewMode()==Application.EDITOR){
				Feature feat=(Feature) features.get(rowIndex);
				try{
					if (columnIndex==0){
						feat.setName((String) aValue);
					}
					if (columnIndex==1){
						if (feat instanceof BaseAttribute){
							((BaseAttribute) feat).setType((String) aValue);
						}
						if (feat instanceof MultiColumnFeature){
							//nothing todo here
							//the dialog sets the baseattributes
							//((MultiColumnFeature) feat).setBaseAttributes((Collection) aValue);							
						}
					}
					if (columnIndex==2){
						if (feat instanceof BaseAttribute){
							((BaseAttribute) feat).setConceptualDataTypeName((String) aValue);
						}else{
						}
					}
					app.getModel().setDirty(true);
				}catch(M4Exception error){
					M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
				}
				
				
			}
		}

	}
	
	/**
	 *Creates editors and renderers for the parameters.
	 */
	public void createEditorAndRenderer(){
//		name_editor=new Vector();
		mcfeateditor=new Vector();
//		data_type_editor=new Vector();
		
		BaseAttributeEditor editor;
		Feature feat;
		for (int i=0;i<features.size();i++){
			feat=(Feature) features.get(i);	

			if (feature_mode==BASEATTRIBUTE_MODE){	
//				name_editor.add(new NameEditor(feat));
//				att_type_editor.add(new BaseAttributeEditor((BaseAttribute) feat,BaseAttributeEditor.ATTRIBUTE_TYPE_EDITOR));
//				data_type_editor.add(new BaseAttributeEditor((BaseAttribute) feat,BaseAttributeEditor.DATA_TYPE_EDITOR));
			}

			if (feature_mode==MCFEATURE_MODE){	
//				name_editor.add(new NameEditor(feat));
				mcfeateditor.add(new MCFeatureEditor(app,(MultiColumnFeature) feat));
			}
		}
		
		
		if (feature_mode==BASEATTRIBUTE_MODE){	
			TableColumn tablecolumn = getColumnModel().getColumn(1);
			String[] types=new String[]{BaseAttribute.TYPE_DB,BaseAttribute.TYPE_MINING};
			JComboBox comboBox = new JComboBox((Object[]) types);
			tablecolumn.setCellEditor(new DefaultCellEditor(comboBox));			

			tablecolumn = getColumnModel().getColumn(2);
			String[] cdtypes=new String[ConceptualDatatypes.CDTYPES.length];
			for(int i=0;i<cdtypes.length;i++){
				cdtypes[i]=ConceptualDatatypes.CDTYPES[i];
			}
			comboBox = new JComboBox((Object[]) cdtypes);
			tablecolumn.setCellEditor(new DefaultCellEditor(comboBox));			
		}


	}

	/* (non-Javadoc)
	 * @see javax.swing.JTable#getCellEditor(int, int)
	 */
	public TableCellEditor getCellEditor(int row, int column) {
		if (row>=features.size()){
			return super.getCellEditor(row,column);
		}

		if (column==0){
			return super.getCellEditor(row,column);
		}
		if (column==1){
			if (feature_mode==BASEATTRIBUTE_MODE){	
				return super.getCellEditor(row,column);
			}else{
				return (TableCellEditor) mcfeateditor.get(row);
			}
		}
		if (column==2){
//			return (TableCellEditor) data_type_editor.get(row);
			return super.getCellEditor(row,column);
		}
		return null;
	}

	/* (non-Javadoc)
	 * @see javax.swing.JTable#getCellRenderer(int, int)
	 */
	public TableCellRenderer getCellRenderer(int row, int column) {
		if (row>=features.size()){
			return super.getCellRenderer(row,column);
		}

		if (column==0){
			return super.getCellRenderer(row,column);
//			return (TableCellRenderer) name_editor.get(row);
		}
		if (column==1){
			if (feature_mode==BASEATTRIBUTE_MODE){	
				return super.getCellRenderer(row,column);
			}else{
				return (TableCellRenderer) mcfeateditor.get(row);
			}
		}
		if (column==2){
//			return (TableCellRenderer) data_type_editor.get(row);
			return super.getCellRenderer(row,column);
		}
		return null;
	}

}
/*
 * Historie
 * --------
 *
 * $Log: FeatureTable.java,v $
 * Revision 1.3  2006/04/11 14:10:17  euler
 * Updated license text.
 *
 * Revision 1.2  2006/04/06 16:31:16  euler
 * Prepended license remark.
 *
 * Revision 1.1  2006/01/03 09:54:25  hakenjos
 * Initial version!
 *
 */

/*
Revision 1.6  2005/11/29 08:00:38  hakenjos
MCFeatures must have at least two BaseAttributes.

Revision 1.5  2005/11/24 09:50:28  hakenjos
Names etc. replaced with resource-access

Revision 1.4  2005/11/10 10:48:44  hakenjos
*** empty log message ***

Revision 1.3  2005/11/03 10:46:25  hakenjos
*** empty log message ***

Revision 1.2  2005/10/18 09:31:54  hakenjos
*** empty log message ***

Revision 1.1  2005/10/11 07:57:57  hakenjos
*** empty log message ***

 */
