/*
 * 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.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

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

/**
 * This class serves as the container to store a single or multiple
 * <code>Parameter</code>s in the parameter dictionary in class <code>Step</code>.
 * The aggregation of <code>Parameter</code>s by this class is according to the
 * operators access by name, where arrays of <code>Parameter</code> objects and
 * optional parameters are possible.
 * 
 * Please note, that the name is not stored in this object, but the object is
 * stored in the <code>ParamDict</code> dictionary with the parameter name used
 * by the operator as the key.
 * 
 * @author Martin Scholz
 * @version $Id: ParameterArray.java,v 1.4 2006/04/11 14:10:14 euler Exp $
 */
public class ParameterArray implements Serializable, edu.udo.cs.miningmart.m4.ParameterArray {

	// static final InterM4Communicator parArr2par = new InterM4ParameterArrayParameter();

	/** The type of the/all parameter(s). */
	private final short parameterType;
	
	/** The <code>Vector</code> of <code>Parameter</code>s. */
	private final Vector parametersV = new Vector();

	/**
	 * An array of the <code>ParameterObject</code>s contained in the <code>Parameter</code>s.
	 * If this field is set to <code>null</code>, then it has not yet been set by the active
	 * getter method. Instead of <code>null</code> an array of length 0 is a valid value.
	 */
	private ParameterObject[] parameterObjectArray;



	// ***** Constructors *****
	
	public ParameterArray(short parameterType) 
		throws ParameterError
	{
		// Throws a ParameterError, if the constant is out of bounds:
		Parameter.typeStringForTypeConst(parameterType);

		// Constant ok:
		this.parameterType = parameterType;	
	}
	
	public ParameterArray(String parameterType) throws ParameterError {
		// typeConstForTypeString throws a ParameterError, if the String is not valid:
		this.parameterType = Parameter.typeConstForTypeString(parameterType);		
	}

	// ***** 

	/**
	 * Extends the array of ParameterObjects by the specified Parameter.
	 * Note, that the type of this Parameter has to be the same or a subclass
	 * of this ParameterArray's type!
	 * 
	 * The <code>Parameter</code> will also have a reference to this object
	 * after it has been added by this method.
	 * 
	 * After each invokation the array of ParameterObjects is invalidated and
	 * the active getter of this field will set it anew.
	 * 
	 * @param par the <code>Parameter</code> to be added
	 */
	public void addParameter(edu.udo.cs.miningmart.m4.Parameter par) throws M4Exception {
		edu.udo.cs.miningmart.m4.ParameterObject parObj = null;
		if ((par == null) || (parObj = par.getTheParameterObject()) == null) {
			return; // nothing to do for empty parameters
		}

		Class thisParClass = Parameter.getClassForParameterType(this.getParameterType());
		if (thisParClass.isInstance(parObj)){
			this.parameterObjectArray = null; // Invalidates the pre-computed array.
			// changed code:
			this.parametersV.add(par);
			// parArr2par.add(this, (Parameter) par); // Add the parameter (does all the work)!
		}
		else { // Type mismatch!
			throw new ParameterError(
				"ParameterArray.addParameter:\n"
				+ "Tried to add an incompatible ParameterObject"
				+ "of type " + par.getParObjectType()
				+ " to an array of type " + this.getParameterTypeS()
				);
		}
	}

	/**
	 * Inverts the <code>addParameter(Parameter)</code> functionality.
	 * The object specified is removed from the internal list of embedded
	 * <code>Paramter</code>s. The reference of the <code>Parameter</code> to
	 * this object is also deleted.
	 * @param par the <code>Parameter</code> to be deleted
	 * @return <code>true</code> if the object could be deleted
	 */
	public boolean removeParameter(edu.udo.cs.miningmart.m4.Parameter par) throws M4Exception {
		// changed code (2 lines):
		// boolean ret = parArr2par.remove(this, (Parameter) par); // Tries to remove par from the collection.
		boolean ret = this.parametersV.remove(par);
		
		if (ret) { // If the removal succeeded (changed anything) ...
			this.parameterObjectArray = null; // ... invalidate the prepared array.
		}
		return ret;
	}

	/**
	 * @param  par a <code>Parameter</code>
	 * @return <code>true</code> if a <code>Parameter</code> with the same ID is
	 *         found in this <code>ParameterArray</code>
	 * */
	public boolean hasParameter(edu.udo.cs.miningmart.m4.Parameter par) throws M4Exception {
		return  ( par != null
		       && this.getParameters() != null
		       && this.getParameters().contains(par));
	}

	// ***** Getter and setter *****

	/**
	 * Gets the parameterType.
	 * @return Returns a short
	 */
	public short getParameterType() {
		return parameterType;
	}

	/**
	 * Gets the parameterType as the String constant used in class DB.
	 * @return Returns a String
	 */
	public String getParameterTypeS() {
		try {
			return Parameter.typeStringForTypeConst(this.getParameterType());
		}
		catch (M4Exception e) {
			// should never happen, validity of type has been checked before
			return null;
		}
	}

	/**
	 * @return the number of <code>Parameter</code>s this
	 * <code>ParameterArray</code> contains.
	 */
	public int size() {
		return this.getParameters().size();	
	}

	/**
	 * @return the <code>Collection</code> of embedded <code>Parameter</code>
	 * objects.
	 */	
	public Collection getParameters() {
		return this.parametersV;
	}

	/**
	 * Active getter of the <code>parameterObjectArray</code>.
	 * @return Returns a <code>ParameterObject[]</code>
	 */
	public edu.udo.cs.miningmart.m4.ParameterObject[] getParameterObjectArray() throws M4Exception
	{
		if (this.parameterObjectArray == null) {
			Class classForArray;
			try {		
				classForArray = Parameter.getClassForParameterType(this.getParameterType());
			}
			catch (M4Exception e) { // should never happen
				classForArray = ParameterObject.class;		
			}
			edu.udo.cs.miningmart.m4.ParameterObject[] parObjArr =
				(ParameterObject[]) Array.newInstance(classForArray, this.size());		

			Iterator it = this.getParameters().iterator();
			for (int i=0; it.hasNext(); i++) {
				Parameter par = (Parameter) it.next();
				if (par != null) {
					parObjArr[i] = par.getTheParameterObject();	
				}
			}
			this.parameterObjectArray = (ParameterObject[]) parObjArr;
		}
		return this.parameterObjectArray;
	}

}

/*
 * Historie
 * --------
 * 
 * $Log: ParameterArray.java,v $
 * Revision 1.4  2006/04/11 14:10:14  euler
 * Updated license text.
 *
 * Revision 1.3  2006/04/06 16:31:14  euler
 * Prepended license remark.
 *
 * Revision 1.2  2006/03/16 14:53:38  euler
 * *** empty log message ***
 *
 * Revision 1.1  2006/01/03 09:54:18  hakenjos
 * Initial version!
 *
 */
