/*
 * 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.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultCellEditor;
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.SwingConstants;
import javax.swing.table.AbstractTableModel;
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.DbConnectionClosed;
import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.gui.application.MiningMartApplication;
import edu.udo.cs.miningmart.gui.util.M4ObjectComparator;
import edu.udo.cs.miningmart.m4.BaseAttribute;
import edu.udo.cs.miningmart.m4.Column;
import edu.udo.cs.miningmart.m4.Columnset;
import edu.udo.cs.miningmart.m4.Concept;
import edu.udo.cs.miningmart.m4.M4Interface;
import edu.udo.cs.miningmart.m4.PrimaryKey;
import edu.udo.cs.miningmart.m4.utils.Print;

/**
 * This is a <code>JPanel</code> to show and edit the mapping between the <code>BaseAttribute</code>s 
 * of a <code>Concept</code> and the <code>Column</code>s of its <code>Columnset</code>.
 * 
 * @author Daniel Hakenjos
 * @version $Id: MappingPanel.java,v 1.3 2006/04/11 14:10:17 euler Exp $
 */
public class MappingPanel extends ConceptPanel implements ActionListener{
	
	private MiningMartApplication app;
	
	private Concept concept;
	
	private Columnset columnset;
	
	private MappingTable table;
	
	private JButton okButton,cancelButton, clearButton;
	
	private Column[] allcolumns;
	private String[] allcolumnNames;
	
	private String[] baseattributes;
	private String[] ba_types;
	
	private Column[] Columns;
	private String[] columns;
	private String[] coltypes;
	
	private boolean[] primaryKey;
	
	public MappingPanel(MiningMartApplication app, Concept concept){
		this.app=app;
		this.concept=concept;
		
		initData();
		initComponents();
	}
	
