// Customer record class
// This class is used to store and access customer data from the database
import java.sql.*;
import java.sql.Types;

public class Customer {
  private Connection conn;
  private PreparedStatement insertNewCustomer;
  private CallableStatement getNewID;
  public static CallableStatement checkZip;
  public static CallableStatement checkID;
  public Customer(Connection c) {
    conn = c;
    try {
      insertNewCustomer =conn.prepareStatement("INSERT INTO customers VALUES (?, ?, ?, ?, ?)");
      getNewID = conn.prepareCall ("{call getNewID (?)}");
      checkID = conn.prepareCall ("{call checkID (?,?)}");
      checkZip = conn.prepareCall ("{call checkZip (?, ?)}");
    } catch (SQLException e) {
      System.err.println ("Cannot create statements");
    }
  }
  public String insertNewCustomer (String lname, String fname,
      String pnum, String addr, String zip)
      throws InsertFailedException, SQLException {
    String newID;
    if ((newID = getNewID ()) == null) {
      throw new InsertFailedException ("could not get new ID");
    }
    insertNewCustomer.setString (1, newID);
    insertNewCustomer.setString (2, lname);
    insertNewCustomer.setString (3, fname);
    insertNewCustomer.setString (4, pnum);
    insertNewCustomer.setString (5, addr);
    insertNewCustomer.setString (6, zip);
    if (insertNewCustomer.executeUpdate() != 1) {
      throw new InsertFailedException ("could not execute insert");
    }
    return (newID);
  }
  public CustomerInfo getCustomer (String custID)
      throws SelectException, SQLException {
    if (!validateID (custID)) {
      throw new SelectException ("no customer with ID: " + custID);
    }
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery (
      "SELECT *FROM Customer WHERE CustID = " + custID);
    CustomerInfo info = new CustomerInfo ();
    info.CustomerID = rs.getString (1);
    info.LastName = rs.getString (2);
    info.FirstName = rs.getString (3);
    info.PhoneNumber = rs.getString (4);
    info.StreetAddress = rs.getString (5);
    info.Zip = rs.getString (6);

    return (info);
  }
  public static synchronized boolean validateZip (String zip)
      throws SQLException {
    checkZip.setString (1, zip);
    checkZip.registerOutParameter(2, Types.BIT);
    checkZip.executeUpdate();
    return (checkZip.getBoolean(2));

  }
  public static synchronized boolean validateID (String id)
      throws SQLException {
    checkID.setString (1, id);
    checkID.registerOutParameter(2, Types.BIT);
    checkID.executeUpdate();
    return (checkID.getBoolean(2));
  }
  private String getNewID () throws SQLException {
    getNewID.registerOutParameter (1, Types.VARCHAR);
    getNewID.executeUpdate();
    return (getNewID.getString(1));
  }
}
class InsertFailedException extends SQLException {
  public InsertFailedException () {
  }
  public InsertFailedException (String reason) {
    super (reason);
  }
}
class SelectException extends SQLException {

  public SelectException (String reason) {
    super (reason);
  }
  public SelectException () {
  }
}
