import java.sql.ResultSet;
import java.util.Vector;

public class Cabs {
    public static final String tName = "Cabs"; // Name of the this table

    // Establish abbreviations for calling methods in other modules:
    private static Lab3Props per = new Lab3Props();
      // All general utilities for dealing with persistent data
    private static Lab3Props out = per;
      // For output to terminal or browser or other logging/display device

    public static int mayMakeTable() {
	String fspec = "CabID int, Name varchar(8), PRIMARY KEY(CabID)";
	int nrows = per.mayMakeTable(tName, fspec);
	if (nrows>0) {
	    out.printbr("Table " + tName + " exists and has " + nrows +
			" already.");
	    return nrows;
	}
	if (nrows<0) {
	    out.printbr("Bug: Table wasn't created");
	}
	out.printbr("Table " + tName + " exists, but it's empty.");
	String[] cabNames = loadCabData();
	cabDataFillTable(cabNames);
	return per.tableNrows(tName);
    }

    /* Load, from the properties file, the starting-configuration
        of cab names. Return value is array of strings. */
    public static String[] loadCabData() {
	String delims = per.getProp("cabsdelims");
	out.printbr("delims = " + Sexpr1.toSexpr(delims));
	if (delims.length()!=1) {
	    out.printbr("*** Length of cabsdelims not 1, aborting!");
	    return null;
	}
	String del1 = String.valueOf(delims.charAt(0));
	String cabs = per.getProp("cabs");
	out.printbr("cabs = " + cabs);
	String[] names = per.parseSlashTokens(cabs, del1);
	out.printbr("names = " + Sexpr1.toSexpr(names));
	return names;
    }

    /* Given ud which is array of strings, each the name of a cab,
        copy each cab name new record of table, except if cab already there.
    */
    public static void cabDataFillTable(String[] ud) {
	out.printbr("Copying cab-data to table...");
	for (int ix=0; ix<ud.length; ++ix) {
	    String name = ud[ix];
	    out.printbr("    name=" + name);
	    add(name);
	}
	out.println("...done copying cab-data to table.");
    }

    /* Hard-coded for the Cabs table with standard field specs.
       First make sure the cabname isn't already listed in the table.
       Add new record to table. */
    public static void add(String cabname) {
	add(cabname, false); }
    public static void add(String cabname, boolean trace) {
	if (trace) out.print("* Cabs.add: ");
	int icnt =  countMatchingName(cabname);
	if (icnt>0) {
	    out.printbr("*** Already cab called '" + cabname + "', can't " +
			"add new cab by same name.");
	    return;
	}
	int maxSeq = getMaxSeq();
	String sql = "INSERT INTO " + tName + " VALUES (" + (maxSeq+1) +
	    ", '" + cabname + "')";
	if (trace) out.printbr("sql = " + sql);
	int nup = per.doUpdate(sql);
	if (nup!=1) {
	    out.printbr("*** Number of records changed is " + nup +
			" instead of 1.");
	}
    }

    /* Hard-coded for the Cabs table with standard field specs.
       Count how many records have matching name. */
    public static int countMatchingName(String cabname) {
	return countMatchingName(cabname, false); }
    public static int countMatchingName(String cabname, boolean trace) {
	if (trace) out.printbr("* Cabs.countMatchingName(" + cabname +"):");
	String sql = "SELECT count(*) FROM " + tName + " WHERE Name='" +
	    cabname + "'";
	if (trace) out.println("sql = " + sql);
	ResultSet rs = per.doQuery(sql);
	int nval = per.rsGetSingleInt(rs, 0, false);
	if (trace) out.printbr("Parsed number = " + nval);
	return(nval);
    }

    /* Hard-coded for the Cabs table with standard field specs.
       Return largest value of Seq field, or 0 if table is empty. */
    public static int getMaxSeq() {
	return getMaxSeq(false); }
    public static int getMaxSeq(boolean trace) {
	if (trace) out.print("* Cabs.getMaxSeq: ");
	String sql = "SELECT max(CabID) FROM " + tName;
	ResultSet rs = per.doQuery(sql);
	int nval = per.rsGetSingleInt(rs, 0, false);
	if (trace) out.printbr("Result, i.e. maximum CabID field, is " + nval);
	return nval;
    }

    /* Return Vector of Vector[cabId, name] pairs for on-duty cabs.
       Note: We collect all the data and return in one big vector,
        instead of returning one-at-a-time via an enumeration, to avoid
	the problem whereby somebody does another SQL query before the
	enumeration is finished causing this result set to be closed
	causing invalid cursor state when attempt is made later to pick up
	this enumeration where it left off. */
    public static Vector getOndutyNames() {
	Vector res = new Vector();
	String sql = "SELECT * FROM Cabs";
	ResultSet rs = per.doQuery(sql);
	try {
	    while (rs.next()) { //Move to first/next row of SQL-query result
		String sCabID = rs.getString("CabID");
		String sName = rs.getString("Name");
		System.out.println("CabID: " + sCabID + " // Name: " + sName);
		int iCabID = Integer.parseInt(sCabID);
		Vector pair = new Vector();
		pair.add(new Integer(iCabID));
		pair.add(sName);
		res.add(pair);
	    }
	} catch (java.sql.SQLException ex) {
	    throw new java.util.MissingResourceException
		("Got an exception while trying to collect list of cabs: " +
		 ex, "","");
	}
	return res;
    }

    /* Given name of cab, look it up in table and return cab ID# */
    public static int lookupName(String cabName) {
	return lookupName(cabName, true); }
    public static int lookupName(String cabName, boolean trace) {
	String sql = "SELECT CabID FROM Cabs where Name='" + cabName + "'";
	if (trace) out.println("sql = " + sql);
	ResultSet rs = per.doQuery(sql);
	int cabID = per.rsGetSingleInt(rs, 0, false);
	System.out.println("For cabName=" + cabName + " cabID=" + cabID);
	return cabID;
    }

    public static void main(String args[]) {
	Vector pairs = getOndutyNames();
	System.out.println("All cabs as [id,name] pairs: " +
			   Sexpr1.toSexpr(pairs));
	while (true) {
	    System.out.print("Lookup cab name:");
	    String cabName = MyInput.readString(null);
	    if (cabName==null) break;
	    int cabID = lookupName(cabName);
	    System.out.println("That cab is number " + cabID);
	}
    }

}
