/*
 * 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 java.util.Collection;

import edu.udo.cs.miningmart.compiler.CompilerAccess;
import edu.udo.cs.miningmart.compiler.CompilerAccessLogic;
import edu.udo.cs.miningmart.db.DB;
import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.m4.core.M4InterfaceImpl;
import edu.udo.cs.miningmart.m4.utils.Print;


/** 
 * This is the main interface object. This is the starting point for using the M4Interface.
 * 
 * @author Timm Euler, Martin Scholz
 * @version $Id: M4Interface.java,v 1.8 2006/04/11 14:10:12 euler Exp $
 */
abstract public class M4Interface {

  private static transient M4Interface instance  = new M4InterfaceImpl();

  protected static Case currentCase;
  protected static transient CompilerAccess currentCompilerAccess;
  
  public static transient Print print = Print.getGlobalPrintObject();

  /** Name of the system property setting the print verbosity of log outputs */
  public static final String SYSTEM_PROP_PRINT_VERBOSITY = "PRINT_VERBOSITY";

  /** Name of the system property specifying the path to the dbConfig file */
  public static final String SYSTEM_PROP_DB_CONFIG_PATH  = "DB_CONFIG_PATH";

  /**
   * Public constants that represent different schema matching algorithms
   */
  public static final String MATCHER_SIMPLE = "SimpleMatcher";
  public static final String MATCHER_SOUNDEX = "SoundexMatcher";
  public static final String MATCHER_EDITDISTANCE = "EditDistanceMatcher";
  public static final String MATCHER_NGRAM = "N-Gram-Matcher";
  
  /**
   * A public string array that declares the types of schema matchers that
   * are available. 
   */
  public static final String[] AVAILABLE_MATCHERS = {
  		MATCHER_SIMPLE
		, MATCHER_SOUNDEX
		, MATCHER_EDITDISTANCE
		, MATCHER_NGRAM         // add more here if available
  };
  
  /**
   * Creates an instance of the M4Interface class. This method needs to be called
   * before being able to use the M4Interface.
   * @return M4Interface the M4Interface that is created.
   */
  public static M4Interface getInstance() {
    return instance;
  }

  protected static void setInstance(M4Interface m4Instance) {
    instance = m4Instance;
  }

  /**
   * Creates a new Case. The name of the Case must be unique within the M4 Schema.
   * 
   * @param name The name of the Case that should be created.
   * @param setAsCurrentCase If this parameter is set to TRUE, the newly created
   * case is set as the current case, and can be retrieved using getCurrentCase().
   * Otherwise the only handle to the new case is the returned object.
   * 
   * @throws M4Exception
   * @return Case the Case that is created.
   */
  public abstract Case createCase(String name, boolean setAsCurrentCase) throws M4Exception;

  /** 
   * Creates a new Operator. The name of the Operator must be unique within the M4 Schema.
   * @param name The name of the Operator that should be created.
   * @throws CreateException when an error occurs during creation of the object.
   * @throws NameExistsException when the provided name already exists.
   * @return Operator the Operator that is created.
   */
  public abstract Operator createOperator(String name) throws M4Exception;

  /**
   * Find all Case names.
   * @return Collection of Case names.
   */
  public abstract Collection getAllCaseNames();
	
  /**
   * @return a Collection of Strings, namely the names of all tables
   * and views in the business data schema except those that were created
   * by the compiler (ie, are listed in the trash table).
   */
  public abstract Collection getNamesOfBusinessTablesAndViews() throws M4Exception;
  
  /**
   * Checks wether a table in the business schema with this name exists.
   * @param name the name of the table
   * @return true if the table exists, false otherwise
   */
  public abstract boolean isBusinessTable(String name) throws M4Exception;

  /**
   * Checks wether a view in the business schema with this name exists.
   * @param name the name of the view
   * @return true if the view exists, false otherwise
   */  
  public abstract boolean isBusinessView(String name) throws M4Exception;

