/**
 * Class copyright 2003 by the Ravensfield Digital Resource Group, Ltd, Granville, OH.
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without a written agreement
 * is hereby granted, provided that the above copyright notice and this
 * paragraph and the following two paragraphs appear in all copies.
 *
 * IN NO EVENT SHALL THE RAVENSFIELD DIGITAL RESOURCE GROUP, LTD BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
 * DOCUMENTATION, EVEN IF THE RAVENSFIELD DIGITAL RESOURCE GROUP, LTD HAS BEEN ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * THE RAVENSFIELD DIGITAL RESOURCE GROUP, LTD SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE RAVENSFIELD DIGITAL RESOURCE GROUP, LTD HAS NO OBLIGATIONS TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 * (Quick readers will recognize that as the stock BSD license)
 *
 */
package org.postgresql.ers;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;


/**
 *  Class to add a table to a replication scheme. This is a rewrite of ers_addtable.
 *
 * @author     Andrew Rawnsley
 */
public class ERSRemoveTable extends ERS {

	/**
	 * Constructor for the ERSAddTable object
	 *
	 *USAGE: java org.postgresql.ers.ERSAddTable {options} <table 1> <table 2> ... <table n>
	 *options: 	-u columnName		Column name for the unique sequence id (default _ers_uniq)
	 *-d config			Install directory for eRServer (default /opt/erserver)
	 *
	 * @param  table             Table
	 * @param  primary           Connection to the primary
	 * @param  replicants        Connections to the replicants
	 * @param  schemaSupport     Parameter
	 * @exception  SQLException
	 */
	public ERSRemoveTable(String table, Connection primary, Connection[] replicants, boolean dropTable,
						  boolean schemaSupport, String ersSchema, String host, int port) throws SQLException {

		Statement stmnt;

		setSchemaSupport(schemaSupport);
		setErsSchema(ersSchema);

		if (!quiet) {
			System.out.println("Removing table " + table);
		}

		// Bad table name. Yell at user
		if (!tableExists(table, primary)) {
			System.out.println("Table " + table + " does not exist in primary.");
			return;
		}

		String schema;

		String tableName;
		String sequenceName;
		int pos;

		if (schemaSupport) {
			// Separate the table name to schema and table, if necessary
			if ((pos = table.indexOf(".")) >= 0) {
				schema = table.substring(0, pos);
				tableName = table.substring(pos + 1);
			} else {
				tableName = table;
				schema = "public";
				table = "public." + table;
			}
			sequenceName = schema + "._ers_" + tableName + "_seq";
		} else {
			tableName = table;
			schema = null;
			sequenceName = "_ers_" + tableName + "_seq";
		}

		removeTable(table,primary,replicants);

		// Signal the backend to reset its table/column maps
		if (host != null) {
			try {
				new ERSCtl(2, host, port);
				if (!quiet) {
					System.out.println("Backend successfully signaled.");
				}
			} catch (Exception ex) {
				System.out.println("Backend signal failed.");
				//ex.printStackTrace();
			}
		}

		// Remove the tables after the backend has been signaled
		if (dropTable) {
			if (!quiet) {
				System.out.println("Dropping table/sequence.");
			}
            stmnt = primary.createStatement();
			stmnt.execute("DROP SEQUENCE "+sequenceName);
			stmnt.execute("DROP TABLE "+table+" CASCADE");
			stmnt.close();

			for (int i=0;i<replicants.length;i++) {
				stmnt = replicants[i].createStatement();
				stmnt.execute("DROP TABLE "+table+" CASCADE");
				stmnt.close();
			}

		}

	}

