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

import edu.udo.cs.miningmart.exception.M4Exception;

import java.util.Collection;
import java.util.Map;

/**
 * @author Timm Euler, Daniel Hakenjos
 * @version $Id: Concept.java,v 1.7 2006/04/11 14:10:13 euler Exp $
 */
public interface Concept extends ParameterObject {

	  /* Constants */

	  /**
	   * Concepts of type BASE can be used to define a Conceptual Model.
	   */
	  public static final String TYPE_BASE = "BASE";

	  /**
	   * Concepts of type DB are based directly on a table. They are not the result of some operator.
	   */
	  public static final String TYPE_DB = "DB";

	  /**
	   * Concepts that are the result of an operator are of type MINING.
	   */
	  public static final String TYPE_MINING = "MINING";
	  
	//methods from core
	
	// ***** Getter and setter methods ****
	
	/**
	 * Setter method for the type of this concept.
	 * 
	 * @param t the new type (one of "DB", "Base", "Mining")
	 */
    public void setType(String t) throws M4Exception;

	/**
	 * Getter method.
	 * 
	 * @return the type of this concept
	 */
    public String getType();

    /**
     * Return the Parameter object that represents this
     * concept as an output concept parameter (of a certain step).
     *  
     * @return a Parameter object
     */
    public Parameter getParameterWhereThisIsOutputConcept() throws M4Exception;

    /**
     * Returns all Steps in the Case that use this Concept as
     * an input concept.
     * 
     * @return a Collection of Steps
     */
    public Collection getStepsWhereThisIsInputConcept() throws M4Exception; 

    /**
     * Returns the Step in the Case where this Concept is created as
     * the output concept.
     * 
     * @return a Step
     */
    public Step getStepWhereThisIsOutputConcept() throws M4Exception;

	public EstimatedStatistics getEstimatedStatistics()	throws M4Exception;
	
	// ***** Handling of Columnsets *****

	/**
	 * Add a columnset to this concept's columnsets.
	 * 
	 * @param cs the additional columnset
	 */
	public void addColumnSet(Columnset cs) throws M4Exception;

	/**
	 * Remove a Columnset from this concept.
	 * 
	 * @param cs the Columnset
	 */
	public boolean removeColumnset(Columnset cs) throws M4Exception;

	/**
	 * @param cs a <code>Columnset</code>
	 * @return <code>true</code> if a <code>Columnset</code> with the same ID is already
	 * linked to this <code>Concept</code>
	 * */
	public boolean hasColumnset(Columnset cs) throws M4Exception;

	/**
	 * Set the columnsets of this concept.
	 * 
	 * @param theColumnsets An array with the new columnsets.
	 */
    public void setColumnSets(Collection theColumnsets) throws M4Exception;

	/**
	 * @return the columnsets that belong to this concept
	 */
    public Collection getColumnSets() throws M4Exception;        
	
    /**
     * This method returns a suffix for the current <i>Columnset</i>.
     * See the method "getCurrentColumnset()".
     * It is ment as a helper method for generating distinct table
     * names, when having an input concept with multiple column sets.
     *
     * @return the index of the current <i>Columnset</i> as a <i>String</i>
     *         or the empty String if the concept has only one <i>Columnset</i>
     */
	public String getCurrentSuffix();

    /**
     * This method is invoked to initialize the support for concepts
     * referring to multiple column sets (multi steps). The set of
     * column sets is stored internally and a pointer to a "current"
     * column set is maintained, in order to ease the handling by
     * operators.
     * 
     * @param columnsets An array of column sets this concept refers to.
     */
    public void initMultiStepSupport(Collection columnsets);

	/**
	 * This method returns a specific columnset: in a compilation where
	 * multistep operators have occured, there can be more than one columnset
	 * for an input concept. The compiler then chooses one columnset for the step, 
	 * compiles the step with that columnset, then chooses another one, compiles
	 * again and so on. This method returns the currently chosen columnset.
	 * 
	 * @return the current columnset as selected by the compiler
	 */
	public Columnset getCurrentColumnSet() throws M4Exception;

    /** 
     * In case of multi step support this method resets the internal
     * pointer to the current column set to the first one. 
     */
    public void resetColumnSets();

    /** 
     * In case of multi step support this method answers the question
     * if <i>getNextColumnSet()</i> will succeed.
     * 
     * @return <i>true</i> if and only if there is at least one more
     *         column set after the current one.
    */
    public boolean hasNextColumnSet() throws M4Exception;

    /** 
     * In case of multi step support this method returns the next
     * column set after the current one and increases the internal
     * pointer accordingly. If this method is called when
     * <i>hasNextColumnSet()</i> returns <i>false</i> then an
     * exception is thrown. 
     * 
     * @return the next columnset
     */
    public Columnset getNextColumnSet() throws M4Exception;
	

