/**
 * 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 java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;

import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

//the jakarta command line processing tools
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.Options;

/**
 *  Class to set up the eRServer package.
 *
 * @author     ronz
 */
public class ERSRemove extends ERS {

	/**
	 *Constructor for the ERSSetup object
	 *
	 * @param  ersHome           eRServer home directory
	 * @param  adminUser         Admin user name
	 * @param  adminPassword     Parameter
	 * @param  removeCols        Parameter
	 * @exception  SQLException
	 */
	public ERSRemove(String adminUser, String adminPassword, boolean removeCols, String ersHome) throws SQLException {

		Statement stmnt = null;
		Properties properties = null;

		String primaryURL;
		String primaryUser;
		String primaryPass;

		Connection primary = null;
		Connection replicant = null;
		Connection admin = null;
		File configFile = null;
		File setvarFile;

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

		// Read the replication.cfg file
		try {
			configFile = new File(ersHome + "etc/replication.cfg");

			if (!configFile.exists()) {
				System.out.println("Cannot find replication.cfg in " + ersHome);
				System.exit(1);
			}

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

		setErsSchema(properties.getProperty("erserver_schema"));

		primaryURL = properties.getProperty("replic.master.JDBCConnectionURL");
		primaryUser = properties.getProperty("replic.master.user");
		primaryPass = properties.getProperty("replic.master.password");

		if (adminUser == null) {
			adminUser = primaryUser;
		}

		if (adminPassword == null) {
			adminPassword = primaryPass;
		}

		try {
			// Create the primary, replicant, and admin DB connections, bail if any are null
			primary = getConnection(primaryURL, primaryUser, primaryPass);
			admin = getConnection(primaryURL, adminUser, adminPassword);

			if (primary == null) {
				System.out.println("Bad master URL/user/password");
				return;
			}

			if (admin == null) {
				System.out.println("Bad master URL/superuser/superuser password");
				return;
			}

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

			primary.setAutoCommit(false);
			admin.setAutoCommit(false);

			String[] replicantURLs = split(properties.getProperty("replic.slave.JDBCConnectionURL"), ",");
			String[] replicantUsers = split(properties.getProperty("replic.slave.user"), ",");
			String[] replicantPasswords = split(properties.getProperty("replic.slave.password"), ",");

			for (int i = 0; i < replicantURLs.length; i++) {
				if (!quiet) {
					System.out.println("Removing slave " + replicantURLs[i]);
				}

				replicant = getConnection(replicantURLs[i], replicantUsers[i], replicantPasswords[i]);
				if (replicant == null) {
					if (!quiet) {
						System.out.println("Invalid URL. Skipping.");
					}
					continue;
				}

				if (removeCols) {
					if (!quiet) {
						System.out.println("Stripping control columns.");
					}
					stripColumns(createRelName("_rserv_slave_tables_"), replicant);
				}

				try {
					removeReplicant(replicant);
				} catch (Exception ex) {
					ex.printStackTrace();
				} finally {
					try {
						replicant.close();
					} catch (Exception ex) {}
				}

			}

			if (!quiet) {
				System.out.println("\nRemoving master tables");
			}

			try {
				primary.setAutoCommit(false);
				stmnt = primary.createStatement();
				if (removeCols) {
					if (!quiet) {
						System.out.println("Stripping control columns.");
					}
					stripColumns(createRelName("_rserv_tables_"), primary);
				}

				stmnt.execute("DROP TABLE "+createRelName("_rserv_servers_"));
				stmnt.execute("DROP TABLE "+createRelName("_rserv_tables_"));
				stmnt.execute("DROP TABLE "+createRelName("_rserv_log_1_"));
				stmnt.execute("DROP TABLE "+createRelName("_rserv_log_2_"));
				stmnt.execute("DROP TABLE "+createRelName("_rserv_sync_"));
				stmnt.execute("DROP SEQUENCE "+createRelName("_rserv_sync_seq_"));
				stmnt.execute("DROP SEQUENCE "+createRelName("_rserv_active_log_id_"));
				stmnt.execute("DROP SEQUENCE "+createRelName("_rserv_old_log_status_"));
				//stmnt.execute("DROP SEQUENCE _rserv_servers__server_seq");
				stmnt.execute("DROP VIEW "+createRelName("_ers_class_attr"));
				if (relationExists(createRelName("_rserv_failover_constraints_"), primary)) {
					stmnt.execute("DROP TABLE "+createRelName("_rserv_failover_constraints_"));
				}
				primary.commit();
			} catch (SQLException sx) {
				sx.printStackTrace();
				primary.rollback();
			} finally {

				try {
					stmnt.close();
				} catch (SQLException sx) {}
			}

			if (!quiet) {
				System.out.println("Master database replication removal completed\n");
			}

			try {
				admin.setAutoCommit(false);
				stmnt = admin.createStatement();

				stmnt.execute("set transaction isolation level serializable");
				stmnt.execute("DROP FUNCTION "+createRelName("_rserv_log_()")+" CASCADE");
				stmnt.execute("DROP FUNCTION "+createRelName("_rserv_sync_(int4)")+" CASCADE");
				stmnt.execute("DROP FUNCTION "+createRelName("_rserv_debug_(int4)")+" CASCADE");
				stmnt.execute("DROP FUNCTION "+createRelName("_rserv_lock_altid_(int4)")+" CASCADE");
				stmnt.execute("DROP FUNCTION "+createRelName("_rserv_unlock_altid_(int4)")+" CASCADE");
				stmnt.execute("DROP FUNCTION "+createRelName("_pte_get_snapshot_()")+" CASCADE");
				stmnt.execute("DROP FUNCTION "+createRelName("_pte_set_snapshot_(text)")+" CASCADE");
				admin.commit();
			} catch (SQLException sx) {
				sx.printStackTrace();
				admin.rollback();
			} finally {
				try {
					stmnt.close();
				} catch (Exception ex) {}
			}

			if (!quiet) {
				System.out.println("Replication function removal completed\n\n");
			}
		} finally {

			if (primary != null) {
				primary.close();
			}
			if (admin != null) {
				admin.close();
			}
		}

		try {
			configFile.delete();
			setvarFile = new File(ersHome + "bin/ers_setvars");

			if (setvarFile.exists()) {
				setvarFile.delete();
			}

			if (!quiet) {
				System.out.println("Configuration files removed\n\n");
			}
		} catch (Exception iox) {
			iox.printStackTrace();
			if (!quiet) {
				System.out.println("Configuration files not removed\n\n");
			}
		}

		if (!quiet) {
			System.out.println("eRServer removal completed\n");
		}
	}

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

		String adminUser;
		String adminPass;

		Options options = new Options();
		options.addOption("pu", "pgsuperuser", true, "User");
		options.addOption("pp", "pgsuperpass", true, "Password");
		options.addOption("q", "quiet", false, "quiet mode");
		options.addOption("rc", "remove-column", false, "Strip _ers_uniq (or equivelant) column from tables");

		options.addOption("d", "ers_home", true, "Install directory for eRServer (default /opt/erserver)");

		//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;
		}

