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

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.ModelFigureElement;
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.m4.Case;
import edu.udo.cs.miningmart.m4.Chain;
import edu.udo.cs.miningmart.m4.M4Data;
import edu.udo.cs.miningmart.m4.M4Interface;
import edu.udo.cs.miningmart.m4.Step;
import edu.udo.cs.miningmart.m4.utils.Print;

/**
 *A wrapper for a case-object. It's the parent-model.
 * @author Daniel Hakenjos
 * @version $Id: MiningMartCase.java,v 1.4 2006/04/11 14:10:15 euler Exp $
 * @see edu.udo.cs.miningmart.m4.Case
 */
public class MiningMartCase extends MiningMartModel {

	private LinkedList namelist; 

	private Case thecase;
	
	private MiningMartApplication app;
	
	private int transcounter;
	
	private boolean deleteInDatabase=true;
	
	private boolean cansetdirty=true;

    /**
     * Creates a new MiningMartCase.
     */
    public MiningMartCase(MiningMartApplication app,Case thecase) {
        super(thecase.getName());
        
        this.app=app;
        this.thecase=thecase;
        this.transcounter=0;

		this.namelist=new LinkedList();

		deleteInDatabase=true;
		cansetdirty=true;

		
        ((ModelPrimitiveAttribute)getAttribute(Resource.getString("ATTR_COLOR"))).setColor(Color.white);
        try{
	        ((ModelPrimitiveAttribute)getAttribute("notes")).setString(thecase.getDocumentation());
        }catch(M4Exception error){
        }        
        //((ModelPrimitiveAttribute) getAttribute("Name")).setAccess(ModelPrimitiveAttribute.ACCESS_READ);

    }

	/**
	 * Sets the flag that this object could be deleted in the database.
	 */    
    public void setDeleteInDatabase(boolean bool,boolean propagate){
    	this.deleteInDatabase=bool;
    	if (propagate){
			for(int i=0;i<this.getConnectionCount();i++){
					((StepTransition) this.getConnection(i)).setDeleteInDatabase(bool);    			
			}
    		for(int i=0;i<this.getChildCount();i++){
    			ModelFigureElement child=this.getChild(i);
    			if (child instanceof MiningMartChain){
    				((MiningMartChain) child).setDeleteInDatabase(bool,true);
    			}
    		}
    	}
    }
    
    /**
     * Gets the flag indicating that this obkect can be deleted in the database.
     */
    public boolean canDeleteInDatabase(){
    	return this.deleteInDatabase;
    }
    
    /**
     * Gets the counter for the transitions.
     */
    public int getTransitionCounter(){
    	return transcounter;
    }

	/**
	 * Increments the counter for the transitions.
	 */    
    public int incrementTransitionCounter(){
    	transcounter++;
    	return transcounter;
    }
    
	/**
	 * Decrements the counter for the transitions.
	 */    
    public int decrementTransitionCounter(){
    	if (transcounter>0)
	    	transcounter--;
    	return transcounter;
    }

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

    /**
     * Inits this <code>MiningMartCase</code>.
     * It loads the chains and transitions between chains.
     */
	public void initTheCase(){
		cansetdirty=false;
		try{
			Collection c=thecase.getTopLevelChains();
			Iterator iter=c.iterator();
			Chain chain;
			MiningMartChain mchain;
			Point p;
			int i=10;
			while (iter.hasNext()){
				chain=(Chain) iter.next();
				p=chain.getPoint();
				if (p==null){
					p=new Point(i,i);
					chain.setPoint(p);
				}
				mchain=new MiningMartChain(app,thecase,chain,thecase.getName(),p,new Rectangle(p.x,p.y,35,35),this);
		        mchain.initTheChain();
				addMiningMartChain(this,mchain);
				i+=40;
			}

			organizeTransitions(false);

		}catch(M4Exception error){
			M4Interface.print.doPrint(Print.ERROR,error.getMessage(),error);
		}
		cansetdirty=true;
	}

