package miningmart.storedProcedures;
import java.sql.*;

public class Windowing {
    private DbConnector connector;
    private ResultSet rSet;
    private int wndSize;	    // current window size
    private int distance; 	    // distance between two data windows
    private boolean firstWnd;	    // true, if the current window is the first one
    private int sourceCol;	    // index of the source column
    private int timeCol;	            // index of the primary key column
    private String[] results;	    // the data window
    private String[] timeStamps;    // the time stamp window

    // Constructor
    // in :
    // - wndSize : size of a data window
    // - distance : distance between two data windows
    public Windowing(DbConnector connector) throws SQLException {
	wndSize    = 5;
	distance   = 1;
	sourceCol  = 1;
	timeCol    = 2;
	firstWnd   = true;
	results    = new String[wndSize];
	timeStamps = new String[wndSize];

	this.connector = connector;
    }

    public Windowing(int wndSize, int distance, DbConnector connector) throws SQLException {
	this.wndSize  = wndSize;
	this.distance = distance;
	
	sourceCol  = 1;
	timeCol    = 2;
	firstWnd   = true;
	results    = new String[wndSize];
	timeStamps = new String[wndSize];
	
	this.connector = connector;
    }

    // setWindowSize
    // description : sets a new window size
    // in :
    // - size : new size
    public void setWndSize(int size) {
	wndSize = size;
	results = new String[wndSize];
    }

    // setDistance
    // description : sets a new distance
    // in :
    // - distance : new distance
    public void setDistance(int distance) {
	this.distance = distance;
    }

    // setSourceCol
    // description : sets the source column index
    // in :
    // - col : the column's index in the source table
    public void setSourceCol(int col) {
	sourceCol = col;
    }

    // setSourceCol
    // desctiption : sets the source column index
    // in :
    // - col : the column's index in the source table
    public void setPrimaryKeyCol(int timeCol) {
	this.timeCol = timeCol;
    }

    // open
    // description : opens the target table and sends a sql command
    public boolean open(String sql) {
	try {
	    Statement stmt = connector.getConnection().createStatement();
	    rSet = stmt.executeQuery(sql);
	    
	    return true;
	}
	catch (Exception e) {
	    DbConnector.infoOutput("Error while opening " + sql);
	    return false;
	}
    }

    // deallocates the database connection for this window 
    public void close() {
	if (this.rSet != null) {
	    try {
		this.rSet.close();
	    } catch (SQLException e) {
		DbConnector.infoOutput("Closing ResultSet in class Windowing failed:\n" + e);
	    }
	    this.rSet = null;
	}
    }

    // shiftArray
    // description : shifts all values in the array n indexes left
    // in :
    // - array : the array
    // - n : number of indexes to shift
    private void shiftArray(String[] array, int n) {
	for (int i = 0; i < array.length; i++)
	    array[i] = (i + n < array.length) ? array[i + n] : "0";
    }
    
    // getNextWnd
    // desctiontion : returns the next data window
    // out :
    // - String[] : the new window
    public String[] getNextWnd() {
	if (this.rSet == null)
	    return null;

	try {
	    if (firstWnd) {
		// if this is the first window, simply initialize it
		for (int i = 0; i < wndSize; i++) {
		    if (rSet.next()) {
			results[i] = rSet.getString(sourceCol);
			timeStamps[i] = rSet.getString(timeCol);
			
			// if current value is a SQL NULL, get next value
			if (results[i] == null) i--;
		    }
		    else {
			return null;
		    }
		}
		firstWnd = false;
		
		return results;
	    }

	    // two windows are overlapping
	    if (distance < wndSize) {
		shiftArray(results,distance);
		shiftArray(timeStamps,distance);
		
		for (int i = wndSize - distance; i < wndSize; i++) {
		    if (rSet.next()) {
			results[i] = rSet.getString(sourceCol);
			timeStamps[i] = rSet.getString(timeCol);
			
			// if current value is a SQL NULL, get next value
			if (results[i] == null) i--;
		    }
		    else {
			return null;
		    }
		}
	    }
	    // two windows are disjunct
	    else {
		// move to next window
		for (int i = 0; i < distance - wndSize; i++)
		    if (!rSet.next()) return null;
		
		// fill  array with values
		for (int i = 0; i < wndSize; i++)
		    {
			if (rSet.next()) {
			    results[i]    = rSet.getString(sourceCol);
			    timeStamps[i] = rSet.getString(timeCol);
			    
			    // if current value is a SQL NULL, get next value
			    if (results[i] == null) i--;
			}
			else {
			    return null;
			}
		    }
	    }
	    
	    return results;
	}
	catch (SQLException e) {
	    return null;
	}
    }
    
    public String getTimeFirstEntry() {
	if ((timeStamps == null) || (timeStamps.length == 0))
	    return null;
	return (timeStamps[0]);
    }

    public String getTimeLastEntry() {
	if ((timeStamps == null) || (timeStamps.length == 0))
	    return null;
	return (timeStamps[timeStamps.length-1]);
    }

}
