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

/**
 * <p>M4 Compiler</p>
 * <p>Copyright: Copyright (c) 2002</p>
 * <p>Company: University Dortmund</p>
 */

import java.sql.SQLException;

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

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.Step;
import edu.udo.cs.miningmart.m4.Value;

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

    /* Some general settings: */
    // Parameter names:
    private static final String TIMEBASEATTRIB   = "TimeBaseAttrib";
    private static final String VALUEBASEATTRIB  = "ValueBaseAttrib";
    private static final String WINDOWSIZE       = "WindowSize";
    private static final String DISTANCE         = "Distance";
    private static final String OUTTIMESTARTBA   = "OutputTimeStartBA";
    private static final String OUTTIMEENDBA     = "OutputTimeEndBA";
    private static final String WINDOWEDVALUESBA = "WindowedValuesBA";

    private static final String procedureName      = "dbWindow";
    private static final String columnSetSuffix    = "_CS";
    protected String getColumnSetSuffix() { return Windowing.columnSetSuffix; }

    // Name for new BaseAttributes and Columns: Old name + separator + number
    // private static final String VALNAME_SEPARATOR  = "_";


    public BaseAttribute getTimeBA() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(TIMEBASEATTRIB);
    }
	
    public BaseAttribute getValueBA() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(VALUEBASEATTRIB);
    }
	
    public Value getWinSize() throws M4CompilerError {
    	return (Value) this.getSingleParameter(WINDOWSIZE);
    }
	
    public Value getDistance() throws M4CompilerError { 
    	return (Value) this.getSingleParameter(DISTANCE);
    }
	
    public BaseAttribute getOutStartTimeBA() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(OUTTIMESTARTBA);
    }
	
    public BaseAttribute getOutEndTimeBA() throws M4CompilerError {
    	return (BaseAttribute) this.getSingleParameter(OUTTIMEENDBA);
    }


	private BaseAttribute[] getWindowedValuesBA() throws M4CompilerError {
		return (BaseAttribute[]) this.getParameter(WINDOWEDVALUESBA);	
	}
	
    public BaseAttribute getWindowedValueBA(int i) throws M4CompilerError {
		BaseAttribute[] windowedValues = this.getWindowedValuesBA();
		if (windowedValues != null && i < windowedValues.length && i >= 0)
		    return windowedValues[i];
		else return null;
    }

    public int getNumberOfWindowedValuesBAs() throws M4CompilerError {
		BaseAttribute[] windowedValues = this.getWindowedValuesBA();
		if (windowedValues != null)
		    return windowedValues.length;
		else return (0);
    }

    /* This method creates and links the JAVA objects representing the
     * involved M4 objects. While two of the output base attributes are
     * specified as parameters the windowed base attributes and columns
     * need to be created by some kind of template mechanism. */
    protected void createJavaColumns(Columnset newColumnSet)
    	throws M4CompilerError
    {
		this.createWindowedColumns(newColumnSet);
		this.linkOutputTimeBAs(newColumnSet);
    }

    /* --- create and link java columns for "windowed values": --- */
    private void createWindowedColumns(Columnset newCS)
    	throws M4CompilerError
    {
    	try {
			final Column columnForType = this.getValueBA().getColumn(0);
			final int winsize = this.getNumberOfWindowedValuesBAs();
			for (int i=0; i<winsize; i++) {
		    	createM4Column(getWindowedValueBA(i), newCS, columnForType);
			}
    	}
   		catch (M4Exception m4e)
   		{   throw new M4CompilerError("M4 interface error in " + this.getName() + ": " + m4e.getMessage());  } 
    }

    /* --- Create and link columns for startTime and endTime: --- */
    private void linkOutputTimeBAs(Columnset newCS)
    	throws M4CompilerError
    {
    	try {
			final Column columnForType = this.getTimeBA().getColumn(0);
			createM4Column(getOutStartTimeBA(), newCS, columnForType);
			createM4Column(getOutEndTimeBA(), newCS, columnForType);
    	}
   		catch (M4Exception m4e)
   		{   throw new M4CompilerError("M4 interface error in " + this.getName() + ": " + m4e.getMessage());  } 
    }

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

    /*
     * The method invokes the following stored procedure:
     *
     *   dbWindow( NameColumnSet VARCHAR2,
     *             TimeAttrib    VARCHAR2,
     *             ValueAttrib   VARCHAR2,
     *             Target        VARCHAR2,
     *             OutTimeStart  VARCHAR2,
     *             OutTimeEnd    VARCHAR2,
     *             OutWindowCols VARCHAR2,
     *             distance      NUMBER)
     *
     */
    protected void runStoredProcedure(String newColumnsetName)
    	throws SQLException, M4CompilerError, TimeOperatorException
    {
		final Step st = this.getStep();

	  	/* Check if values are numeric: */
		this.valueIsLong(getWinSize(), WINDOWSIZE);
		this.valueIsLong(getDistance(), DISTANCE);

		/* Check if input BaseAttributes have a column: */
		this.baseattribHasColumns(getTimeBA(), TIMEBASEATTRIB);
		this.baseattribHasColumns(getValueBA(), VALUEBASEATTRIB);

		/* Check if number of output BaseAttributes for
		 * windowed values equals the windowsize: */
		if (this.getNumberOfWindowedValuesBAs() != getWinSize().getLong().intValue()) {
		    throw new M4CompilerError(
		    	"Array of BaseAttributes '" + WINDOWEDVALUESBA + "' of step "
		    	+ st.getId() + " does not match the windowsize (parameter name: '"
		    	+ WINDOWSIZE +"')!");
		}

		String[] parameters = {
		    //Input:
		    getQuotedColSetNameforCon(getInputConcept()), // Input Columnset
	    	getQuotedColNameforInpBA(getTimeBA()),        // Time BA
		    getQuotedColNameforInpBA(getValueBA()),       // Value BA
		    // Output:
		    DB.quote(newColumnsetName),                   // Output Columnset
		    getQuotedColNameforOutBA(getOutStartTimeBA()),// BA: Start of Time Window
	    	getQuotedColNameforOutBA(getOutEndTimeBA()),  // BA: End of Time Window
		    DB.quote(createWindowedColsString()),         // Array of BAs: names of "windowed" columns
		    // Specific Parameters:
	    	getUnquotedIntFromValue(getDistance())        // Distance (step size)
	    };

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

    private String createWindowedColsString() throws M4CompilerError {
		String r = "";
		final int winsize = this.getNumberOfWindowedValuesBAs();
		for (int i=0; i<winsize; i++) {
		    r += this.getWindowedValueBA(i).getName() + " ";
		}
		return r;
    }

}
/*
 * Historie
 * --------
 *
 * $Log: Windowing.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:13  scholz
 * fixed author tags for release
 *
 * Revision 1.2  2006/03/23 11:13:45  euler
 * Improved exception handling.
 *
 * Revision 1.1  2006/01/03 09:54:20  hakenjos
 * Initial version!
 *
 */
