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

import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.JOptionPane;

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 org.musoft.limo.model.ModelFigureElement;
import org.musoft.limo.model.ModelListener;
import org.musoft.limo.model.ModelPrimitiveAttribute;

import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.gui.application.MiningMartApplication;
import edu.udo.cs.miningmart.gui.application.MiningMartMenuBar;
import edu.udo.cs.miningmart.gui.application.MiningMartToolBar;
import edu.udo.cs.miningmart.gui.concepteditor.CreateRelationDialog;
import edu.udo.cs.miningmart.m4.Concept;
import edu.udo.cs.miningmart.m4.M4Interface;
import edu.udo.cs.miningmart.m4.Projection;
import edu.udo.cs.miningmart.m4.Relation;
import edu.udo.cs.miningmart.m4.utils.Print;

/**
 * This is the parent model of the <code>ConceptEditor</code>.
 * @author Daniel Hakenjos
 * @version $Id: MiningMartConcepts.java,v 1.9 2006/04/11 14:10:15 euler Exp $
 */
public class MiningMartConcepts extends Model{


	private MiningMartApplication app;
	
	private boolean cansetdirty;
	
	private int subconceptcounter;
	// private int relationcounter; // Relations have names
	private int projectioncounter;
	
	/**
	 * Creates new MiningMartConcepts.
	 */
	public MiningMartConcepts(MiningMartApplication app) {
		super(Resource.getString("CONCEPTS"));
		this.app=app;
		this.cansetdirty=true;
		this.subconceptcounter=0;
		this.projectioncounter=0;
		((ModelPrimitiveAttribute)getAttribute(Resource.getString("ATTR_COLOR"))).setColor(Color.white);

	}
    
    
	/**
	 * Gets the <code>MiningMartApplication</code>.
	 */
	public MiningMartApplication getMMartApplication(){
		return app;
	}

