/*
 * $Source: /usr/local/cvsroot/erserver/erserver/java/src/com/postgres/replic/tools/JDBCSystem.java,v $
 * $Author: asullivan $ $Revision: 1.1.1.1 $ $Date: 2003/08/26 19:02:24 $
 *
 **********************************************************************
 * DROP TRIGGER name ON table
 **********************************************************************
 * To get all the table names that have the trigger

        SELECT cl.relname
        FROM pg_trigger AS tr, pg_class AS cl, pg_proc AS fn
        WHERE tr.tgrelid=cl.oid AND tr.tgfoid=fn.oid  and tr.tgname = '_rserv_trigger_t_'
        ;

 **********************************************************************
 */

package com.postgres.replic.tools;

import com.postgres.replic.tools.desc.*;
import com.postgres.util.cmd.*;
import java.sql.*;
import java.util.*;

public class JDBCSystem implements ToolKitConst {

    private Connection m_connection;
    protected DBMetaHelper dbMetaHelper;
    private boolean debug = false;
    protected boolean verbose = false;
    private String host;
    private String port;
    private String user;
    private String pass;
    private String db;
    private String schema;
    private String table;
    private String column;
    private String postgres;




    private static final String[] labels =
        {"-host",
        "-port",
        "-user",
        "-pass",
        "-db",
        "-schema",
        "-mode",
        "-table",
        "-column",
        "-postgres",
        };

    private static final String[] flags =         {"-debug", "-verbose", "-slave"};

    private static final String APP_NAME = "java com.postgres.replic.JDBCSystem";


    private static final String DB = "master";
    private static final String USER_SCHEMA = DB;


    private static final int PRINT_TABLES = 1;
    private static final int PRINT_TABLE_COLUMNS = 2;
    private static final int PRINT_PROCEDURES = 3;
    private static final int PRINT_DROP_TRIGGER = 4;
    private static final int PRINT_SEQ = 5;
    private static final int PRINT_MARKER_ADD = 6;
    private static final int PRINT_MARKER_SET_DEF = 7;
    private static final int PRINT_MARKER_PROC_ADD = 8;
    private static final int PRINT_MARKER_PROC_REMOVE = 9;
    private static final int UPDATE_MARKER_COL = 10;
    private static final int PRINT_MARKER_KEY_ADD = 11;  // not used
    private static final int PRINT_MARKER_SET_KEY_DEF = 12; // not used
    private static final int ADD_TABLE = 13;
    private static final int MASTER_INIT = 14;
    private static final int MASTER_DROP = 15;
    private static final int PRINT_CREATE_MARKER_INDEX = 16;
    private static final int PRINT_SCRIPT = 99;

    private int printMode = PRINT_DROP_TRIGGER;

    private static Hashtable hsMode = new Hashtable();

    // Avalilabe modes:
    static {
        hsMode.put("TABLES",
            new Integer(PRINT_TABLES));
        hsMode.put("COLUMNS",
            new Integer(PRINT_TABLE_COLUMNS));
        hsMode.put("PROCEDURES",
            new Integer(PRINT_PROCEDURES));
        hsMode.put("DROP_TRIGGER",
            new Integer(PRINT_DROP_TRIGGER));
        hsMode.put("SCRIPT",
            new Integer(PRINT_SCRIPT));
        hsMode.put("SEQ",
            new Integer(PRINT_SEQ));
        hsMode.put("ADD_MARKER",
            new Integer(PRINT_MARKER_ADD));
        hsMode.put("SET_MARKER_DEF",
            new Integer(PRINT_MARKER_SET_DEF));
        hsMode.put("MARKER_PROC_ADD",
            new Integer(PRINT_MARKER_PROC_ADD));
        hsMode.put("MARKER_PROC_REMOVE",
            new Integer(PRINT_MARKER_PROC_REMOVE));
        hsMode.put("UPDATE_MARKER_COL",
            new Integer(UPDATE_MARKER_COL));
        hsMode.put("MARKER_KEY_ADD",
            new Integer(PRINT_MARKER_KEY_ADD));
        hsMode.put("MARKER_SET_KEY_DEF",
            new Integer(PRINT_MARKER_SET_KEY_DEF));
        hsMode.put("ADD_TABLE",
            new Integer(ADD_TABLE));
        hsMode.put("MASTER_INIT",
            new Integer(MASTER_INIT));
        hsMode.put("MASTER_DROP",
            new Integer(MASTER_DROP));
        hsMode.put("CREATE_MARKER_INDEX",
            new Integer(PRINT_CREATE_MARKER_INDEX));



    }

    private boolean master; // if true should print AddMasterTable & Slave if false