  /**
   * Checks wether a case with this name exists.
   * @return true if the case exists, false otherwise.
   */
  public abstract boolean existsCase(String name);

  public abstract DB getM4db();
  
  public abstract OperatorGroup getOperatorGroup();
  
  /**
   * Returns an Operator that may be changed. As Operators are much less
   * frequently added or changed by users than Cases a findOperatorForUpdate()
   * method is not provided here.
   * @param name The name of the Operator that should be retrieved.
   * @return Operator the Operator that is found or null if it is not found.
   */
  public abstract Operator findOperator(String name);

  /**
   * Find all Operator names.
   * @return Collection of Operator names.
   */
  public abstract Collection getAllOperatorNames();

  /**
   * Returns a Case for read-only access. Read-only access administration is
   * done in a database table; it is not enforced by the M4Interface however!
   * This means it is left to the programmer to disallow changes.
   * Many users are allowed to read a Case as long as nobody else is writing
   * to the Case. No writer to a Case is allowed if there is at least one reader.
   *
   * @param name The name of the Case that should be retrieved.
   * @param setAsCurrent Boolean indicating retrieved case should be set as current.
   *
   * The current Case is used as the context for M4Interface methods that depend
   * on the Case. Normally this value should be set to true. Note that the
   * current Case context can also be set using the <code>setCurrentCase</code> method.
   *
   * @throws CaseLockedException when a Case is already locked for reading.
   * @return Case the Case that is found or null if it is not found.
   */
  public abstract Case findCaseForReadOnlyAccess(String name, boolean setAsCurrent)
  throws CaseLockedException;

  /**
   * Returns a Case and locks it so it may be modified.
   * Many users are allowed to read a Case as long as nobody else is writing
   * to the Case. No writer to a Case is allowed if there is at least one reader.
   *
   * @param name The name of the Case that should be retrieved.
   * @param setAsCurrent If the retrieved Case should be set as the current Case
   * context for M4Interface methods that depend on the Case. Normally this
   * value should be set to true. Note that the current Case context can also
   * be set using the <code>setCurrentCase</code> method.
   *
   * @throws CaseLockedException when a Case is already locked for writing.
   * @return Case the Case that is found or null if it is not found.
   */
  public abstract Case findCaseForUpdate(String name, boolean setAsCurrent)
  throws CaseLockedException;

	/** Check if the M4Access for the specified <code>Case</code> can be removed.*/
  public abstract boolean canRemoveM4Access(String caseName);

	/** Check if case can be locked for reading. */
  public abstract boolean isCaseLockedForReading(String name);

	/** Check if case can be locked for writing. */
  public abstract boolean isCaseLockedForWriting(String name);

  /**
   * Release a Case for access. The Case is stored to the DB.
   * 
   * @param name the name of the case to be released
   */
  public abstract void releaseCase(String name);
  
  /**
   * Release a Case from access lock, but do not store it to the DB 
   * even if it has been changed.
   * 
   * @param name the name of the case to be released
   */
  public abstract void releaseCaseWithoutStoring(String name);

  /**
   * Returns the Case that is used as the context for methods of the M4Interface
   * that are Case dependent. Normally the returned Case is the Case currently
   * accessed by the user.
   *
   * @return the currently accessed Case.
   */
  public static Case getCurrentCase() {
    return currentCase;
  }

  /**
   * Some methods of the M4Interface are Case dependend. By setting the
   * current Case the context for these methods to work in is set. The current
   * Case can also be set using the <code>getCaseForReadOnly</code> or
   * <code>getCaseForUpdate</code> methods.
   *
   * @param currentCase The Case to be set as the current one.
   */
  public static void setCurrentCase(Case currentCase) {
    M4Interface.currentCase = currentCase;
    print.doPrint(Print.M4_OBJECT, "Current case set to:  " + currentCase.getName());
  }

