import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

import COM.odi.*;
import COM.odi.util.*;
import COM.odi.util.query.*;

public class CatalogBasicServlet extends HttpServlet {

  private static String dbName = "catalog.odb";
  /* The database that this CatalogManager is operation against. */
  private static Database db = null;

  // Class storage for the HOLLOW roots.
  private static OSTreeSet catalogRoot = null;
  private static OSVectorList booksRoot = null;
  private static OSVectorList moviesRoot = null;

  private static String CATALOG_ROOT_NAME = "Catalog";
  private static String BOOKS_ROOT_NAME = "Books";
  private static String MOVIES_ROOT_NAME = "Movies";

  private static Session aSession = null;

  public void init(ServletConfig config)
    throws ServletException {

    // Always pass the ServletConfig object to the super class
    super.init(config);
    System.out.println("Starting init.");
    aSession = Session.create(null, null);
    aSession.join();
    String threadName = Thread.currentThread().getName();
    String sessionName = Session.getCurrent().getName();
    System.out.println("threadName = " + threadName);
    System.out.println("sessionName = " + sessionName);
    createDatabase(dbName);
    getRoots();
    addIndexToCatalogItems();
    System.out.println("Exiting init.");
  }

  //Process the HTTP Get request
  public void doGet(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    doPost(request, response);
  }

  //Process the HTTP Post request
  public void doPost(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {

    // Construct a query on all Book classes to find out how
    //  many books there are in the CatalogItems.
    Query productQuery = new Query(CatalogItem.class,
      "getProductType() == \"Movie\"");

    // Start transaction.
    Transaction tr = Transaction.begin(ObjectStore.READONLY);

    Collection result = productQuery.select(catalogRoot);

    response.setContentType("text/html");
    PrintWriter out = response.getWriter();

    out.println("<html>");
    out.println("<head><title>CatalogBasicServlet</title></head>");
    out.println("<body>");

    out.println("Query Found " + result.size() + " Movies." + "<BR>");
    out.println("<BR>");
    Iterator iterator = result.iterator();
    int i = 0;
    while(iterator.hasNext()) {
      i++;
      CatalogItem queryCatalogItem = (CatalogItem)iterator.next();
      Movie queryMovie = (Movie) queryCatalogItem.getProduct();
      out.println("Movie " + i + " is : " + queryMovie.getName() + "<BR>");
      out.println("description = " + queryMovie.getDescription() + "<BR>");
      out.println("category = " + queryMovie.getGenre()+ "<BR>");
      out.println("rating = " + queryMovie.getRating()+ "<BR>");
      out.println("format = " + queryMovie.getFormatType()+ "<BR>");
      out.println("actors = " + queryMovie.getTalent()+ "<BR>");
      out.println("quantity on hand = " +
        queryCatalogItem.getQuantity()+ "<BR>");
      out.println("<BR>");
    }

    out.println("</body></html>");
    out.close();

    tr.commit(ObjectStore.RETAIN_HOLLOW);
  }

//Get Servlet information
  public String getServletInfo() {

    return "BasicServlet Information";
  }
  // This method will create and open the database that is specified
  //   on the command line when the Java application is invoked.
  public static void createDatabase(String dbName) {
    System.out.println("Starting createDatabase("+dbName+")");

    // Attempt to open and destroy the database specified on the
    // command line.  This ensures that that program creates a
    // new database each time the application is called.
    try {
      Database.open(dbName, ObjectStore.OPEN_UPDATE).destroy();
    } catch (DatabaseNotFoundException e) {
    }

    // Create a new database.
    db = Database.create(dbName,
       ObjectStore.ALL_READ | ObjectStore.ALL_WRITE);

    // Build the data and store it in the OSTreeSet before
    //  a transaction is started.
    // Create books.
    String authors[] = {"James Goodwill"};
    Book servletBook = new Book("Developing Java Servlets",
      "Cool book on Servlets", "Sams Publishing", authors);
    String authors2[] = {"Michael Morrison", "et. all"};
    Book javaBook = new Book("Java Unleashed, Second Edition",
      "Cool book on Java", "Sams Publishing", authors2);

    // Create movies.
    String talent[] = {"Will Smith", "Tommy Lee Jones",
      "Linda Fiorentino"};
    Movie menInBlack = new Movie("Men in Black",
      "Funny alien invasion movie", "Sci-Fi/Horror",
      "VHS", "PG-13", talent);
    String talent2[] = {"Harrison Ford", "Gary Oldman"};
    Movie airForceOne = new Movie("Air Force One",
      "Thriller about hijacking of Air Force One", "Action/Adventure",
      "VHS", "PG-13", talent2);

    // Create instances catalog items.
    CatalogItem book1 = new CatalogItem(servletBook, 2);
    CatalogItem book2 = new CatalogItem(javaBook, 1);
    CatalogItem movie1 = new CatalogItem(menInBlack, 1);
    CatalogItem movie2 = new CatalogItem(airForceOne, 3);

		// Start an update transaction.
		Transaction tr = Transaction.begin(ObjectStore.UPDATE);

    catalogRoot = new OSTreeSet(db);
    catalogRoot.add(book1);
    catalogRoot.add(book2);
    catalogRoot.add(movie1);
    catalogRoot.add(movie2);
    db.createRoot("Catalog", catalogRoot);

    booksRoot = new OSVectorList(2);
    booksRoot.addElement(book1);
    booksRoot.addElement(book2);
    db.createRoot("Books", booksRoot);

    moviesRoot = new OSVectorList(2);
    moviesRoot.addElement(movie1);
    moviesRoot.addElement(movie2);
    db.createRoot("Movies", moviesRoot);

    // all database references will be STALE.
    tr.commit();
    System.out.println("Ending createDatabase("+dbName+")");
  }

  // Populate the HOLLOW Roots.
  public static void getRoots() {
    // Start a read-only transaction:
    Transaction tr = Transaction.begin(ObjectStore.READONLY);

    catalogRoot = (OSTreeSet)db.getRoot(CATALOG_ROOT_NAME);
    booksRoot = (OSVectorList)db.getRoot(BOOKS_ROOT_NAME);
    moviesRoot = (OSVectorList)db.getRoot(MOVIES_ROOT_NAME);

    // End the read-only transaction.  This makes the roots
    //  HOLLOW so later when used in a transaction, they don't
    //  have to be read from the database.
    tr.commit(ObjectStore.RETAIN_HOLLOW);
  }

  public static void addIndexToCatalogItems() {

    // Start transaction.
    Transaction tr = Transaction.begin(ObjectStore.UPDATE);

    catalogRoot.addIndex(CatalogItem.class, "getProductType()");

    tr.commit(ObjectStore.RETAIN_HOLLOW);
  }
  public void destroy() {
    super.destroy();
    // Insure shutdown is performed even if exception is caught.
    System.out.println("Closing database & terminating session.");
    db.close();
    aSession.terminate();
  }
}