    /**
     * Organizes the transitions.
     */
	public void organizeTransitions(boolean check) throws M4Exception{
			int childs=this.getChildCount();
			ModelFigureElement elem1,elem2;
			MiningMartChain mchain1=null, mchain2=null;
			Chain chain1=null,chain2=null;
			StepTransition transition;
			
			boolean create;
			for (int a=0;a<childs;a++){
				elem1=this.getChild(a);	

				if (!(elem1 instanceof MiningMartChain)){
					continue;
				}
				mchain1=(MiningMartChain) elem1;
				chain1=mchain1.getChain();

				for (int j=0;j<childs;j++){

					elem2=this.getChild(j);
						
					if (!(elem2 instanceof MiningMartChain)){
						continue;
					}
					
					mchain2=(MiningMartChain) elem2;
					chain2=mchain2.getChain();
					if (mchain1.getName().equals(mchain2.getName())){
						//dies sins zwei gleiche elemente diese nicht betrachten
						continue;
					}

					create=true;
					if (check){
						create=!existsTransition(mchain1,mchain2);
					}
					//zwischen chain1 und chain1 muss eine Abhngigkeit bestehen
					//jedoch darf noch keine Transition vorhanden sein
					if ((chain1.dependencyExists(chain2))&&(create)){
						//transition besteht nicht, deshalb neue anlegen
						incrementTransitionCounter();
						transition=new StepTransition(app,thecase,Resource.getString("DEPENDENCY")+"("+getTransitionCounter()+")",(Model) this,mchain1,mchain2);
//						transition=new StepTransition(app,thecase,chain1.getName(),(Model) this,mchain1,mchain2);
						addStepTransition(transition);
					}
				}

			}
	}
	
        /**
         * Checks wether a transition between the specified <code>ModelFigureElement</code>s exists.
         * @return true if there exits a transition.
         */
	public boolean existsTransition(ModelFigureElement start, ModelFigureElement end){
		//pruefe die connection
		StepTransition trans=null;
		for(int c=0;c<this.getConnectionCount();c++){
			trans=(StepTransition) this.getConnection(c);
			if ((trans.getStartName().equals(start.getName()))&&(trans.getEndName().equals(end.getName()))){
				//es besteht eine Transition
				return true;
			}
		}
		return false;
	}

	
    /**
     * Adds a <code>MiningMartChain</code> to this <code>MiningMartCase</code>.
     * @ return null if creating the MiningMartChain is permitted
     */
	public MiningMartChain addMiningMartChain(ModelFigureElement parent,MiningMartChain chain){

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

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

	}

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