	/**
	 * Inits this <code>MiningMartConcepts</code>.
	 * It loads the concepts and relations between concepts.
	 */
	public void initConcepts(){
		cansetdirty=false;
		
		//init the concepts
		
		try{
			Collection c=M4Interface.getCurrentCase().getAllConceptNames();
			if (app.hasDataModel()){
				c=app.getDataModel();
			}
			
			Iterator iter=c.iterator();
			String conceptname;
			Concept concept;
			MiningMartConcept mconcept;
			Point p;
			int i=10;
			Rectangle rectangle;
			int nrbas;
			int nrmcfs;
			int nr=app.getNumberOfFeatures();
			while (iter.hasNext()){
				conceptname=(String) iter.next();
				if (conceptname==null){
					continue;
				}
				concept=M4Interface.getCurrentCase().getConcept(conceptname);
				if (concept==null){
					continue;
				}
				p=concept.getPoint();
				if (p==null){
					p=new Point(i,i);
					concept.setPoint(p);
				}
				nrbas=concept.getAllBaseAttributes().size();
				nrmcfs=concept.getAllMultiColumnFeatures().size();
				rectangle=new Rectangle(p.x,p.y,200,50+Math.min(nrbas,nr)*21+Math.min(nrmcfs,nr));
				rectangle=new Rectangle(p.x,p.y,200,70);
				mconcept=new MiningMartConcept(app,concept,this,p,rectangle);
				mconcept.initConcept();
				addMiningMartConcept(this,mconcept);
				i+=40;
			}

		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
		
		//init the subconcept-transition
		//Add SubConcepts		
		if (this.app.shouldDrawSubconceptLinks()) {
			MiningMartConcept superconcept,subconcept;
			for(int i=0;i<this.getChildCount();i++){
				superconcept=(MiningMartConcept) this.getChild(i);
				
				try {
					Collection subconcepts=superconcept.getConcept().getSubConcepts();
					Iterator iter=subconcepts.iterator();
					while(iter.hasNext()){
						subconcept=(MiningMartConcept) this.getChild(((Concept) iter.next()).getName());
						if (subconcept != null) {
							createSubConceptTransition(null,superconcept,subconcept,true);
						}
						//	System.out.println("superconcept: "+superconcept.getName());
						//	System.out.println("subconcept: "+subconcept.getName());
					}					
				} catch (M4Exception error) {
					M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
				}
			}
		}
		
		//init the relations
		if (this.app.shouldDrawRelationships()) {
			MiningMartConcept start, end;
			Relation relation;
			for(int i=0;i<this.getChildCount();i++){
				start=(MiningMartConcept) this.getChild(i);
				
				try{
					Collection relationsStartingHere=start.getConcept().getTheFromRelationships();
					Iterator iter=relationsStartingHere.iterator();
					while(iter.hasNext()){
						relation=(Relation) iter.next();
						end=(MiningMartConcept) this.getChild(relation.getTheToConcept().getName());
						if (end != null) {
							createMiningMartRelation(relation,start,end);
						}
					}
				} catch (M4Exception error) {
					M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
				}			
			}
		}		
		
		//init the projections
		if (this.app.shouldDrawProjections()) {
			MiningMartConcept from,to;
			Projection projection;
			for(int i=0;i<this.getChildCount();i++){
				from=(MiningMartConcept) this.getChild(i);
				
				try{
					Collection toprojections=from.getConcept().getProjectionsAsFromConcept();
					Iterator iter=toprojections.iterator();
					while(iter.hasNext()){
						projection=(Projection) iter.next();
						to=(MiningMartConcept) this.getChild(projection.getToConcept().getName());
						if (to != null) {
							createMiningMartProjection(projection,from,to);
						}
					}
				} catch (M4Exception error) {
					M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
				}
			}
		}		
		
		cansetdirty=true;
	}

	/**
	 * Adds a <code>MiningMartConcept</code> to this <code>MiningMartConcepts</code>.
	 * @ return null if creating the MiningMartConcepts is permitted
	 */
	public MiningMartConcept addMiningMartConcept(ModelFigureElement parent,MiningMartConcept concept){

		if (!( parent instanceof Model)){
			return null;
		}

		for (int i = 0; i < getListenerCount(); i++) {
			getListener(i).onCreateChild(this, concept);
		}
        
		if (concept.canSetParent(this) && canAddChild(concept)) {
			concept.setParent(this);
		}
		else {
			concept.destroy();
			concept = null;
		}
        
		return concept;

	}
	
	/**
	 * Creates a new <code>MiningMartSubConcept</code>.
	 * @param the name of the transition
	 * @param superconcept the super <code>Concept</code> 
	 * @param subconcept the sub <code>Concept</code>
	 * @param existsTransition if the transition exists then no new <code>TransitionFigure</code> is added.
	 */
	public MiningMartSubConcept createSubConceptTransition(String name, MiningMartConcept superconcept, MiningMartConcept subconcept, boolean existsTransition) {

		if (name==null){
			subconceptcounter++;
			name=new String("SubConcept("+subconceptcounter+")");
		}

		MiningMartSubConcept result = new MiningMartSubConcept(app,name,(Model) this,superconcept,subconcept);

		if (!existsTransition){
			try {
				superconcept.getConcept().addSubConcept(subconcept.getConcept());
			} catch (M4Exception error) {
				M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			}
		}

		return addSubConceptTransition(result);
	}

	/**
	 * Adds the specified <code>MiningMartSubConcept</code> to this <code>MiningMartConcepts</code>.
	 */
	public MiningMartSubConcept addSubConceptTransition(MiningMartSubConcept transition){

		for (int i = 0; i < getListenerCount(); i++) {
			getListener(i).onCreateConnection(this, transition);
		}

		return transition;
	}

	
	/**
	 * Gets the listener count.
	 */
	public int countListener(){
		return getListenerCount();
	}
	
	/**
	 * Gets the modellistener.
	 */
	public ModelListener getModelListener(int index){
		return getListener(index);		
	}

	/**
	 * Creates a new <code>MiningMartConcept</code> with the specified parameters.
	 * @param parent the MiningMartConcept is child of this <code>ModelFigureElement</code>.
	 * @param name the name of the <code>MiningMartConcept</code>
	 * @param point the <code>MiningMartConcept</code> is placed at this point.
	 * @param bounds the bounds of the figure.
	 * @return null if creating the MiningMartConcept is permitted
	 */
	public MiningMartConcept createMiningMartConcept(ModelFigureElement parent, String name, Point point, String type) {

		MiningMartConcept result;
		Concept concept;
		try{
			name=M4Interface.getCurrentCase().getValidName(name,Concept.class);
			concept=M4Interface.getCurrentCase().createConcept(name,type);
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			JOptionPane.showMessageDialog(app,
				error.getMessage(),
				Resource.getString("DIALOG_ERROR_TITLE"),
				JOptionPane.ERROR_MESSAGE);
			return null;
		}
		
		int nr=app.getNumberOfFeatures();
		int nrbas=0;
		int nrmcfs=0;
		try{
			nrbas=concept.getAllBaseAttributes().size();
			nrmcfs=concept.getAllMultiColumnFeatures().size();
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			nrbas=0;
			nrmcfs=0;
		}
		Rectangle rectangle=new Rectangle(point.x,point.y,200,50+Math.min(nrbas,nr)*21+Math.min(nrmcfs,nr));
		rectangle=new Rectangle(point.x,point.y,200,70);
        
		result = new MiningMartConcept(app,concept,this,point,rectangle);
		result=addMiningMartConcept(parent,result);
		result.initConcept();

		return result;
	}

	/**
	 * Creates a new <code>MiningMartConcept</code> with the specified parameters.
	 * @param parent the MiningMartConcept is child of this <code>ModelFigureElement</code>.
	 * @param concept the created <code>MiningMartConcept</code> wrapps this <code>Concept</code>.
	 * @param point the <code>MiningMartConcept</code> is placed at this point.
	 * @param bounds the bounds of the <code>MiningMartConcept</code>.
	 * @return null if creating the MiningMartConcept is permitted
	 */
	public MiningMartConcept createMiningMartConcept(ModelFigureElement parent, Concept concept, Point point) {

		MiningMartConcept result;

		int nr=app.getNumberOfFeatures();
		int nrbas=0;
		int nrmcfs=0;
		try{
			nrbas=concept.getAllBaseAttributes().size();
			nrmcfs=concept.getAllMultiColumnFeatures().size();
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			nrbas=0;
			nrmcfs=0;
		}
		Rectangle rectangle=new Rectangle(point.x,point.y,200,50+Math.min(nrbas,nr)*21+Math.min(nrmcfs,nr));
		rectangle=new Rectangle(point.x,point.y,200,70);

		result = new MiningMartConcept(app,concept,parent,point,rectangle);
		//first the concept must be added
		result=addMiningMartConcept(parent,result);

		// then you can init the concept and the features are added
		result.initConcept();

		return result;
	}



	/**
	 * Adds a <code>MiningMartRelation</code> to the <code>MiningMartConcepts</code>.
	 * @ return null if creating the MiningMartRelation is permitted
	 */
	public MiningMartRelation addMiningMartRelation(MiningMartRelation relation){

		for (int i = 0; i < getListenerCount(); i++) {
			getListener(i).onCreateConnection(this, relation);
		}
        
		return relation;

	}

	/**
	 * Creates a new <code>MiningMartRelation</code> with the specified parameters.
	 * @param parent the MiningMartRelation is child of this <code>Model</code>.
	 * @param name the name of the <code>MiningMartRelation</code>
	 * @param start The MiningMartConcept containing the from-key of the <code>Relation</code>.
	 * @param end The MiningMartConcept containing the to-key of the <code>Relation</code>.
	 * @return null if creating the MiningMartRelation is permitted
	 */
	public MiningMartRelation createMiningMartRelation(String name,MiningMartConcept fromconcept, MiningMartConcept toconcept) {

		MiningMartRelation result;
		Relation relation;
		try{
			CreateRelationDialog dialog=new CreateRelationDialog(app,fromconcept,toconcept);
			if (dialog.getExitAction()==CreateRelationDialog.CANCEL){
				return null;
			}
			
			name=dialog.getName();
			if ((name==null)||(name.equals(""))){
				name=Resource.getString("RELATION");
			}
			
			name=M4Interface.getCurrentCase().getValidName(name,Relation.class);
			relation=dialog.getRelation();			
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			JOptionPane.showMessageDialog(app,
				error.getMessage(),
				Resource.getString("DIALOG_ERROR_TITLE"),
				JOptionPane.ERROR_MESSAGE);
			return null;
		}
		
		if (relation==null)
			return null;        

		result = new MiningMartRelation(app,relation,name, this, fromconcept, toconcept);

		return addMiningMartRelation(result);
	}

	/**
	 * Creates a new <code>MiningMartRelation</code> with the specified parameters.
	 * @param parent the MiningMartRelation is child of this <code>Model</code>.
	 * @param chain the created <code>MiningMartRelation</code> wrapps this <code>Relation</code>.
	 * @param start The MiningMartConcept containing the from-key of the <code>Relation</code>.
	 * @param end The MiningMartConcept containing the to-key of the <code>Relation</code>.
	 * @return null if creating the MiningMartRelation is permitted
	 */
	public MiningMartRelation createMiningMartRelation(Relation relation, MiningMartConcept start, MiningMartConcept end) {

		String name = relation.getName();

		MiningMartRelation result;
		result = new MiningMartRelation(app,relation, name, this,start, end);

		return addMiningMartRelation(result);
	}
	
	public MiningMartProjection addMiningMartProjection(MiningMartProjection projection){
		for (int i = 0; i < getListenerCount(); i++) {
			getListener(i).onCreateConnection(this, projection);
		}
        
		return projection;
	}
	
	public MiningMartProjection createMiningMartProjection(Projection projection, MiningMartConcept from,MiningMartConcept to){

		projectioncounter++;
		String name=new String("Projection("+projectioncounter+")");

		MiningMartProjection result=new MiningMartProjection(app,projection,name, this,from,to);
		
		return addMiningMartProjection(result);
	}

	public MiningMartProjection createMiningMartProjection(String name, MiningMartConcept from,MiningMartConcept to){

		MiningMartProjection result;
		Projection projection;
		try{
			
			if (name==null)
				name=Resource.getString("PROJECTION");
			name=M4Interface.getCurrentCase().getValidName(name,Projection.class);
			Concept fromconcept=from.getConcept();
			Concept toconcept=to.getConcept();
			
			projection=fromconcept.createProjectionToConcept(toconcept,name);
			if (!projection.isValid()){
				JOptionPane.showMessageDialog(app,
					"The projection isn't valid.",
					Resource.getString("DIALOG_ERROR_TITLE"),
					JOptionPane.ERROR_MESSAGE);
					projection.deleteSoon();
					projection = null;
			}
			
		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
			JOptionPane.showMessageDialog(app,
				error.getMessage(),
				Resource.getString("DIALOG_ERROR_TITLE"),
				JOptionPane.ERROR_MESSAGE);
			return null;
		}
		
		if (projection==null)
			return null;
        
		projectioncounter++;
		name=new String("Projection("+projectioncounter+")");
        
		result = new MiningMartProjection(app,projection,name,this, from, to);

		return addMiningMartProjection(result);
	}



	public boolean canAddChild(ModelFigureElement child) {
		return true;
	}

	public boolean canRemoveChild(ModelFigureElement child) {
		return true;
	}


	public boolean canSetParent(ModelFigureElement parent) {
		return false;
	}

	public String getType() {
		return Resource.getString("CONCEPTS");
	}


	public boolean canDestroy() {
		if (app.getViewMode()==Application.VIEWER){
			return false;
		}
		return true;
	}

	/**
	 * Sets the <code>MiningMartCase</case> dirty.
	 * @see org.musoft.limo.model.Model#setDirty(boolean)
	 */
	public void setDirty(boolean dirty) {
		if (!cansetdirty)
			return;
		if ((app!=null)&&(app.getViewMode()==Application.VIEWER)){
			return;
		}
		
		super.setDirty(dirty);
		if ((dirty)&&(app!=null)){
		 ((MiningMartMenuBar) app.getJMenuBar()).setItemState(Resource.getString("MENU_CASE")
				+ "."+ Resource.getString("MENU_CASE_SAVE"),true);
		((MiningMartToolBar) app.getToolbar()).enableTool(Resource.getString("TOOL_SAVECASE"),true);

		}
		
		if (app!=null)
			app.updateToolsAndMenus();
	}



	/* (non-Javadoc)
	 * @see org.musoft.limo.model.ModelElement#destroy()
	 */
	public void destroy() {
		MiningMartConcept concept;
		for(int i=0;i<this.getChildCount();i++){
			concept=(MiningMartConcept) getChild(i);
			concept.setDeleteInDatabase(false,true);
		}
		
		ModelConnectionElement connection;
		for(int i=0;i<this.getConnectionCount();i++){
			connection=getConnection(i);
			if (connection instanceof MiningMartSubConcept){
				((MiningMartSubConcept) connection).setDeleteInDatabase(false);
			}
			if (connection instanceof MiningMartRelation){
				((MiningMartRelation) connection).setDeleteInDatabase(false);
			}
			if (connection instanceof MiningMartProjection){
				((MiningMartProjection) connection).setDeleteInDatabase(false);
			}
		}
		
		super.destroy();
	}

	/* (non-Javadoc)
	 * @see org.musoft.limo.model.ModelElement#canSetName(java.lang.String)
	 */
	public boolean canSetName(String name) {
		return false;
	}

}
/*
 * Historie
 * --------
 *
 * $Log: MiningMartConcepts.java,v $
 * Revision 1.9  2006/04/11 14:10:15  euler
 * Updated license text.
 *
 * Revision 1.8  2006/04/06 16:31:14  euler
 * Prepended license remark.
 *
 * Revision 1.7  2006/03/24 14:19:31  euler
 * Added concept links preferences
 *
 * Revision 1.6  2006/02/10 17:27:42  euler
 * bugfix
 *
 * Revision 1.5  2006/01/27 17:27:18  euler
 * Bugfix
 *
 * Revision 1.4  2006/01/26 15:45:31  euler
 * bugfix
 *
 * Revision 1.3  2006/01/26 15:40:10  euler
 * bugfix
 *
 * Revision 1.2  2006/01/03 10:59:39  hakenjos
 * Relations and Projections have no name!
 *
 * Revision 1.1  2006/01/03 09:54:36  hakenjos
 * Initial version!
 *
 */

/*
Revision 1.16  2005/12/23 11:44:11  euler
Bugfix concerning relations in method
initConcepts() (line 138)

Revision 1.15  2005/12/22 10:46:21  hakenjos
*** empty log message ***

Revision 1.14  2005/12/15 09:15:55  hakenjos
*** empty log message ***

Revision 1.13  2005/12/13 09:32:34  hakenjos
Initial version!

Revision 1.12  2005/12/06 08:53:14  hakenjos
*** empty log message ***

Revision 1.11  2005/10/20 08:58:23  hakenjos
*** empty log message ***

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

Revision 1.9  2005/08/25 08:20:27  hakenjos
*** empty log message ***

Revision 1.8  2005/08/23 09:03:03  hakenjos
*** empty log message ***

Revision 1.7  2005/08/16 08:41:44  hakenjos
*** empty log message ***

Revision 1.6  2005/07/21 14:47:37  hakenjos
*** empty log message ***

Revision 1.5  2005/07/20 14:00:06  hakenjos
*** empty log message ***

Revision 1.4  2005/07/19 14:20:55  hakenjos
*** empty log message ***

Revision 1.3  2005/07/19 12:18:06  hakenjos
*** empty log message ***

Revision 1.2  2005/07/07 07:51:36  hakenjos
*** empty log message ***

Revision 1.1  2005/06/22 08:31:39  hakenjos
Initial version!

 */