	// ***** Handling cases *****

	/**
	 * Getter method.
	 * 
	 * @return the <code>Case</code> this <code>Concept</code> belongs to
	 */
	public Case getTheCase() throws M4Exception;

	/**
	 * Sets the case for this concept
	 * 
	 * @param ca the <code>Case</code> this <code>Concept</code> belongs to
	 */
	public void setTheCase(Case ca) throws M4Exception;


	// ***** Handling features *****

	/**
	 * Add a Feature (a BaseAttribute or a MultiColumnFeature) to this concept.
	 * 
	 * @param f the new Feature
	 */
	public void addFeature(Feature f) throws M4Exception;

	/**
	 * Get a specific Feature by name.
	 * 
	 * @param name the name
	 * @return the Feature with that name
	 */
    public Feature getFeature(String name) throws M4Exception;

	/**
	 * Get a specific Feature by index.
	 * 
	 * @param index the index
	 * @return the Feature with that name
	 */
    public Feature getFeature(int index) throws M4Exception;

	/**
	 * Returns a String with comma-separated names of the Features
	 * of this Concept.
	 * 
	 * @return a String
	 * @throws M4Exception
	 */
	public String getFeatureNames() throws M4Exception;
	
	/**
	 * Remove a Feature (a BaseAttribute or a MultiColumnFeature) from this concept.
	 * 
	 * @param f the Feature
	 */
	public boolean removeFeature(Feature feature) throws M4Exception;

	/**
	 * Remove a Feature (a BaseAttribute or a MultiColumnFeature) with
	 * the given name from this concept.
	 * 
	 * @param name the Name
	 */
	public boolean removeFeatureByName(String name) throws M4Exception;
	
	/**
	 * Remove all features from this concept.
	 * 
	 * @throws M4Exception
	 */
	public void removeAllFeatures() throws M4Exception;

	/**
	 * Set all Features into this concept.
	 * 
	 * @param fs A Collection of Feature objects
	 */
    public void setFeatures(Collection theFeatures) throws M4Exception;

	/**
	 * @return All Features of this concept.
	 */
	public Collection getFeatures() throws M4Exception;

	/**
	 * Returns the number of features that this Concept has.
	 * 
	 * @return the number of features as an int
	 */
	public int getNumberOfFeatures() throws M4Exception;
	
	/**
	 * @param f a <code>Feature</code>
	 * @return <code>true</code> if a <code>Feature</code> with the same ID is already
	 * linked to this <code>Concept</code>
	 * */
	public boolean hasFeature(Feature f) throws M4Exception;

	/**
	 * When this Concept has changed its Features, depending concepts
	 * of later steps can be adapted with this method. The method is not
	 * called automatically from methods addFeature or removeFeature because
	 * those methods are used too frequently during normal M4 Java administration.
	 */
	public void propagateChangesToDependingConcepts() throws M4Exception;
	
	
	// ***** Handling relationships *****

	/**
	 * Returns a Collection of Relations in which this concept
	 * is the FromConcept.
	 * 
	 * @return Collection
	 */
	public Collection getTheFromRelationships() throws M4Exception;
	
	/**
	 * Returns a Collection of Relations in which this concept
	 * is the ToConcept.
	 * 
	 * @return Collection
	 */
	public Collection getTheToRelationships() throws M4Exception;

	/**
	 * Returns a Relation with this concept as the ToConcept and the
	 * given concept as the FromConcept, if such a Relation exists, and NULL otherwise.
	 * 
	 * @param fromConcept the given FromConcept
	 * @return a Relation between this concept and the FromConcept or NULL
	 * @throws M4Exception
	 */
	public Relation getRelationshipFromConcept(Concept fromConcept) throws M4Exception;
	
	/**
	 * Returns a Relation with this concept as the FromConcept and the
	 * given concept as the ToConcept, if such a Relation exists, and NULL otherwise.
	 * 
	 * @param toConcept the given toConcept
	 * @return a Relation between this concept and the ToConcept or NULL
	 * @throws M4Exception
	 */
	public Relation getRelationshipToConcept (Concept toConcept) throws M4Exception;
	
	// ***** Handling concept inheritance *****

	/**
	 * Returns the Collection of ConceptInheritance objects with this Concept
	 * as a Super-Concept
	 * 
	 * @return <code>Collection</code> of <code>ConceptInheritance</code>
	 */
	public Collection getConceptInheritanceAsSuperConcept() throws M4Exception;

	/**
	 * Returns the Collection of ConceptInheritance objects with this Concept
	 * as a Sub-Concept
	 * 
	 * @return <code>Collection</code> of <code>ConceptInheritance</code>
	 */
	public Collection getConceptInheritanceAsSubConcept() throws M4Exception;