		// get options
		String ersHome = line.getOptionValue("d", "/opt/erserver/");

		adminUser = line.getOptionValue("pu");
		adminPass = line.getOptionValue("pp");

		String s = line.getOptionValue("q");
		if (s != null) {
			setQuiet(true);
		}

		boolean removeCols = false;
		if (line.hasOption("rc")) {
			removeCols = true;
		}

		String[] newArgs = line.getArgs();
		if (newArgs.length == 0) {
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("USAGE: java org.postgresql.ers.ERSRemove <options> go", options);
			return;
		}

		if (!newArgs[0].equals("go")) {
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("USAGE: java org.postgresql.ers.ERSRemove <options> go", options);
			return;
		}

		try {
			new ERSRemove(adminUser, adminPass, removeCols, ersHome);
		} catch (SQLException sx) {
			sx.printStackTrace();
		}

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

	/**
	 *  Strip the unique control column from tables
	 *
	 * @param  controlTable  Control table to get values from
	 * @param  c             Connection to use
	 */
	private void stripColumns(String controlTable, Connection c) {

		Statement stmnt = null;
		Statement stmnt2 = null;
		String columnName;
		String table;
		String seqName;
		int pos;

		try {
			stmnt = c.createStatement();
			stmnt2 = c.createStatement();
			ResultSet rs = stmnt.executeQuery("SELECT cname, tname FROM " + controlTable);
			while (rs.next()) {
				try {
					columnName = rs.getString(1);
					table = rs.getString(2);
					pos = table.indexOf(".");
					if (pos >= 0) {
						seqName = table.substring(0,pos)+"._ers_"+table.substring(pos+1)+"_seq";
					} else {
						seqName = "_ers_"+table+"_seq";
					}
					stmnt2.execute("ALTER TABLE " + table + " DROP COLUMN " + columnName + " CASCADE");
					stmnt2.execute("DROP SEQUENCE "+seqName);
				} catch (SQLException ex) {
					ex.printStackTrace();
				}
			}
		} catch (SQLException sx) {
			sx.printStackTrace();
		} finally {
			try {
				if (stmnt != null) {
					stmnt.close();
				}
			} catch (Exception ex) {}
			try {
				if (stmnt2 != null) {
					stmnt2.close();
				}
			} catch (Exception ex) {}
		}

	}
}

