package com.mozartframework.db.create;

import java.sql.SQLException;
import java.util.List;

import org.springframework.dao.DataAccessException;

import com.mozartframework.db.config.Function;

/**
 * Method Object for creating and dropping stored procedures.
 */
class Functions extends CreationStuff {

    Functions(DBCreate dbc) {
        super(dbc);
    }

    /**
     *	Create all functions from config
     */
    void create() throws DBCreateException {
	    if (isLoggingEnabled()) {
	        getLog().setCreateFunctionsException(DBCreateLog.STARTED);
	    }
        actionMessage("Creating stored procedures");
        if ( getConfig().isNativeSystemTriggers() ) {
        	createSystemFunctions();
        }
        createUserDefinedFunctions();
        if (isLoggingEnabled()) {
            getLog().setCreateFunctionsException(DBCreateLog.OK);
        }
        ok();
    }

    void create(String functionStatment) throws DBCreateException {
        if (functionStatment == null || functionStatment.length() == 0)
            return;
        String functionName = getDBAdapter().getStoredProcedureName(functionStatment);
        try {
	        execute(functionStatment);
        } catch (SQLException e) {
            throw newCreateException(DBCreateException.DBC_CANT_CREATE_FUNCTION, "Cannot create function", e, functionName);
        }
        try {
            execute("INSERT INTO " + getDBAdapter().getFuctionTableName() + " (funcname) VALUES ('" + functionName + "')");
        } catch (SQLException e) {
            throw newCreateException(DBCreateException.DBC_CANT_REGISTER_FUNCTION, "Cannot register function", e, functionName);
        }
    }

    /**
     *	Drop function that registered in mz_function table
     */
    void drop() throws DBCreateException {
    	if (isLoggingEnabled()) {
    		getLog().setDropFunctionsException(DBCreateLog.STARTED);
    	}
    	actionMessage("Dropping stored procedures");

    	try {
    		List<Object[]> rows = executeQuery("SELECT funcname FROM " + getDBAdapter().getFuctionTableName());
    		for (Object[] row : rows) {
    			drop( (String)row[0] );
    		}
    	} catch (DataAccessException e) {
    		throw newGeneralDropException("Cannot drop functions", e);
    	}
    	if (isLoggingEnabled()) {
    		getLog().setDropFunctionsException(DBCreateLog.OK);
    	}
    	ok();
    }

    private DBCreateException newGeneralDropException(String msg, Exception e) {
        DBCreateException exception = new DBCreateException(DBCreateException.DBC_CANT_DROP_FUNCTIONS, msg, e, null);
        if (isLoggingEnabled()) {
            getLog().setDropFunctionsException(exception);
        }
        return exception;
    }

    private DBCreateException newDropException(int code, String msg, SQLException e, String function) {
        DBCreateException exception = new DBCreateException(code, msg, e, null);
        exception.setAttr("function", function);
        if (isLoggingEnabled()) {
            getLog().setDropFunctionsException(exception);
        }
        return exception;
    }

    private DBCreateException newCreateException(int code, String msg, SQLException e, String function) {
        DBCreateException exception = new DBCreateException(code, msg, e, null);
        exception.setAttr("function", function);
        if (isLoggingEnabled()) {
            getLog().setCreateFunctionsException(exception);
        }
        return exception;
    }

    private void drop(String functionName) throws DBCreateException {
        try {
            if (getDBAdapter().storedProcedureExists(getDBConnect(), functionName)) {
                execute(getDBAdapter().getDropStoredProcedureSql(functionName));
            }
        }
        catch (SQLException e) {
            throw newDropException(DBCreateException.DBC_CANT_DROP_FUNCTION, "Cannot drop function", e, functionName);
        }
        try {
            execute("DELETE FROM " + getDBAdapter().getFuctionTableName() + " WHERE funcname='" + functionName + "'");
        }
        catch (SQLException e) {
            throw newDropException(DBCreateException.DBC_CANT_UNREGISTER_FUNCTION, "Cannot unregister function", e, functionName);
        }
    }

    private void createUserDefinedFunctions() throws DBCreateException {
        for (Function f : getConfig().getFunctions()) {
        	if (f.isSqlFunction()) {
        		create(f.getBody());
        	}
        }
    }

    private void createSystemFunctions() throws DBCreateException {
        for ( String sql : getDBAdapter().getSystemStoredProcedureSql( getConfig().getSchemaName() ) ) {
        	create(sql);
        }
    }

}