  /**
   * Makes the M4Interface forget its current case.
   */
  public static void removeCurrentCase() {
  	M4Interface.currentCase = null;
  }
  
  /**
   * Some methods of the M4Interface are CompilerAccess dependend. By setting the
   * current CompilerAccess the context for these methods to work in is set.
   *
   * @param currentCompilerAccess The CompilerAccess to be set as the current one.
   */
  public static void setCurrentCompilerAccess(CompilerAccess currentCompilerAccess)
  {
      M4Interface.currentCompilerAccess = currentCompilerAccess;
      print.doPrint(Print.MIN, "Current CompilerAccess set!");
  }

  /**
   * Returns the CompilerAccess that is used as the context for methods of the M4Interface
   * that are CompilerAccess dependent. Normally the returned CompilerAccess is the CompilerAccess currently
   * accessed by the user.
   *
   * @return the currently accessed CompilerAccess.
   */
  public static CompilerAccess getCurrentCompilerAccess() {
  	if (currentCompilerAccess == null) {
  		try {  			
	  		currentCompilerAccess = new CompilerAccessLogic(getInstance().getM4db(), print);
  		}
  		catch (Exception e) {}
  	}
    return currentCompilerAccess;
  }

  /**
   * Connects the given concept with one of the Db Objects (tables or views)
   * whose names are given in the second parameter. If the given concept already has
   * a connection to a Columnset, that connection is removed. A new Columnset
   * is created that represents one of the tables or views, or a join result (see below), 
   * and is connected to the concept given in the first parameter. The Db Object is 
   * chosen by schema matching. The third parameter determines which matcher is used; 
   * its value must be one of the public constants defined in this class. The returned
   * Collection will be empty in many cases. However, if it contains two columnsets,
   * this means that these two columnsets were joined and the result matched the given
   * Concept better than any of the single tables/views. In this case the given
   * Concept is connected to a Columnset that represents a view of the join result.
   * 
   * @param theConcept Concept to be connected
   * @param namesOfDbObjects Names of business schema tables and views among which
   * to select the best-matching one
   * @param matcher The type of schema matching algorithm to be used (must be one of 
   * the corresponding public constants of this class)
   * @return A Collection that is NULL iff the given Concept was matched directly to 
   * one of the given Db Objects, and that contains two Columnsets iff two of the 
   * given Db Objects were joined (following existing foreign key relationships in the
   * database schema) and the resulting view matched the given concept better than any
   * single table/view.
   * @throws M4Exception
   */
  public abstract Collection findConnection( Concept theConcept, 
  										   Collection namesOfDbObjects, 
										   String matcher) 
  throws M4Exception;
  
/** This exception is thrown when a Case is locked.*/
  public class CaseLockedException extends Exception {
  	
    /** Constructs an Exception without a message. */
    public CaseLockedException() {
      super();
    }

    /**
     * Constructs an Exception with a detailed message.
     * @param Message The message associated with the exception.
     */
    public CaseLockedException(String message) {
      super(message);
    }
  }

}
/*
 * Historie
 * --------
 * 
 * $Log: M4Interface.java,v $
 * Revision 1.8  2006/04/11 14:10:12  euler
 * Updated license text.
 *
 * Revision 1.7  2006/04/06 16:31:11  euler
 * Prepended license remark.
 *
 * Revision 1.6  2006/03/23 11:13:46  euler
 * Improved exception handling.
 *
 * Revision 1.5  2006/03/22 13:08:52  euler
 * *** empty log message ***
 *
 * Revision 1.4  2006/03/19 17:00:38  scholz
 * refactoring
 *
 * Revision 1.3  2006/01/27 17:27:18  euler
 * Bugfix
 *
 * Revision 1.2  2006/01/03 14:51:34  euler
 * Two new schema matchers.
 *
 * Revision 1.1  2006/01/03 09:54:24  hakenjos
 * Initial version!
 *
 */
