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

import java.util.ArrayList;
import java.util.StringTokenizer;

import edu.udo.cs.miningmart.m4.Column;
import edu.udo.cs.miningmart.m4.Value;
import edu.udo.cs.miningmart.m4.utils.Print;
import edu.udo.cs.miningmart.exception.M4CompilerError;

/**
 * <p>M4 Compiler</p>
 * <p>Copyright: Copyright (c) 2002</p>
 * <p>Company: University Dortmund</p>
 * 
 * @author Felix Koschin
 * @version $Id: EquifrequentDiscretizationGivenCardinality.java,v 1.6 2006/04/11 14:10:18 euler Exp $
 */
public class EquifrequentDiscretizationGivenCardinality extends Discretization
{

	/* Parameters */
	public Value getCardinality() throws M4CompilerError
	{
		return (Value) this.getSingleParameter("Cardinality", this.getCurrentLoopNumber());
	}

	public Value getCardinalityType() throws M4CompilerError
	{
		return (Value) this.getSingleParameter("CardinalityType", this.getCurrentLoopNumber());
	}

	public Value getClosedTo() throws M4CompilerError
	{
		return (Value) this.getSingleParameter("ClosedTo", this.getCurrentLoopNumber());
	}

	/* Basic method */
	public double[] generateCutPoints(Column theTargetAttributeColumn) throws M4CompilerError
	{
		int i;
		long count, IntCardA, sum, MaxDiff;
		// int n[];
		long[] cnt;
		double[] val;
		ArrayList cutPoints = new ArrayList();
		double[] cp;
		// String s;
		// double min, max;

		/* SELECT TA, Count(TA) FROM ... */
		String[] elements = this.getM4Db().getCountOfElements(theTargetAttributeColumn);

		cnt = new long[elements.length + 1];
		val = new double[elements.length + 1];
		sum = 0;

		doPrint(Print.OPERATOR,"EquifrequentDiscretizationGivenCardinality:" );

		/* Parse string returned from getCountOfElements ("count,value")*/
		for(i = 0; i < elements.length; i++){
			StringTokenizer t = new StringTokenizer(elements[i], ",");
			cnt[i] = Long.parseLong(t.nextToken());
			val[i] = Double.parseDouble(t.nextToken());
			sum = sum + cnt[i];

		}

		/* Temporary absurdly value for terminating */
		cnt[elements.length] = 0;
		val[elements.length] = val[elements.length - 1] + .05;

		/* Calculate min and max 
		 * - but they are not used! T.E.
		s = theTargetAttributeColumn.getMinValue();
		if (s == null)
			min = Double.parseDouble(this.getM4Db().readOrComputeMinimum(theTargetAttributeColumn));
		else
			min = Double.parseDouble(s);
		s = theTargetAttributeColumn.getMaxValue();
		if (s == null)
			max = Double.parseDouble(this.getM4Db().readOrComputeMaximum(theTargetAttributeColumn));
		else
			max = Double.parseDouble(s);
		*/

		/* if neccessary, convert RELATIVE cardinality to ABSOLUTE */
		if (getCardinalityType().getValue().equalsIgnoreCase("absolute"))
			IntCardA = Long.parseLong(getCardinality().getValue());
		else
			IntCardA = Math.round(sum * Double.parseDouble(getCardinality().getValue()));

		/* Create cut points*/
		i = 0;
		MaxDiff = 0;

		while(i < val.length){
			count = 0;
			while (count <= IntCardA && i < val.length){
				count = count + cnt[i];
				i++;
			}
			i--;

			if ((count - IntCardA) > (IntCardA - (count - cnt[i])))
			{
				if (MaxDiff < (IntCardA - (count - cnt[i]))) MaxDiff = (IntCardA - (count - cnt[i]));
				count = count - cnt[i];
				if (count == 0)
				{
					count = cnt[i++];
					if (MaxDiff < (count - IntCardA)) MaxDiff = (count - IntCardA);
				}
			}
			else
			{
				if (MaxDiff < (count - IntCardA)) MaxDiff = (count - IntCardA);
				i++;
			}
			if (i == val.length)
				cutPoints.add(new Double(val[i - 1] + (val[i - 1] - val[0]) * 0.001));
			else
				cutPoints.add(new Double((val[i - 1] + val[i]) / 2));

			doPrint(Print.OPERATOR, "Interval no. " + cutPoints.size() + ",  Cardinality " + count);
		}

		cp = new double[cutPoints.size()];
		for (i = 0; i < cutPoints.size(); i++)
			cp[i] = ((Double)cutPoints.get(i)).doubleValue();

		return cp;
	}
}
/*
 * $Log: EquifrequentDiscretizationGivenCardinality.java,v $
 * Revision 1.6  2006/04/11 14:10:18  euler
 * Updated license text.
 *
 * Revision 1.5  2006/04/06 16:31:17  euler
 * Prepended license remark.
 *
 * Revision 1.4  2006/03/30 16:07:14  scholz
 * fixed author tags for release
 *
 * Revision 1.3  2006/03/23 11:13:46  euler
 * Improved exception handling.
 *
 * Revision 1.2  2006/01/06 16:27:57  euler
 * Bugfixes
 *
 * Revision 1.1  2006/01/03 09:54:35  hakenjos
 * Initial version!
 *
 */