	/**
	 *  Add tables to the replicator
	 *
	 * @param  args  The command line arguments
	 */
	public static void main(String[] args) {

		int i;
		String fileName;
		String[] fileArgs;
		Properties properties = null;
		String[] replicantURL = null;
		String[] replicantUser = null;
		String[] replicantPass = null;

		Options options = new Options();
		options.addOption("h", "host", true, "Host name of running eRServer (default localhost)");
		options.addOption("p", "port", true, "Port # for signal (default 1099)");
		options.addOption("ns", "nosignal", false, "Don't signal backend");
		options.addOption("d", "ers_home", true, "Install directory for eRServer (default /opt/erserver)");
		options.addOption("x", "droptable", true, "Remove table and sequences - CAREFUL! DONE WITH CASCADE!");
		options.addOption("f", "file", true, "File containing a list of tables to remove");
		options.addOption("q", "quiet", false, "Run quiet");

		//parse the commandline arguments
		GnuParser parser = new GnuParser();
		CommandLine line = null;
		try {
			line = parser.parse(options, args);
		} catch (org.apache.commons.cli.ParseException exp) {
			System.out.println("Parsing failed. Reason: " + exp.getMessage());
			return;
		}

		if (args.length == 0) {
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("USAGE: java org.postgresql.ers.ERSAddTable <options> <table1{,uniq}> ... <table n{,uniq}>", options);
			return;
		}

		String ersHome = line.getOptionValue("d", "/opt/erserver/");
		quiet = line.hasOption("q");

		if (!ersHome.endsWith(System.getProperty("file.separator"))) {
			ersHome += System.getProperty("file.separator");
		}

		String s;
		String host = null;
		int port = 1099;

		if (!line.hasOption("ns")) {
			host = line.getOptionValue("h", "localhost");
			if ((s = line.getOptionValue("p")) != null) {
				try {
					port = Integer.parseInt(s);
				} catch (Exception ex) {
					ex.printStackTrace();
					port = 1099;
				}
			}
		}

		// Read the replication.cfg file
		try {
			File file = new File(ersHome + "etc/replication.cfg");
			if (!file.exists()) {
				System.out.println("Cannot find replication.cfg in " + ersHome);
				System.exit(1);
			}

			properties = new Properties();
			FileInputStream in = new FileInputStream(file);
			properties.load(in);
			in.close();
		} catch (IOException ix) {
			ix.printStackTrace();
			System.exit(1);
		}

		// Get connection properties for the primary
		String primaryURL = properties.getProperty("replic.master.JDBCConnectionURL");
		String primaryUser = properties.getProperty("replic.master.user");
		String primaryPass = properties.getProperty("replic.master.password");

		if (primaryURL == null || primaryUser == null || primaryPass == null) {
			System.out.println("Invalid primary URL/user/password");
			System.exit(1);
		}

		boolean dropTable = line.hasOption("x");

		// Get connection properties for the replicants
		s = properties.getProperty("replic.slave.JDBCConnectionURL");

		if (s != null) {
			replicantURL = split(s, ",");
		}

		s = properties.getProperty("replic.slave.user");

		if (s != null) {
			replicantUser = split(s, ",");
		}

		s = properties.getProperty("replic.slave.password");

		if (s != null) {
			replicantPass = split(s, ",");
		}

		String ersSchema = properties.getProperty("replic.schema");

		if (replicantURL == null || replicantUser == null || replicantPass == null) {
			System.out.println("Bad replicant configuration");
			System.exit(1);
		}

		if (replicantURL.length != replicantUser.length || replicantURL.length != replicantPass.length) {
			System.out.println("Bad replicant configuration");
			System.exit(1);
		}

		// Create the primary and replicant DB connections
		Connection primaryConnection = getConnection(primaryURL, primaryUser, primaryPass);
		Connection[] replicants = new Connection[replicantURL.length];

		for (i = 0; i < replicantURL.length; i++) {
			replicants[i] = getConnection(replicantURL[i], replicantUser[i], replicantPass[i]);
		}

		boolean schemaSupport;
		s = properties.getProperty("schema_support");
		if (s != null) {
			schemaSupport = s.equals("true");
		} else {
			schemaSupport = false;
		}

		String[] s2;

		if ((fileName = line.getOptionValue("f")) != null) {
			try {
				File f = new File(fileName);
				if (f.exists()) {
					LineNumberReader in = new LineNumberReader(new FileReader(f));
					while ((s = in.readLine()) != null) {
						s = s.trim();
						if (s.length() == 0) {
							continue;
						}
						if (s.charAt(0) == '#') {
							continue;
						}
						// Check for a custom column name on the same line as the table (table,column) from ERSAddTable -
						// ignore the column name
						if (s.indexOf(",") >= 0) {
							s2 = split(s, ",");
							s = s2[0];
						}
						try {
							new ERSRemoveTable(s, primaryConnection, replicants, dropTable, schemaSupport, ersSchema, host, port);
						} catch (SQLException sx) {
							sx.printStackTrace();
						}

					}
				}
			} catch (IOException iox) {
				iox.printStackTrace();
			}
		} else {
			fileArgs = line.getArgs();
			// Process each table
			for (i = 0; i < fileArgs.length; i++) {
				try {
					if (fileArgs[i].indexOf(",") >= 0) {
						s2 = split(fileArgs[i], ",");
						s = s2[0];
					}
					new ERSRemoveTable(s, primaryConnection, replicants, dropTable, schemaSupport, ersSchema, host, port);
				} catch (SQLException sx) {
					sx.printStackTrace();
				}
			}
		}

		if (!quiet) {
			System.out.println("\nDone\n");
		}
	}

}