	private void initData(){
		
		Collection coll;
		try {
			coll=concept.getColumnSets();
		} catch (M4Exception error) {
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			coll=new LinkedList();
		}

		if (coll.size()!=1){
			baseattributes=new String[0];
			ba_types=new String[0];
			Columns=new Column[0];
			columns=new String[0];
			coltypes=new String[0];
			primaryKey=new boolean[0];
			return;
		}
		
		try {
			columnset=(Columnset) coll.toArray()[0];
			Collection columnscoll=columnset.getColumns();
			allcolumns=new Column[columnscoll.size()];	
			allcolumnNames=new String[columnscoll.size()+1];
			allcolumnNames[0]=Resource.getString("MAPPING_NONE");
			Iterator iter=columnscoll.iterator();
			int index=0;
			while (iter.hasNext()){
				allcolumns[index]=(Column) iter.next();
				allcolumnNames[index+1]=allcolumns[index].getName()+"-"+allcolumns[index].getColumnDataTypeName().toLowerCase();
				index++;
			}
		
		
			Collection bas=concept.getAllBaseAttributes();

			//only baseattributes of type db can be connected
			iter=bas.iterator();
			int nr_bas=0;
			BaseAttribute ba;
			while(iter.hasNext()){
				ba=(BaseAttribute) iter.next();
				if (ba.getType()==BaseAttribute.TYPE_DB){
					nr_bas++;
				}
			}

			//init the data
			baseattributes=new String[nr_bas];
			ba_types=new String[nr_bas];
	
			Columns=new Column[nr_bas];
			columns=new String[nr_bas];
			coltypes=new String[nr_bas];

			primaryKey=new boolean[nr_bas];

			PrimaryKey pkey=concept.getPrimaryKey();
			Collection pkeycoll;
			if (pkey==null){
				pkeycoll=new LinkedList();
			}else{
				pkeycoll=pkey.getAllColumns();
			}

			LinkedList baslist=new LinkedList();
			baslist.addAll(bas);
			//init the baseattributes,columns and primarykeys
			Collections.sort(baslist,new M4ObjectComparator());
			iter=baslist.iterator();
			index=0;
			Collection columncoll;
			Column column;
			while(iter.hasNext()){
				ba=(BaseAttribute) iter.next();
				if (ba.getType().equals(BaseAttribute.TYPE_DB)){
					baseattributes[index]=ba.getName();				
					ba_types[index]=ba.getConceptualDataTypeName().toLowerCase();
					columncoll=ba.getColumns();
					if (columncoll.size()!=1){
						Columns[index]=null;
						columns[index]=Resource.getString("MAPPING_NONE");
						coltypes[index]="";
						primaryKey[index]=false;
					}else{
						column=(Column) columncoll.toArray()[0];
						Columns[index]=column;
						columns[index]=column.getName();
						coltypes[index]="-"+column.getColumnDataTypeName().toLowerCase();
						primaryKey[index]=pkeycoll.contains(column);
					}
					index++;
				}
			}
			
		} catch (M4Exception error) {
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}catch (DbConnectionClosed error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
		
	}
	
	
	private void initComponents(){
		
		setLayout(new BorderLayout(5,5));
		setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

		//Info
		JPanel infopanel=new JPanel();
		infopanel.setLayout(new GridLayout(2,1,5,5));
		infopanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
		add(infopanel,BorderLayout.NORTH);	

		JLabel label=new JLabel();
		label.setText(Resource.getString("BASEATTRIBUTE")+" - "+Resource.getString("MAPPING"));
		Font font=new Font("SansSerif",Font.PLAIN,15);
		label.setFont(font);
		label.setHorizontalAlignment(SwingConstants.CENTER);	
		infopanel.add(label);

		label=new JLabel();
		label.setText(concept.getName());
		font=new Font("SansSerif",Font.PLAIN,13);
		label.setFont(font);
		label.setHorizontalAlignment(SwingConstants.CENTER);	
		label.setForeground(Color.BLUE);
		infopanel.add(label);

		//Button		
		
		clearButton=new JButton(Resource.getString("CLEAR"));
		clearButton.addActionListener(this);
		
		okButton=new JButton(Resource.getString("OK"));
		okButton.addActionListener(this);
		okButton.setEnabled(false);
		
		cancelButton=new JButton(Resource.getString("CANCEL"));
		cancelButton.addActionListener(this);
		
		JPanel buttonPanel=new JPanel();
		buttonPanel.setLayout(new BoxLayout(buttonPanel,BoxLayout.X_AXIS));
		buttonPanel.add(Box.createHorizontalGlue());
		
		buttonPanel.add(clearButton);
		buttonPanel.add(Box.createRigidArea(new Dimension(5, 0)));		
		buttonPanel.add(okButton);
		buttonPanel.add(Box.createRigidArea(new Dimension(5, 0)));		
		buttonPanel.add(cancelButton);
		add(buttonPanel,BorderLayout.SOUTH);
		
		if (app.getViewMode()!=Application.EDITOR){
			clearButton.setEnabled(false);
			okButton.setEnabled(false);
		}
		
		//Table
		table=new MappingTable();
		table.createEditor();
		JScrollPane scrollpane=new JScrollPane(table);
		add(scrollpane,BorderLayout.CENTER);
		
	}

	/* (non-Javadoc)
	 * @see edu.udo.cs.miningmart.gui.concepteditor.ConceptPanel#getConcept()
	 */
	public Concept getConcept() {
		return this.concept;
	}


	
	public String toString(){
		return Resource.getString("MAPPING");
	}
	
	private void createMapping(){
		//Do the BaseAttributeMapping
		try{
			BaseAttribute baseatt;
			LinkedList pkeyslist=new LinkedList();

			for(int i=0;i<this.baseattributes.length;i++){
				baseatt=this.concept.getBaseAttribute(baseattributes[i]);
				if (Columns[i]==null){
					baseatt.setColumns(new LinkedList());
				}else{
					LinkedList list=new LinkedList();
					list.add(Columns[i]);
					baseatt.setColumns(list);
					if (primaryKey[i]){
						pkeyslist.add(baseatt);
					}
				}
			}

			PrimaryKey pkey=concept.createPrimaryKey(pkeyslist);
			columnset.setPrimaryKey(pkey);

		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
		
		app.getModel().setDirty(true);
		((ModelDrawingView) app.getDrawingView()).repaint();
	}
	
	private void clearMapping(){
		for(int row=0;row<this.baseattributes.length;row++){
			Columns[row]=null;
			columns[row]=Resource.getString("MAPPING_NONE");
			coltypes[row]="";
			primaryKey[row]=false;		
		}
		((AbstractTableModel) table.getModel()).fireTableDataChanged();		
		okButton.setEnabled(true);		
	}

	/* (non-Javadoc)
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent event) {
		if (!(event.getSource() instanceof JButton))
			return;
		JButton source=(JButton) event.getSource();
		
		if (source.getText().equals(cancelButton.getText())){
			//Removes the tab
			app.removeComponentFromTab(this);
		}
		if (source.getText().equals(okButton.getText())){
			//create the mapping
			createMapping();
			//Removes the tab
			app.removeComponentFromTab(this);
		}
		if (source.getText().equals(clearButton.getText())){
			//clear the mapping
			clearMapping();
		}
	}

	private class MappingTable extends JTable{
		
		public MappingTable(){
			setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
			getTableHeader().setReorderingAllowed(false);
			setRowHeight(getRowHeight() + 4);
			setModel(new MappingTableModel());
			this.getColumnModel().getColumn(2).setMaxWidth(90);
		}
		
		public void createEditor(){
			TableColumn tablecolumn = getColumnModel().getColumn(1);
			JComboBox comboBox = new JComboBox((Object[]) allcolumnNames);
			tablecolumn.setCellEditor(new DefaultCellEditor(comboBox));			
		}
		
	}

	private class MappingTableModel extends AbstractTableModel {
		
		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getColumnCount()
		 */
		public int getColumnCount() {
			return 3;
		}

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

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getValueAt(int, int)
		 */
		public Object getValueAt(int rowIndex, int columnIndex) {
			if (columnIndex==0){
				return baseattributes[rowIndex]+"-"+ba_types[rowIndex];
			}else if (columnIndex==1){
				return columns[rowIndex]+coltypes[rowIndex];
			}else if (columnIndex==2){
				return new Boolean(primaryKey[rowIndex]);
			}
			return null;
		}
		
		

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getColumnClass(int)
		 */
		public Class getColumnClass(int columnIndex) {
			if (columnIndex==2){
				return Boolean.class;
			}
			return String.class;
		}

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#getColumnName(int)
		 */
		public String getColumnName(int column) {
			if (column==0){
				return Resource.getString("BASEATTRIBUTE");
			}
			if (column==1){
				return Resource.getString("COLUMN");
			}
			if (column==2){
				return Resource.getString("PRIMARYKEY");
			}
			return ":-)";
		}

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

		/* (non-Javadoc)
		 * @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
		 */
		public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
			okButton.setEnabled(true);
			
			if (columnIndex==1){
				String value=(String) aValue;
				if (value.equals(Resource.getString("MAPPING_NONE"))){
					Columns[rowIndex]=null;
					columns[rowIndex]=Resource.getString("MAPPING_NONE");
					coltypes[rowIndex]="";
					primaryKey[rowIndex]=false;
					fireTableDataChanged();
					return;
				}
				columns[rowIndex]=value.substring(0,value.indexOf('-'));
				try {
					Columns[rowIndex]=columnset.getColumn(columns[rowIndex]);
				} catch (M4Exception error) {
					M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
					Columns[rowIndex]=null;
					columns[rowIndex]=Resource.getString("MAPPING_NONE");
					coltypes[rowIndex]="";
					primaryKey[rowIndex]=false;					
					fireTableDataChanged();
					return;
				}
				coltypes[rowIndex]=value.substring(value.indexOf('-'),value.length());
			}
			if ((columnIndex==2)&&(Columns[rowIndex]!=null)){
				primaryKey[rowIndex]=((Boolean) aValue).booleanValue();
			}else{
				fireTableDataChanged();
			}
			
		}

	}

}
/*
 * Historie
 * --------
 *
 * $Log: MappingPanel.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!
 *
 */
