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

import java.sql.SQLException;

import edu.udo.cs.miningmart.storedProcedures.TimeOperatorException;
import edu.udo.cs.miningmart.storedProcedures.WMF;

import edu.udo.cs.miningmart.db.DB;
import edu.udo.cs.miningmart.exception.M4CompilerError;
import edu.udo.cs.miningmart.exception.M4Exception;
import edu.udo.cs.miningmart.m4.BaseAttribute;
import edu.udo.cs.miningmart.m4.Column;
import edu.udo.cs.miningmart.m4.Columnset;
import edu.udo.cs.miningmart.m4.Value;

/**
 * @author Martin Scholz
 * @version $Id: WeightedMovingFunction.java,v 1.5 2006/04/11 14:10:10 euler Exp $
 */
public class WeightedMovingFunction extends TimeOperator {

    /* Some general settings: */
    // Parameter names:
    private static final String INPUTTIMEBA       = "InputTimeBA";
    private static final String INPUTVALUEBA      = "InputValueBA";
    private static final String OUTPUTTIMESTARTBA = "OutputTimeStartBA";
    private static final String OUTPUTTIMEENDBA   = "OutputTimeEndBA";
    private static final String OUTPUTVALUEBA     = "OutputValueBA";
    private static final String WEIGHTS           = "Weights";
    private static final String DISTANCE          = "Distance";

    private static final String procedureName      = "WMA";
    private static final String columnSetSuffix    = "_CS";

    protected String getColumnSetSuffix() { return WeightedMovingFunction.columnSetSuffix; }

    public BaseAttribute getTimeBaIn() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(INPUTTIMEBA);
    }
	
    public BaseAttribute getValueBaIn() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(INPUTVALUEBA);
    }

    public BaseAttribute getTimeBaStartOut() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(OUTPUTTIMESTARTBA);
    }

    public BaseAttribute getTimeBaEndOut() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(OUTPUTTIMEENDBA);
    }

    public BaseAttribute getValueBaOut() throws M4CompilerError { 
    	return (BaseAttribute) this.getSingleParameter(OUTPUTVALUEBA);
    }

    public Value getDistance() throws M4CompilerError {
    	return (Value) this.getSingleParameter(DISTANCE);
    }

    public Value[] getWeights() throws M4CompilerError {
    	return (Value[]) this.getParameter(WEIGHTS);
    }

    public Value getWeight(int i) throws M4CompilerError {
    	Value[] weights = this.getWeights();
		if (weights != null && i < weights.length && i >= 0)
		    return weights[i];
		else return null;
    }

    public int getNumberOfWeights() throws M4CompilerError {
    	Value[] weights = this.getWeights();
		if (weights != null)
		    return weights.length;
		else return (0);
    }

    /* -------- Create and link columns: -------- */
    protected void createJavaColumns(Columnset newCS) throws M4CompilerError 
    {
    	try {
			final Column timeColumnForType = this.getTimeBaIn().getColumn(0);
			createM4Column(getTimeBaStartOut(), newCS, timeColumnForType);
			createM4Column(getTimeBaEndOut(),   newCS, timeColumnForType);
		
			final Column valueColumnForType = this.getValueBaIn().getColumn(0);
			createM4Column(getValueBaOut(), newCS, valueColumnForType);
    	}    	
   		catch (M4Exception m4e)
   		{   throw new M4CompilerError("M4 interface error in " + this.getName() + ": " + m4e.getMessage());  } 
    }

    // ------------------------------------------------------------------------------

    /*
     * ----- Method invokes the following stored procedure: -----
     *
     *  WMA( InputColumnSet     VARCHAR2,
     *       TimeAttribIn       VARCHAR2,
     *       ValueAttribIn      VARCHAR2,
     *       TargetColumnSet    VARCHAR2,
     *       TimeStartAttribOut VARCHAR2,
     *       TimeEndAttribOut   VARCHAR2,
     *       ValueAttribOut     VARCHAR2,
     *       weights            VARCHAR2,
     *       distance           NUMBER)
     *
     */
    protected void runStoredProcedure(String newColumnsetName)
    	throws SQLException, M4CompilerError, TimeOperatorException
    {
		// Check if values are numeric:
		this.valueIsLong(getDistance(), DISTANCE);
		final int numWeights = this.getNumberOfWeights();
		if (numWeights == 0) {
	    	throw new M4CompilerError(
	    		"Parameter array '" + WEIGHTS + "' of step "
	    		+ this.getStep().getId() + " could not be loaded!"
	    	);
		}

		for (int i=0; i<numWeights; i++) {
		    this.valueIsDouble(this.getWeight(i), WEIGHTS);
		}

		// Check if input BaseAttributes have a column:
		this.baseattribHasColumns(getTimeBaIn(),  INPUTTIMEBA);
		this.baseattribHasColumns(getValueBaIn(), INPUTVALUEBA);

		String[] parameters = {
		    //Input:
	    	getQuotedColSetNameforCon(getInputConcept()), // Input Columnset
		    getQuotedColNameforInpBA(getTimeBaIn()),      // Time BA
		    getQuotedColNameforInpBA(getValueBaIn()),     // Value BA
		    // Output:
	    	DB.quote(newColumnsetName),                 // Output Columnset
		    getQuotedColNameforOutBA(getTimeBaStartOut()), // BA: Start time for output
		    getQuotedColNameforOutBA(getTimeBaEndOut()),   // BA: End time for output
	    	getQuotedColNameforOutBA(getValueBaOut()),  // BA: output values
		    // Specific Parameters:
		    DB.quote(weightsToString()),     // Weights vector
	    	getDistance().getValue().trim()  // Distance (step size)
    	};

		if (storedProceduresAvailable()) {
			this.executeDbProcedure(WeightedMovingFunction.procedureName, parameters);
		}
		else {
			WMF.dbWMA( this.getM4Db(),
					   unquote(parameters[0]),
					   unquote(parameters[1]),
					   unquote(parameters[2]),
					   unquote(parameters[3]),
					   unquote(parameters[4]),
					   unquote(parameters[5]),
					   unquote(parameters[6]),
					   unquote(parameters[7]),
					   Integer.parseInt(parameters[8])
					 );
		}
    } // end private void runStoredProcedure


    private String weightsToString() throws M4CompilerError {
		String r = "";
		final int numWeights = this.getNumberOfWeights();
		for (int i=0; i<numWeights; i++) {
		    r += this.getWeight(i).getValue().trim() + " ";
		}
		return (r.trim());
    }

}
/*
 * Historie
 * --------
 *
 * $Log: WeightedMovingFunction.java,v $
 * Revision 1.5  2006/04/11 14:10:10  euler
 * Updated license text.
 *
 * Revision 1.4  2006/04/06 16:31:10  euler
 * Prepended license remark.
 *
 * Revision 1.3  2006/03/30 16:07:12  scholz
 * fixed author tags for release
 *
 * Revision 1.2  2006/03/23 11:13:44  euler
 * Improved exception handling.
 *
 * Revision 1.1  2006/01/03 09:54:21  hakenjos
 * Initial version!
 *
 */