	/**
	 * This method gets the set of all super concepts
	 * 
	 * @return a <code>Collection</code> of <code>Concept</code>s
	 */
	public Collection getSuperConcepts() throws M4Exception;

	/**
	 * This method gets the set of all sub concepts
	 * 
	 * @return a <code>Collection</code> of <code>Concept</code>s
	 */
	public Collection getSubConcepts() throws M4Exception;

	/**
	 * Usually there is only one Super Concept.
	 *
	 * @return the first Super Concept or <code>null</code>
	 */
	public Concept getTheSuperConcept() throws M4Exception;

	/**
	 * Adds a Sub Concept.
	 * 
	 * @param newSubConcept The Sub Concept to add
	 */
	public void addSubConcept(Concept newSubConcept) throws M4Exception;

	/**
	 * Adds a Super Concept and check for cycles in the inheritance graph.
	 * 
	 * @param newSuperConcept The Super Concept to add
	 */
	public void addSuperConcept(Concept newSuperConcept) throws M4Exception;

	/**
	 * Sets the Super Concept to be the only Super Concept of this Concept
	 * @param newSuperConcept The Super Concept to set
	 */
	public void setTheSuperConcept(Concept newSuperConcept) throws M4Exception;

	/**
	 * Removes a Sub Concept.
	 * 
	 * @param conInh The <code>Concept</code> object to remove
	 */
	public void removeSubConcept(Concept subCon) throws M4Exception;

	/**
	 * Removes a Super Concept.
	 * 
	 * @param conInh The <code>Concept</code> object to remove
	 */
	public void removeSuperConcept(Concept superCon) throws M4Exception;

	/**
	 * Checks wether the given concept has the same features as this one
	 * (correspondence of features is by name). 
	 */
	public boolean isValidSubconcept(Concept potentialSubConcept) throws M4Exception;

	// ***** Handling projections *****

	/**
	 * Create a new Projection from this concept to the given concept.
	 * The new Projection is returned; in it, this concept is the from 
	 * concept and the given concept is the to concept.
	 */
	public Projection createProjectionToConcept(Concept toConcept, String nameOfProjection) 
	throws M4Exception;
	
	/**
	 * Adds a To-Projection.
	 * 
	 * @param projection The Projection to add with this Concept as the To-Concept
	 */
	public void addToProjection(Projection projection) throws M4Exception;

	/**
	 * Removes a To-Projection.
	 * 
	 * @param projection The Projection (with this Concept as the To-Concept) to be removed
	 * @return <code>true</code> if the object was found and removed from the
	 * 		   <code>Collection</code>
	 */
	public boolean removeToProjection(Projection projection) throws M4Exception;

	/**
	 * Adds a From-Projection.
	 * 
	 * @param projection The Projection to add with this Concept as the From-Concept
	 * @return <code>true</code> if the object was found and removed from the
	 * 		   <code>Collection</code>
	 */
	public void addFromProjection(Projection projection) throws M4Exception;
	
	/**
	 * Removes a From-Projection.
	 * 
	 * @param projection The Projection (with this Concept as the From-Concept) to be removed
	 */
	public boolean removeFromProjection(Projection projection) throws M4Exception;

	/**
	 * Sets the From-Projection as the only From-Projection of this
	 * <code>Concept</code>
	 * @param newFromProjection The From-Projection to set
	 */
	public void setTheFromProjection(Concept newFromProjection)
		throws M4Exception;

	/**
	 * @return the (first) <code>Concept</code> which this <code>Concept</code>
	 * is a <code>Projection</code> from.
	 */
	public Concept getTheFromProjection() throws M4Exception;

	/**
	 * Returns the From-Projections.
	 * 
	 * @return <code>Collection</code> of <code>Projection</code> objects
	 */
	public Collection getProjectionsAsFromConcept() throws M4Exception;

	/**
	 * Returns the To-Projections.
	 * 
	 * @return <code>Collection</code> of <code>Projection</code> objects
	 */
	public Collection getProjectionsAsToConcept() throws M4Exception;
	
	
	//methods from old interface


  /* Attribute methods */

  // String getSubConceptRestriction();// TE: probably never needed

  // void setSubConceptRestriction(String subConceptRestriction);// TE: probably never needed

  /**
   * This method returns information about the relational validity of the object. The relational validity is managed at the
   * database level by triggers. The returned value denotes if the object is valid on the relational level or not.
   */
  boolean isRelationallyValid() throws M4Exception;

  /**
   * Creates a BaseAttribute that is connected to this Concept. The name of the BaseAttribute must be unique within the Concept.
   * The datatype should also be provided or will be set to BASE if omitted. Use
   * the predefined constants to set the datatype.
   * @throws M4Exception when an error occurs during creation of the object.
   */
  BaseAttribute createBaseAttribute(String name, String datatype, String attributeType) throws M4Exception;