    public static void main (String[] args ) throws Exception {
        JDBCSystem jdbcSys = new JDBCSystem();
        //System.out.println("::jdbcSys.getValidModes()"+jdbcSys.getValidModes());
        //System.exit(0);
        //System.out.println("1");
        if (!jdbcSys.init(args)) {
            System.exit(1);
        }

        jdbcSys.run();
    }

    protected DBMetaHelper getDBMetaHelper() throws Exception {
        if (dbMetaHelper == null) {
            dbMetaHelper = new DBMetaHelper(getConnection());
        }
        return dbMetaHelper;
    }

    private int decodeMode(String mode) throws Exception {
        if (mode == null) {
            return 0;
        } else {
            Integer rcInt = (Integer) hsMode.get(mode.toUpperCase());
            if (rcInt == null) {
                throw new Exception("Unrecognized mode: " + mode + ";" + getValidModes());
            }

            return rcInt.intValue();
        }
    }

    private String getValidModes() {
        String result = " Valid modes are: \n<<" ;
        Iterator it = hsMode.keySet().iterator();
        while (it.hasNext()) {
            String key = (String)it.next();

            result += "\n    " + key ;
        }
        result += "\n>>" ;
        return result;
    }

    private void setDefaults() {
        host = (host == null) ? HOST : host;
        port = (port == null) ? PORT : port;
        //user = (user == null) ? USER : user;
        //pass = (pass == null) ? PASS : pass;
        //db = (db == null) ? DB : db;
        schema = (schema == null) ? db : schema;
        printMode = (printMode == 0) ? PRINT_TABLES : printMode;

    }


    private boolean init(String[] args)  {
        debug = false;
        verbose = false;
        boolean rc = false;
        CmdLine cline = null;

        if (args == null || args.length <= 0) {
            //System.out.println("args == null || args.length");
            setDefaults();
            debug = DEBUG;
            verbose = VERBOSE;
            return true;
        } else {
            //System.out.println("!(args == null || args.length)");
        }

        try {
            cline = CmdLine.instance(args, labels, flags);
            // Flags:
            verbose = cline.getFlag("-verbose");
            debug = cline.getFlag("-debug");
            master = (!cline.getFlag("-slave"));

            // Params:
            host = cline.getParam("-host");
            port = cline.getParam("-port");
            user = cline.getParam("-user");
            pass = cline.getParam("-pass");
            db = cline.getParam("-db");
            schema = cline.getParam("-schema");
            String mode = cline.getParam("-mode");
            table = cline.getParam("-table");
            column = cline.getParam("-column");
            postgres = cline.getParam("-postgres");
            printMode = decodeMode(mode);

            setDefaults();

            if (verbose) {
                System.out.println("verbose=" + verbose);
                System.out.println("debug=" + debug);
                System.out.println("host=" + host);
                System.out.println("port=" + port);
                System.out.println("user=" + user);
                System.out.println("pass=" + pass);
                System.out.println("db=" + db);
                System.out.println("schema=" + schema);
                System.out.println("mode=" + mode);
                System.out.println("table=" + table);
                System.out.println("column=" + column);
                System.out.println("postgres=" + postgres);
            }

            validate();

            rc = true;
        } catch (Exception e) {

            System.out.println("JDBCSystem::init: " + e.toString());
            String usage = CmdLine.getUsage(APP_NAME, labels, flags);
            System.out.println(usage);

        }
        return rc;
    }

    private void validate() throws Exception {
        if (db == null) {
            throw new Exception("Database name may not be null");
        }
    }


    public void run() {

        try {
            getConnection();

            switch (printMode) {
                case PRINT_TABLES:
                    printTables();
                    break;
                case PRINT_TABLE_COLUMNS:
                    printTableColumns();
                    break;
                case PRINT_SCRIPT:
                    printAddTable(master);
                    break;
                case PRINT_PROCEDURES:
                    printProcedures();
                    break;
                case PRINT_DROP_TRIGGER:
                    printDropTrigger();
                    break;
                case PRINT_SEQ:
                    printSeq() ;
                    break;
                case PRINT_MARKER_ADD:
                    printAddMarker() ;
                    break;
                case PRINT_MARKER_SET_DEF:
                    printSetMarkerDef() ;
                    break;
                case PRINT_MARKER_PROC_ADD:
                    printMarkerProcAdd() ;
                    break;
                case PRINT_MARKER_PROC_REMOVE:
                    printMarkerProcRemove() ;
                    break;
                case PRINT_MARKER_KEY_ADD:
                    printAddMarkerKey() ;
                    break;
                case PRINT_MARKER_SET_KEY_DEF:
                    printSetMarkerKeyDef() ;
                    break;
                case ADD_TABLE:
                    addTable() ;
                    break;
                 case MASTER_INIT:
                    masterInit() ;
                    break;
                 case MASTER_DROP:
                    masterDrop() ;
                    break;
                 case PRINT_CREATE_MARKER_INDEX:
                    printCreateMarkerIndex() ;
                    break;


            }
        } catch (Exception e) {
            System.out.println("JDBCSystem::" + e.toString());
        } finally {
            closeConnection();
        }
    }

