/*
 * 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.compiler.wrapper.dista;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.Properties;

import edu.udo.cs.miningmart.operator.ExecutableOperator;

import edu.udo.cs.miningmart.compiler.SystemPropertyInterface;
import edu.udo.cs.miningmart.db.CompilerDatabaseService;
import edu.udo.cs.miningmart.exception.DbConnectionClosed;
import edu.udo.cs.miningmart.m4.Step;

/**
 * Superclass for all Dista wrappers.
 * 
 * @author Alessandro Serra, Timm Euler
 * @version $Id: Wrapper.java,v 1.4 2006/04/11 14:10:17 euler Exp $
 */
public abstract class Wrapper {
	protected MetaData m_md;
	protected CompilerDatabaseService m4db;
	protected Properties m_properties;
	protected String m_result_name;
	protected long m_sample_size;
	protected boolean m_do_clean;
	protected OutputStream m_log;
	protected String m_ml_home;
	protected String m_os_name;
	
	private final Step step;
	private final ExecutableOperator exOp;

	public Wrapper(Step step, ExecutableOperator exOp) throws Exception {
		this.step = step;
		this.exOp = exOp;
		
		m_sample_size=100000;
		m_do_clean=false;
		m_ml_home=SystemPropertyInterface.getProperty(SystemPropertyInterface.NAME_COMPILER_HOME);
		m_properties=new Properties();
		m_properties.load(new FileInputStream(
			m_ml_home+ File.separator + "etc" + File.separator + "wrapper_properties.txt"));
		m_result_name="test";
		m_os_name=System.getProperty("os.name");
		if (m_os_name.substring(0, 3).equalsIgnoreCase("win")) {
			m_os_name ="Windows";
		}
		if (m_os_name.substring(0, 5).equalsIgnoreCase("linux")) {
			m_os_name ="Linux";
		}

	}

	public CompilerDatabaseService getM4Db() {
		return this.m4db;
	}
	
	

	public void setMetaData(MetaData md) throws Exception {
		m_md=md;
	}
	public void setConnection(CompilerDatabaseService m4db) {
		this.m4db = m4db;
	}
	public void setProperties(Properties p) {
		m_properties=p;
	}
	public void setResultName(String v) {
		m_result_name=v;
	}
	public void setSampleSize(long v) {
		m_sample_size=v;
	}

	public void run() throws Exception {
		if(m_md == null) {
			throw new DMException("Wrapper:"+
				" MetaData Object is null.");
		}
		if(this.getM4Db() == null) {
			throw new DMException("Wrapper:"+
				"DB Object is null.");
		}
		checkMetaData();
		exportTable();
		callTool();
		importResult();
		saveResult();
		if(m_do_clean) {
			clean();
		}
	}

	protected ExecutableOperator getExecutableOperator() {
		return this.exOp;
	}

	protected abstract void checkMetaData() throws Exception;	
	
	protected abstract void exportTable() throws Exception;
	
	protected abstract void callTool() throws Exception;
	
	protected abstract void importResult() throws Exception;
	
	protected abstract void saveResult() throws Exception;
	
	protected abstract void clean() throws Exception;

	protected void callScript(String command) throws DMException {
		try {
			Runtime runtime=Runtime.getRuntime();
		    	String s = File.separator;
			String args[]=new String[3];
			String temporaryDir = SystemPropertyInterface.getProperty(SystemPropertyInterface.NAME_MM_TEMP);
			args[0]=m_properties.getProperty("shell");
			args[1]="-c";

			
			args[2]=
			    "PATH=\"$PATH:" + m_ml_home + s + "bin" + s + m_os_name + s + "\"; " +
				"export PATH; " +
				"cd " + temporaryDir + "; " +
				command;
			// debug
			//System.out.print(args[2]+"\n");

			Process proc = runtime.exec(args,null);
			proc.waitFor();

			if(m_log==null) {
				m_log=new FileOutputStream(
					temporaryDir + s + "wrapper_script.log");
			}
			//m_log.write("*** command: "+command+" ***\n");
			//m_log.write("*** output: ***\n");
			InputStream strm=proc.getInputStream();
			int c=strm.read();
			while(c!=-1) {
				m_log.write(c);
				c=strm.read();
			}
			//m_log.write("*** error: ***\n");
			strm=proc.getErrorStream();
			c=strm.read();
			while(c!=-1) {
				m_log.write(c);
				c=strm.read();
			}
			int ex = proc.exitValue();
			if(ex!=0) {
				proc.destroy();
				throw new DMException("Wrapper:"+
					" Error calling script (returned with exit value "+ex+"): "
					+command);
			}
		} catch(Exception e) {
			throw new DMException("Wrapper: Error calling script "+
				command+" :"+e.getMessage());
		}
	}

	protected double getSampleRatio(
		long sampleSize,
		String tableName,
		String columnName)
		throws DMException, DbConnectionClosed {
		if (sampleSize <= 0) {
			throw new DMException(
				"Wrapper:"
					+ " Sample Size must be positive!"
					+ " Found: "
					+ sampleSize
					+ ".");
		}
		String sql_getNumberOfRecords =
			"SELECT count(*) " + "FROM " + tableName;
		if (columnName != null) {
			sql_getNumberOfRecords =
				sql_getNumberOfRecords
					+ " WHERE "
					+ columnName
					+ " is not null";
		}
		long count = 0;
		try {
			Long countL =
				this.getM4Db().executeBusinessSingleValueSqlReadL(
					sql_getNumberOfRecords);
			if (countL != null) {
				count = countL.longValue();
			}
			else {
				throw new DMException(
					"Wrapper:"
						+ " Could not read result "
						+ " from query: "
						+ sql_getNumberOfRecords);
			}
			this.getM4Db().commitBusinessTransactions();
		}
		catch (SQLException sqle) {
			throw new DMException(
				"Wrapper:"
					+ " Could not read result "
					+ " from query: "
					+ sql_getNumberOfRecords
					+ ", Database problem: "
					+ sqle.getMessage());
		}
		if (sampleSize > count) {
			sampleSize = count;
		}
		double sampleRatio = (double) sampleSize / (double) count;
		// new M4RandomSelect function:
		return sampleRatio;
	}
	
    protected String getArtificalColumnName(String otherColumns)
    {   
    	String artCol = "Z";
    	// make sure artCol does not occur in otherColumns:
    	while (otherColumns.indexOf(artCol + ",") > -1)
    	{   artCol += "1";  }
    	
    	return artCol;
    }
    
	/** @return the current <code>Step</code> */
	public Step getStep() {
		return this.step;
	}

}
/*
 * Historie
 * --------
 * 
 * $Log: Wrapper.java,v $
 * Revision 1.4  2006/04/11 14:10:17  euler
 * Updated license text.
 *
 * Revision 1.3  2006/04/06 16:31:17  euler
 * Prepended license remark.
 *
 * Revision 1.2  2006/03/30 16:07:15  scholz
 * fixed author tags for release
 *
 * Revision 1.1  2006/01/03 09:54:33  hakenjos
 * Initial version!
 *
 */
