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

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

import edu.udo.cs.miningmart.db.DB;
import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.m4.utils.InterM4GraphicalObjectToCoordinates;
import edu.udo.cs.miningmart.m4.utils.InterM4ObjectToObject;
import edu.udo.cs.miningmart.m4.utils.Print;
import edu.udo.cs.miningmart.m4.utils.XmlInfo;

/**
 * This is the abstract superclass of all M4 objects that have graphical
 * information associated with them. It handles the access to the HCI_COORD_T
 * table.
 * 
 * @author Timm Euler
 * @version $Id: GraphicalM4Object.java,v 1.6 2006/04/11 14:10:14 euler Exp $
 */
public abstract class GraphicalM4Object extends M4Data implements XmlInfo, edu.udo.cs.miningmart.m4.GraphicalM4Object {
	
	private Coordinates myCoordinates;
	private boolean coordinatesLoaded = false;
	
	// ***** Inter M4 communication classes *****
	public static InterM4ObjectToObject graph2coord = new InterM4GraphicalObjectToCoordinates();
	
	/**
	 * Constructor for GraphicalM4Object.
	 * @param m4Db
	 */
	public GraphicalM4Object(DB m4Db) 
	{	super(m4Db);	}

	/** Has to be implemented to indicate which classes have coordinates. */
	protected abstract boolean hasCoordinates();

	/**
	 * @see edu.udo.cs.miningmart.m4.core.M4Object#print()
	 */
	public void print()	{
		Coordinates cc = null;
		try {
			if (this.hasCoordinates()) {
				cc = this.getCoordinates();
			}
		}
		catch (M4Exception m4e)
		{   this.doPrint(m4e); 
			return;
		}
		
		if (cc == null)	{
			this.doPrint(Print.M4_OBJECT, "M4 Object '" + this.getName() + "' has no graphical info stored with it.");
		}
		else {
			Point p = null;
			try {
				p = cc.getLocation();
			}
			catch (M4Exception m4e) {
				this.doPrint(Print.MAX, "Error in print method of GraphicalM4Object: " + m4e.getMessage());
			}
			this.doPrint(Print.M4_OBJECT, "Graphical info for M4 object '" + this.getName() +
				                              "': X: " + p.x + ", Y: " + p.y + ".");
		}
	}

	public void primitiveSetCoordinates(Coordinates cc) {
		this.setDirty();
		this.myCoordinates = cc;
	}
	
	/**
	 * In the current implementation the <code>Coordinates</code> object
	 * refers to its <code>GraphicalM4Object</code>'s ID and name, so we have to make
	 * sure that we rewrite the coordinates each time the name is changed!
	 * Thus this method extends the super-method.
	 */
	public void setName(String name) {
		super.setName(name);
		try {
			this.setCoordinatesDirty(); // makes sure the coordinates entry is rewritten
		}
		catch (M4Exception m4e) {
			System.err.println("WARNING: GraphicalM4Object.setName(): could not load coordinates of M4 object '" + name + "'!");
		}
	}

	/**
	 * This method should only be used to indicate
	 * that the coordinates need to be updated in the table <code>HCI_COORD_T</code>.
	 */
	public void setCoordinatesDirty() throws M4Exception {
		if (this.hasCoordinates()) {
			Coordinates cc = this.getCoordinates();
			if (cc != null) {
				cc.setDirty();
			}
		}
	}

	/**
	 * Overwrites the method in M4Object to store the graphical info
	 * associated with this GraphicalM4Object.
	 */
	protected void storeLocal() throws M4Exception {
		if (this.hasCoordinates()) {
			Coordinates cc = this.getCoordinates();
			if (cc != null && cc.isDirty()) {
				cc.store();
			}
		}
	}

	/**
	 * Overwrites the method in M4Object to delete the graphical info
	 * associated with this GraphicalM4Object.
	 */
	protected void deleteLocal() throws M4Exception	{
		if (this.hasCoordinates()) {
			Coordinates cc = this.getCoordinates();
			if (cc != null && cc.isDirty()) {
				cc.delete();
			}
		}
	}

	/**
	 * Overwrites the superclass method because the coordinates that
	 * belong to this object must be deleted, too.
	 * 
	 * @throws M4Exception
	 */
	public void deleteSoon() throws M4Exception {
		if (this.hasCoordinates()) {
			Coordinates cc = this.getCoordinates();
			if (cc != null) cc.delete();
		}
		graph2coord.setReciprocalReferences(this, null);		
		super.deleteSoon();
	}
	
	public void setPoint(Point location) throws M4Exception {
		this.getCoordinates().setLocation(location);
	}
	
	public Point getPoint() throws M4Exception {
		return this.getCoordinates().getLocation();
	}
	
	/**
	 * Active getter for this objects <code>Coordinates</code>
	 * 
	 * @return the <code>Coordinates</code>, or <code>null</code>
	 *         if <code>this</code> object does not have coordinates.
	 */
	public Coordinates getCoordinates() throws M4Exception {
		if ( ! this.hasCoordinates()) {
			return null;
		}

		if (!this.coordinatesLoaded) {
			
			// only load coordinates from DB if this is not a new object:
			Coordinates cc = new Coordinates(this.getM4Db());			
			if ( ! this.isNew()) {
				cc.primitiveSetMyM4Object(this); // enables loading with the right id
				cc.readFromDb();             // this is a local method in Coordinates
			}
			this.coordinatesLoaded = true;
			graph2coord.setReciprocalReferences(this, cc);
		}

		return this.myCoordinates;	
	}	
	
	/** @see M4Data#getDependentObjects */
	public Collection getDependentObjects() throws M4Exception {
		Collection ret = super.getDependentObjects();
		if (this.hasCoordinates()) {   
			ret.add(this.getCoordinates());   
		}
		return ret;
	}
}
/*
 * Historie
 * --------
 * 
 * $Log: GraphicalM4Object.java,v $
 * Revision 1.6  2006/04/11 14:10:14  euler
 * Updated license text.
 *
 * Revision 1.5  2006/04/06 16:31:13  euler
 * Prepended license remark.
 *
 * Revision 1.4  2006/01/20 16:23:10  euler
 * Bugfix
 *
 * Revision 1.3  2006/01/12 13:20:10  euler
 * Bugfix
 *
 * Revision 1.2  2006/01/12 11:33:11  euler
 * Changed the way coordinates are stored completely.
 *
 * Revision 1.1  2006/01/03 09:54:17  hakenjos
 * Initial version!
 *
 */