  /**
   * Creates a new ColumnSet that is connected to this Concept. The name
   * must be unique within this Concept. The schema and type are also required.
   * Use the predefined types for the type parameter.
   *
   * @throws M4Exception when an error occurs during creation of the object.
   */
  Columnset createColumnset(String name, String schema, String type) throws M4Exception;
  
  Columnset getColumnset(String colunsetname) throws M4Exception;
  
  void removeAllColumnsets() throws M4Exception;
  
  Concept copy(Case newCase) throws M4Exception;

  BaseAttribute getBaseAttribute(String name) throws M4Exception;
  
  /**
   * Returns the BaseAttribute of this Concept that is connected
   * to the given Column, if it exists. Otherwise null is returned.
   * 
   * @param column the Column
   * @return a BaseAttribute of this Concept, or null
   * @throws M4Exception
   */
  BaseAttribute getBaseAttribute(Column column) throws M4Exception;
  
  /**
   * Returns ALL BaseAttributes of this Concept, including those
   * that directly belong to a MultiColumnFeature that belongs to
   * this Concept, but do not belong directly to this concept.
   */
  public Collection getAllBaseAttributes() throws M4Exception;

  /**
   * Returns ONLY those BaseAttributes of this Concept that do not
   * belong to a MultiColumnFeature.
   */
  public Collection getBaseAttribsNotInMcf() throws M4Exception;

  /**
   * This method connects this Concept to a DB object, either a table or view,
   * by creating a Columnset and Columns for the DB object and connecting this
   * Concept's BaseAttributes to the Columns according to the information in
   * the given Map. If this Concept is not of type 'DB', the method will do 
   * nothing.
   * 
   * @param nameOfDbObject name of a table or view in the business data schema
   * @param isTable TRUE iff 'nameOfDbObject' refers to a table (otherwise a view
   * is assumed)
   * @param columnNamesForAttribs a Map that maps every BaseAttribute 
   * of this Concept to a String. The String is the name of the Column that this 
   * BaseAttribute will be connected to.
   * @throws M4Exception
   */
  public void connect(String nameOfDbObject, boolean isTable, Map columnNamesForAttribs) throws M4Exception;

  /**
   * Removes the connection of this Concept to its current Columnset,
   * but ONLY if this Concept is of type 'DB'.
   * 
   * @throws M4Exception
   */
  public void removeConnection() throws M4Exception;

  /**
   * Creates a PrimaryKey for the Columnset of this Concept.
   * 
   * @param keyAttribs a Collection of BaseAttributes, each of which is part of the PrimaryKey
   * @return the new PrimaryKey
   * @throws M4Exception
   */
  public PrimaryKey createPrimaryKey(Collection keyAttribs) throws M4Exception;
  
  /**
   * Returns the PrimaryKey of the Columnset of this Concept.
   * @return
   * @throws M4Exception
   */
  public PrimaryKey getPrimaryKey() throws M4Exception;
  
  /**
   * Creates a new MultiColumnFeature that is connected to this Concept. The name must be unique within this Concept.
   * @throws M4Exception when an error occurs during creation of the object.
   */
  MultiColumnFeature createMultiColumnFeature(String name) throws M4Exception;

  public Collection getAllMultiColumnFeatures() throws M4Exception;

  /**
   * Creates a new Relationship to which this Concept is connected as FromConcept.
   * The name of the Relationship in combination with the name of the ToConcept must be unique for the Concept.
   * This allows a Concept to have Relationships to other Concepts with the same name.
   * NOTE:
   * A new Relationship should always be created as a FromConceptRelationship;
   * no method is provided to create a ToConceptRelationship.
   * @param name the name for the relationship
   * @param toConcept the Concept the relationship should point to
   * @throws M4Exception when an error occurs during creation of the object.
   */
  Relation createFromConceptRelation(String name, Concept toConcept) throws M4Exception;
}
/*
 * Historie
 * --------
 * 
 * $Log: Concept.java,v $
 * Revision 1.7  2006/04/11 14:10:13  euler
 * Updated license text.
 *
 * Revision 1.6  2006/04/06 16:31:12  euler
 * Prepended license remark.
 *
 * Revision 1.5  2006/03/20 16:44:21  euler
 * Bugfixes
 *
 * Revision 1.4  2006/03/16 14:53:38  euler
 * *** empty log message ***
 *
 * Revision 1.3  2006/01/18 16:58:58  euler
 * Added some basic estimations of statistics.
 * Will need improvements.
 *
 * Revision 1.2  2006/01/12 08:46:10  euler
 * Added method getBaseAttribute(Column)
 *
 * Revision 1.1  2006/01/03 09:54:24  hakenjos
 * Initial version!
 *
 */