    public void  updateMarkerCol() throws Exception{
        GeneratorDescriptor gd = new UpdateSeqDesc( true,
             getConnection(), schema) ;
        gd.setDebug(debug);
        generateScript(gd);
    }

    public void addTable()
    throws Exception{
        AddTable addTable = null;

        if (master) {
             addTable = new MasterAddTable(
                                getConnection(),
                                table,
                                column);
        } else {
             addTable = new SlaveAddTable(
                                getConnection(),
                                table,
                                column);

        }

        addTable.setDebug(debug);
        addTable.addTable();
    }

    public void masterInit()
    throws Exception{
        //System.out.println("JDBCSystem::masterInit: postgres="+postgres+"; conn="+getConnection());
        MasterInit masterInit = new MasterInit(
                    getConnection(),
                    postgres);
       masterInit.setDebug(debug);
       masterInit.setVerbose(verbose);
       masterInit.masterInit();
    }

    public void masterDrop()
    throws Exception{
        //System.out.println("JDBCSystem::masterInit: postgres="+postgres+"; conn="+getConnection());
        MasterInit masterInit = new MasterInit(
                    getConnection(),
                    postgres);
       masterInit.setDebug(debug);
       masterInit.setVerbose(verbose);
       masterInit.masterDrop();
       masterInit.masterDropFun();
    }

    public void printAddTable(boolean master) throws Exception{
        GeneratorDescriptor gd = new AddTableColumnDesc(host,
             port,
                 user,
                     pass,
                         schema,
                             master,
                                 true) ;

        System.out.println(BIN);
        generateScript(gd);
    }

    public void printSeq() {
        try {
            GeneratorDescriptor gd = new SequenceDesc(true, getConnection()) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printSeq" + e.toString());
        }
    }

    public void printAddMarker() {
        try {
            GeneratorDescriptor gd = new AddMarkerColumn(true, AddMarkerColumn.ADD_COLUMN) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printAddMarker" + e.toString());
        }
    }  // printCreateMarkerIndex

    public void printCreateMarkerIndex() {
        try {
            GeneratorDescriptor gd = new AddMarkerColumn(true, AddMarkerColumn.CREATE_INDEX) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printCreateMarkerIndex" + e.toString());
        }
    }

    public void printSetMarkerDef() {
        try {
            GeneratorDescriptor gd = new AddMarkerColumn(true, AddMarkerColumn.SET_DEFAULT) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printSetMarkerDef" + e.toString());
        }
    }

    //////
    public void printAddMarkerKey() {
        try {
            GeneratorDescriptor gd = new AddMarkerKeyColumn(true, AddMarkerKeyColumn.ADD_COLUMN) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printAddMarkerKey" + e.toString());
        }
    }

    public void printSetMarkerKeyDef() {
        try {
            GeneratorDescriptor gd = new AddMarkerKeyColumn(true, AddMarkerKeyColumn.SET_DEFAULT) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printSetMarkerKeyDef" + e.toString());
        }
    }


    public void printMarkerProcAdd() {
        try {
            GeneratorDescriptor gd = new MarkerProc(true, MarkerProc.ADD) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printMarkerProcAdd" + e.toString());
        }
    }

    public void printMarkerProcRemove() {
        try {
            GeneratorDescriptor gd = new MarkerProc(true, MarkerProc.REMOVE) ;
            gd.setDebug(debug);
            generateScript(gd);
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printMarkerProcRemove" + e.toString());
        }
    }

    public void printDropTrigger() {
        try {
            DropTriggerDesc dtd = new DropTriggerDesc(true, getConnection());
            dtd.printDropTrigger();
        } catch (Exception e) {
            System.out.println("JDBSCSystem::printDropTrigger" + e.toString());
        }
    }

    public void printTables() {
        ResultSet rsTbl = null;
        try {
            rsTbl = getDBMetaHelper().getTables(schema);
            int count = 0;
            System.out.println("******************\n  TABLES:  \n******************");
            while (rsTbl.next()) {
                count++;

                String tableName = rsTbl.getString("TABLE_NAME"); //3
                //int columnCount = rsTbl.getMetaData().getColumnCount();
                System.out.println("  #" +
                count + ": " + tableName);
            }
        } catch (Exception e) {
            System.out.println("JDBCSystem::printTables: " + e.toString());
        } finally {
            try {
                if (rsTbl != null) {
                    rsTbl.close();
                }
            } catch (Exception e) {
            }
        }
    }

