package org.hibernate.examples.quickstart;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

/**
 * Simple Servlet used to show how using Hibernate from a Servlet
 */
public class TestServlet extends HttpServlet {

    /**
     * Hibernate SessionFactory instance
     */
    private SessionFactory sessionFactory;

    /**
     * Hibernate Session instance
     */
    private Session session;

    /**
     * Hibernate Transaction
     */
    private Transaction transaction;

    /**
     * execute GET action
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        try {
            // Initialize Hibernate (Configuration and SessionFactory)
            initHibernate();

            // Prepare out
            response.setContentType("text/html");

            PrintWriter out = response.getWriter();

            // Create some Cats
            beginTransaction();
            createCats(out);
            endTransaction(true);

            // Select all Cats
            beginTransaction();
            selectAllCats(out);
            endTransaction(false);

            // Select female Cats
            beginTransaction();
            selectFemaleCats(out);
            endTransaction(false);

            // print "Servlet OK" at the end (everything went OK)
            out.println("Servlet is OK");
        } catch (HibernateException e) {
            throw new ServletException(e);
        }
    }

    /**
     * Creates and Persists Cats in DB
     * @param out PrintWriter
     */
    public void createCats(PrintWriter out) throws HibernateException {
        out.print("<h3>Creating Cats:</h3>");
        out.println("CREATING 'Princess'...<br/>");

        Cat princess = new Cat();
        princess.setName("Princess");
        princess.setSex('F');
        princess.setWeight(7.4f);
        session.save(princess);

        out.println("CREATING 'Max'...<br/>");

        Cat max = new Cat();
        max.setName("Max");
        max.setSex('M');
        max.setWeight(8.1f);
        session.save(max);

        out.println("CREATING 'Sophie'...<br/>");

        Cat sophie = new Cat();
        sophie.setName("Sophie");
        sophie.setSex('F');
        sophie.setWeight(4.1f);
        session.save(sophie);
    }

    /**
     * Select All the Cats
     * @param out PrintWriter
     */
    public void selectAllCats(PrintWriter out) throws HibernateException {
        out.print("<h3>Retrieving all Cats:</h3>");

        String queryString = "select cat from Cat as cat";
        Query query = session.createQuery(queryString);

        for (Iterator it = query.iterate(); it.hasNext();) {
            Cat cat = (Cat) it.next();
            out.println("CAT: " + cat.getName() + " (" + cat.getSex() + ", " +
                cat.getWeight() + ")<br/>");
        }
    }

    /**
     * Select all Female Cats
     * @param out PrintWriter
     */
    public void selectFemaleCats(PrintWriter out) throws HibernateException {
        out.print("<h3>Retrieving female Cats:</h3>");

        String queryString = "select cat from Cat as cat where cat.sex = :sex";
        Query query = session.createQuery(queryString);
        query.setCharacter("sex", 'F');

        for (Iterator it = query.iterate(); it.hasNext();) {
            Cat cat = (Cat) it.next();
            out.println("CAT: " + cat.getName() + " (" + cat.getSex() + ", " +
                cat.getWeight() + ")<br/>");
        }
    }

    // Helper Methods
    private void initHibernate() throws HibernateException {
        // Load Configuration and build SessionFactory
        sessionFactory = new Configuration().configure().buildSessionFactory();
    }

    private void beginTransaction() throws HibernateException {
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }

    private void endTransaction(boolean commit) throws HibernateException {
        if (commit) {
            transaction.commit();
        } else {
            // Don't commit the transaction, can be faster for read-only operations
            transaction.rollback();
        }

        session.close();
    }
}
