/**
 * 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.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
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.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;


/**
 *  Class to add a new replicated server to a replication scheme. This is a rewrite of ers_addslave.
 *
 * @author     Andrew Rawnsley
 */
public class ERSAddSlave extends ERS {

	/**
	 * Constructor for the ERSAddTable object
	 *
	 * @param  primaryURL        URL of the primary
	 * @param  primaryUser       User for the primary
	 * @param  primaryPass       Password for the primary
	 * @param  replicantURL      URL of the slave
	 * @param  replicantUser     User for the slave
	 * @param  replicantPass     Password for the slave
	 * @param  ersHome           eRServer home directory
	 * @throws SQLException
	 */
	public ERSAddSlave(String primaryURL, String primaryUser, String primaryPass,
			String replicantURL, String replicantUser,
			String replicantPass,
			String columnName,
			String ersHome, boolean schemaSupport) throws SQLException {

		Statement stmnt = null;
		String table;
		String line;
		String value;
		String[] s;
		String[] s2;
		int nReplicants;

		Connection replicant = null;
		Connection primary = null;

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

		try {

			if (!quiet) {
				System.out.println("Adding slave " + replicantURL);
			}

			// Get the connections, bail if either are null
			replicant = getConnection(replicantURL, replicantUser, replicantPass);
			primary = getConnection(primaryURL, primaryUser, primaryPass);

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

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

			// if the _rserv_slave_tables_ doesn't exist, create
			if (!tableExists("_rserv_slave_tables_", replicant)) {

				setupReplicant(replicant);

				// Modify the replication.cfg file
				try {
					File file = new File(ersHome + "etc/replication.cfg");
					File fileOut = File.createTempFile("ers", null);

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

					RandomAccessFile in = new RandomAccessFile(file, "r");
					PrintWriter out = new PrintWriter(new FileOutputStream(fileOut));

					while ((line = in.readLine()) != null) {
						if (line.startsWith("replic.master.ConnectionPoolSize")) {
							s = split(line, "=");
							nReplicants = Integer.parseInt(s[1]);
							out.print("replic.master.ConnectionPoolSize=");
							out.println(nReplicants + 1);
						} else if (line.startsWith("replic.master.ConnectionPoolMax")) {
							s = split(line, "=");
							nReplicants = Integer.parseInt(s[1]);
							out.print("replic.master.ConnectionPoolMax=");
							out.println(nReplicants + 1);
						} else if (line.startsWith("replic.server.ReplicInterval")) {
							s2 = getProperty(line);
							s = split(s2[1], ",");
							value = s[s.length - 1];
							out.println(line + "," + value);
						} else if (line.startsWith("replic.slave.JDBCDriver")) {
							out.println(line + ",org.postgresql.Driver");
						} else if (line.startsWith("replic.slave.ConnectionPoolSize")) {
							s2 = getProperty(line);
							s = split(s2[1], ",");
							value = s[s.length - 1];
							out.println(line + "," + value);
						} else if (line.startsWith("replic.slave.ConnectionPoolMax")) {
							s2 = getProperty(line);
							s = split(s2[1], ",");
							value = s[s.length - 1];
							out.println(line + "," + value);
						} else if (line.startsWith("replic.slave.ConnectionUseCount")) {
							s2 = getProperty(line);
							s = split(s2[1], ",");
							value = s[s.length - 1];
							out.println(line + "," + value);
						} else if (line.startsWith("replic.slave.ConnectionTimeout")) {
							s2 = getProperty(line);
							s = split(s2[1], ",");
							value = s[s.length - 1];
							out.println(line + "," + value);
						} else if (line.startsWith("replic.slave.JDBCConnectionURL")) {
							out.println(line + "," + replicantURL);
						} else if (line.startsWith("replic.slave.user")) {
							out.println(line + "," + replicantUser);
						} else if (line.startsWith("replic.slave.pass")) {
							out.println(line + "," + replicantPass);
						} else if (line.startsWith("replic.schema")) {
						    s = split(line,"=");
							setErsSchema(s[1]);
						} else {
							out.println(line);
						}

					}

					out.close();
					in.close();

					// Rename the tmp to the new
					file.delete();
					fileOut.renameTo(file);

				} catch (IOException ix) {
					ix.printStackTrace();
					return;
				} finally {
					try {
						stmnt.close();
					} catch (Exception ex) {}
				}

			}

			// See if there are any tables to copy
			stmnt = primary.createStatement();
			ResultSet rs = stmnt.executeQuery("SELECT tname FROM "+createRelName("_rserv_tables_"));
			while (rs.next()) {
				table = rs.getString(1);
				copyTable(table, columnName, primary, replicant);
			}
		} finally {
			try {
				stmnt.close();
			} catch (Exception ex) {}
			if (replicant != null) {
				replicant.close();
			}
		}

	}

	/**
	 *  Add a slave to the replication scheme
	 *
	 * @param  args  The command line arguments
	 */
	public static void main(String[] args) {

		int i;
		Properties properties = null;
		String replicantURL = null;
		String replicantUser = null;
		String replicantPass = null;
		String replicantDb;
		String replicantServer;
		String replicantPort;

		// Set up the command line options
		Options options = new Options();
		options.addOption("u", "uniq", true, "Column name for the unique sequence id (default _ers_uniq)");
		options.addOption("d", "ers_home", true, "Install directory for eRServer (default /opt/erserver)");
		options.addOption("q", "quiet", false, "Run quiet");
		options.addOption("ss", "slaveserver", true, "Slave host");
		options.addOption("su", "slaveuser", true, "Slave user");
		options.addOption("sp", "slavepass", true, "Slave password");
		options.addOption("sb", "slavedb", true, "Slave db");
		options.addOption("so", "slaveport", true, "Slave port");

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

		// Yell at user
		if (args.length == 0) {
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("USAGE: java org.postgresql.ers.ERSAddSlave <options>", options);
			return;
		}

		String uniq = line.getOptionValue('u', "_ers_uniq");
		String ersHome = line.getOptionValue('d', "/opt/erserver/");
		quiet = line.hasOption('q');
		replicantServer = line.getOptionValue("ss");
		replicantDb = line.getOptionValue("sb");
		replicantUser = line.getOptionValue("su");
		replicantPass = line.getOptionValue("sp");
		replicantPort = line.getOptionValue("so", "5432");

		// Complain if required parameters are null
		if (replicantServer == null || replicantDb == null || replicantUser == null || replicantPass == null) {
			HelpFormatter formatter = new HelpFormatter();
			formatter.printHelp("USAGE: java org.postgresql.ers.ERSAddSlave <options>", options);
			return;
		}

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

		if (!quiet) {
			System.out.println("Using " + ersHome + " as ERS installation directory");
			System.out.println("Using " + uniq + " as ERS unique column name");
		}

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

			// Read into a properties list
			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);
		}

		replicantURL = "jdbc:postgresql://" + replicantServer + ":" + replicantPort + "/" + replicantDb;

		boolean schemaSupport;
		String s = properties.getProperty("schema_support");
		if (s != null) {
			schemaSupport = s.equals("true");
		} else {
			schemaSupport = false;
		}
		// Add the slave
		try {
			new ERSAddSlave(primaryURL, primaryUser, primaryPass, replicantURL, replicantUser, replicantPass, uniq, ersHome, schemaSupport);
		} catch (SQLException sx) {
			sx.printStackTrace();
		}

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

}