        MiningMartChain result;
		Chain chain;
		try{
			name=this.thecase.getValidName(name,Chain.class);
			chain=thecase.createChain(name);
		}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;
		}
        
        result = new MiningMartChain(app,thecase,chain,this.getName(),point,bounds,parent);
        result.initTheChain();


        return addMiningMartChain(parent,result);
    }

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

        MiningMartChain result;
        result = new MiningMartChain(app,thecase,chain,this.getName(),point,bounds,parent);
        result.initTheChain();

        return addMiningMartChain(parent,result);
    }


    /**
     * Adds the specified <code>StepTransition</code> to this <code>MiningMartCase</code>.
     */
    public StepTransition addStepTransition(StepTransition transition){

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

		return transition;
    }

    
    /**
     * Creates a new <code>StepTransition</code>.
     * @param the name of the transition
     * @param start the <code>StepTransition</code> starts at this <code>ModelFigureElement</code>.
     * @param end the <code>StepTransition</code> ends at this <code>ModelFigureElement</code>.
     * @param existsTransition if the transition exists then no new <code>TransitionFigure</code> is added.
     */
    public StepTransition createTransition(String name, ModelFigureElement start, ModelFigureElement end, boolean existsTransition) {
        //start und end koennen nur Chains sein, da Steps hier gar nicht erzeugt werden koennen!
        
        if (name == null) {
			incrementTransitionCounter();
            name = Resource.getString("DEPENDENCY")+"("+getTransitionCounter()+")";
        }
        
        StepTransition result = new StepTransition(app,thecase,name, this,start, end);
        
        boolean adding=result.addTransitionToCase();

		if ((adding)&&(!existsTransition))
	        return addStepTransition(result);
	
	    return null;
    }


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

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


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

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

    /**
     *Gets the name of the <code>MiningMartCase</code>.
     *@return returns the name of the <code>Case</Case>
     *@see edu.udo.cs.miningmart.m4.Case#getName()
     */
	public String getName(){
		return this.thecase.getName();
	}
    
        /**
         *Sets the name of the <code>MiningMartCase</code>.
         *It means it sets the name of the <code>Case</code>.
         *@see edu.udo.cs.miningmart.m4.Case#setName(String)
         */
    public void setName(String name){

		//TODO valider name fuer den case
		if ((thecase!=null)&&(name!=null)){
			this.thecase.setName(name);
			super.setName(name);
		}
		
		//do nothing more
		//because the name could only be set one time in initializing the object
    }

    /**
     *Gets the <code>Case</code>
     */
	public Case getTheCase(){
		return this.thecase;
	}

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

	/**
     * If the description of this <code>MiningMartCase</code> changed then set the documentation of the underlying <code>Case</code>.
	 * @see org.musoft.limo.model.ModelElement#primitiveAttributeChanged(ModelPrimitiveAttribute)
	 */
	public void primitiveAttributeChanged(ModelPrimitiveAttribute mpa) {
		super.primitiveAttributeChanged(mpa);
	}

	/**
     * 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();
	}

        /**
         * Dissolves the specified <code>MiningMartChain</code>.
         */
	public void dissolveMiningMartChain(MiningMartChain mchain) throws M4Exception{

		//I need all subelements
		Collection subelements=new LinkedList();
		for (int i=0;i<mchain.getChildCount();i++){
			ModelFigureElement child=mchain.getChild(i);
			if (child instanceof MiningMartChain){
				subelements.add(((MiningMartChain) child).getChain());
			}
			if (child instanceof MiningMartStep){
				subelements.add(((MiningMartStep) child).getStep());
			}
		}

		//now resolve and destroy the mchain
		app.getMiningMartCase().setDeleteInDatabase(false,true);

//		this.thecase.resolveSubChain(mchain.getChain());
		mchain.destroy();
		for (int i = 0; i < getListenerCount(); i++) {
			getListener(i).onRemoveChild(this,mchain);
		}

		app.getMiningMartCase().setDeleteInDatabase(true,true);

		//add the subelements
		Iterator iter=subelements.iterator();
		Object next;
		Chain subchain;
		Step substep;
		MiningMartChain submchain;
		MiningMartStep submstep;
		
		while(iter.hasNext()){
			next=iter.next();
			if (next instanceof Chain){
				subchain=(Chain) next;			

				submchain=this.createMiningMartChain(this,subchain,subchain.getPoint(),new Rectangle(35,35));	
				for (int i=0;i<getListenerCount();i++){
					this.getListener(i).onAddChild(submchain,this);			
				}
			}
		}
		
		this.organizeTransitions(true);
	}
	
	

	/* (non-Javadoc)
	 * @see org.musoft.limo.model.ModelElement#destroy()
	 */
	public void destroy() {
		cansetdirty=false;
		MiningMartChain mchain;
		for (int i=0;i<this.getChildCount();i++){
			mchain=(MiningMartChain) this.getChild(i);
			mchain.setDeleteInDatabase(false,true);
		}
		
		StepTransition trans;
		for (int i=0;i<this.getConnectionCount();i++){
			trans=(StepTransition) this.getConnection(i);
			trans.setDeleteInDatabase(false);
		}
		
		super.destroy();
		cansetdirty=true;
	}

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

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

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

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

 */
    