    public void printProcedures() {
        ResultSet rs = null;
        try {
            rs = getDBMetaHelper().getProcedures(schema);
            int count = 0;
            System.out.println("******************\n  PROCEDURES:  \n******************");
            while (rs.next()) {
                count++;

                String tableName = rs.getString("PROCEDURE_NAME"); //3
                System.out.println("  #" +
                count + ": " + tableName);
            }
        } catch (Exception e) {
            System.out.println("JDBCSystem::printProcedures: " + e.toString());
        } finally {
            try {
                if (rs != null) {
                    rs.close();
                }
            } catch (Exception e) {
            }
        }
    }

    public String generateScript(GeneratorDescriptor gd) {
        ResultSet rsTbl = null;
        ResultSet rsCol = null;
        String result = "";
        try {
            rsTbl = getDBMetaHelper().getTables(schema);
            //System.out.println("******************\n  TABLE COLUMNS:
            // \n******************");
            int count = 0;
            while (rsTbl.next()) {
                count++;

                String tableName = rsTbl.getString("TABLE_NAME"); //3
                //int columnCount = rsTbl.getMetaData().getColumnCount();
                if (debug) System.out.println("  generateScript: TABLE #" +
                    count + ": " + tableName);
                if (!gd.tableOnly()) {
                    try {
                        rsCol = getDBMetaHelper().getColumns(schema, tableName);
                        while (rsCol.next()) {
                            String columnName = rsCol.getString("COLUMN_NAME");
                            if (debug)
                                System.out.println("          generateScript: " +
                                    columnName);
                            result += gd.getLine(tableName, columnName);
                        }
                    } catch (Exception e) {
                        System.out.println("JDBCSystem::generateScript: " + e.toString());
                    } finally {
                        try {
                            if (rsCol != null) {
                                rsCol.close();
                            }
                        } catch (Exception e) { }
                    }
                } else { //gd.tableOnly():
                    result += gd.getLine(tableName);
                }

            }
        } catch (Exception e) {
            System.out.println("JDBCSystem::generateScript: " + e.toString());
        } finally {
            try {
                if (rsTbl != null) {
                    rsTbl.close();
                }
            } catch (Exception e) {
            }
        }

        return result;
    }

    public void printTableColumns() {
        ResultSet rsTbl = null;
        ResultSet rsCol = null;
        try {
            rsTbl = getDBMetaHelper().getTables(schema);
            System.out.println("******************\n  TABLE COLUMNS:  \n******************");
            int count = 0;
            while (rsTbl.next()) {
                count++;

                String tableName = rsTbl.getString("TABLE_NAME"); //3
                //int columnCount = rsTbl.getMetaData().getColumnCount();
                System.out.println("  TABLE #" +
                count + ": " + tableName);
                try {
                    rsCol = getDBMetaHelper().getColumns(schema, tableName);
                    while (rsCol.next()) {
                        String columnName = rsCol.getString("COLUMN_NAME");
                        System.out.println("          " +  columnName);
                    }
                } catch (Exception e) {
                    System.out.println("JDBCSystem::printTableColumns: " + e.toString());
                } finally {
                    try {
                        if (rsCol != null) {
                            rsCol.close();
                        }
                    } catch (Exception e) { }
                }

            }
        } catch (Exception e) {
            System.out.println("JDBCSystem::printTableColumns: " + e.toString());
        } finally {
            try {
                if (rsTbl != null) {
                    rsTbl.close();
                }
            } catch (Exception e) {
            }
        }
    }


    public Connection getConnection()  {
        Connection conn = null;

        try {
            if (m_connection == null) {

                DriverManager.registerDriver(
                    new org.postgresql.Driver());

                if (debug) System.out.println ("AFTER DriverManager.registerDriver");
                // Connect to the database
                // You must put a database name after the @ sign in the connection URL.
                // You can use either the fully specified SQL*net syntax or a short cut
                // syntax as <host>:<port>:<sid>.  The example uses the short cut syntax.
                String connString = DB_TCP + host + ":" + port + "/" + db;
                if (debug) System.out.println ("::getConnection:connString="+connString);

                conn =
                DriverManager.getConnection (connString, user, pass);

                if (debug)
                    System.out.println ("SUCCESSFULLY CONNECTED TO DATABASE " + connString);
                m_connection = conn;
            }
        } catch (Exception e) {
             System.out.println ("CANNOT CONNECT TO DATABASE: " + e.toString());
             System.exit(1);
        }

        return m_connection;

    }

    private void closeConnection(){
        try {
            if (m_connection != null) m_connection.close();
        } catch (Exception e) {}
    }
}

