// OrderEBR.java
package org.objectweb.jonas.stests.appli;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.Vector;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.FinderException;
import javax.ejb.RemoveException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.objectweb.jonas.common.Log;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;

/**
 *
 */
public class OrderEBR implements EntityBean {

    static private Logger logger = null;

    // ------------------------------------------------------------------
    // State of the bean.
    //
    // ------------------------------------------------------------------

    // Publically accessible member data that will be persisted
    public String ivWarehouseID;
    public int ivDistrictID;
    public Integer ivCustomerID;
    public float ivOrderID;
    public int ivNumberOfOrderLines;
    //A Vector of OrderDetail objects belonging to the Order
    public Vector ivOrderItems;
    // private variables
    private transient boolean isDirty;
    private transient EntityContext ctx;
    // (The DataSource can be shared among all instances)
    protected static DataSource dataSource = null;
    // table names
    private static String ordersTable =  null;
    private static String orderlinesTable =  null;
    // ------------------------------------------------------------------
    // EntityBean implementation
    // ------------------------------------------------------------------

    public boolean isModified() {
	return isDirty;
    }

    public void setModified(boolean flag) {
	isDirty = flag;
    }

    public void setEntityContext(EntityContext ctxt) {
        if (logger == null) {
            logger = Log.getLogger("org.objectweb.jonas_tests");
        }
        logger.log(BasicLevel.DEBUG, "");
        ctx = ctxt;
        if ( ordersTable == null) {
            try {
                initialContext = new InitialContext();
                ordersTable = (String) initialContext.lookup("java:comp/env/OrderTableName");
                orderlinesTable = (String) initialContext.lookup("java:comp/env/OrderlineTableName");
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, "cannot lookup env-entry "+e);
                System.exit(2); // stop all
            }
        }
    }

    public void unsetEntityContext() {
        logger.log(BasicLevel.DEBUG, "");
        ctx = null;
    }

    static final String tableName = "orderOrderEBR";


    public void ejbRemove() throws RemoveException {
        logger.log(BasicLevel.DEBUG, "");
        Connection con = null;
        Statement stmt = null;
        try {
            con = getConnection();
            OrderID pk = (OrderID) ctx.getPrimaryKey();

            // Delete all the order line records
            String deleteLineSQL = "delete from " + orderlinesTable + "  where " +
                "olwid = '" + pk.ivWarehouseID + "' " +
                "and oldid = " + pk.ivDistrictID + " " +
                "and oloid = " + pk.ivOrderID;
            stmt = con.createStatement();
            int lineCount = stmt.executeUpdate(deleteLineSQL);
            if (lineCount == 0) {
                throw new RemoveException ("Failed to delete bean from database lineCount == 0");
            }
            stmt.close();

            // Delete the order record
            String deleteOrderSQL = "delete from " + ordersTable + " where " +
                "owid = '" + pk.ivWarehouseID + "' " +
                "and odid = " + pk.ivDistrictID + " " +
                "and ooid = "  + pk.ivOrderID;
            stmt = con.createStatement();
            int orderCount = stmt.executeUpdate(deleteOrderSQL);
            stmt.close();
            if (orderCount == 0) {
                throw new RemoveException ("Failed to delete" + ivOrderID + ") from database lineCount == 0");
            }

        } catch (SQLException sqe) {
            throw new RemoveException (sqe.getMessage());
        } finally {
            try {
                con.close();
            } catch (Exception ignore) {}
        }

    }

    public void ejbLoad() {
        logger.log(BasicLevel.DEBUG, "");
        //Get the primary key from the context object.
        OrderID pk = (OrderID) ctx.getPrimaryKey();

        Connection con = null;
        Statement stmt = null;

        try{
            con = getConnection();

            // Create a new Vector to hold order lines.
            // Retrieve all the order lines that match the supplied primary key.
            // For each order line, create a new OrderDetail object and store it on the Vector.
            // Replace the existing ivOrderItems with the new Vector

            Vector newOrderLines = new Vector();
            String selectLineSQL = "select * from " + orderlinesTable + " where " +
                "olwid = '" + pk.ivWarehouseID + "' " +
                "and oldid = " + pk.ivDistrictID + " " +
                "and oloid = " + pk.ivOrderID;
            stmt = con.createStatement();
            ResultSet rsLines = stmt.executeQuery(selectLineSQL);
            while(rsLines.next()){
                Integer itemID = new Integer(rsLines.getInt("OLIID"));
                float amount = rsLines.getFloat("OLAMNT");
                int qty = rsLines.getInt("OLQTY");
                int lineNumber = rsLines.getInt("OLNBR");
                OrderDetail od = new OrderDetail(itemID, amount, qty);
                od.setLineNumber(lineNumber);
                newOrderLines.addElement(od);
            }
            rsLines.close();
            stmt.close();

            ivOrderItems = newOrderLines;
            ivNumberOfOrderLines = ivOrderItems.size();

            // Retrieve the order header information from the orders table and
            // replace the order instance variables
            //
            String selectOrderSQL = "select * from " + ordersTable + " where " +
                "owid = '" + pk.ivWarehouseID + "' " +
                "and odid = " + pk.ivDistrictID + " " +
                "and ooid = "  + pk.ivOrderID;
            stmt = con.createStatement();
            ResultSet rsOrder = stmt.executeQuery(selectOrderSQL);
            if(rsOrder.next()){
                ivWarehouseID = pk.ivWarehouseID;
                ivDistrictID = pk.ivDistrictID;
                ivCustomerID = new Integer(rsOrder.getInt("ocid"));
                ivOrderID = pk.ivOrderID;
            }else{
                throw new EJBException("Order " + pk.ivOrderID + " not found.");
            }
            rsOrder.close();
            stmt.close();
            setModified(false);
        } catch (SQLException sqe){
            throw new EJBException(sqe.getMessage());
        } finally {
            try {
                con.close();
            }catch (Exception ignore) {}
        }
    }


    public void ejbStore() {
        logger.log(BasicLevel.DEBUG, "");
        if ( !isModified() )
            return;
        Connection con = null;
        PreparedStatement ps = null;
        Statement stmt = null;
        try {
            con = getConnection();

            // Create an sql prepared statement that will be used for each order line.
            // The modifiable values are item id (oliid), qty (olqty), and price (olamnt).
            ps = con.prepareStatement("update ordlin set oliid = ?, olqty = ?, olamnt = ? " +
                                      "where oloid = " + ivOrderID + " " +
                                      "and oldid = " + ivDistrictID + " " +
                                      "and olwid = '" + ivWarehouseID + "' " +
                                      "and olnbr = ?");

            // Iterate through each order line and update the record into the database
            Enumeration enumer = ivOrderItems.elements();
            while(enumer.hasMoreElements()){
                OrderDetail od = (OrderDetail)enumer.nextElement();
                ps.setInt(1, od.getItemID().intValue());
                ps.setInt(2, od.getItemQty());
                ps.setFloat(3, od.getItemAmount());
                ps.setInt(4, od.getLineNumber());
                int lineCount = ps.executeUpdate();
                if (lineCount == 0) {
                    throw new EJBException("ejbStore: OrderBean (" + ivOrderID + ") not updated");
                }
            }

            // Update the order table record
            // The modifiable values are customer id (ocid) and number of order lines (olines).
            String updateSQL = "update " + ordersTable + " set " +
                "ocid = '" + ivCustomerID + "', " +
                "olines = " + ivNumberOfOrderLines + " " +
                "where owid = '" + ivWarehouseID + "' " +
                "and odid = " + ivDistrictID + " " +
                "and ooid = " + ivOrderID;

            stmt = con.createStatement();
            int orderCount = stmt.executeUpdate(updateSQL);
            if (orderCount == 0) {
                throw new EJBException("ejbStore: OrderBean (" + ivOrderID + ") not updated");
            }


            setModified(false);

        } catch (SQLException sqe) {
            throw new EJBException(sqe.getMessage());
        } finally {
            try{
                stmt.close();
                ps.close();
                con.close();
            } catch (Exception ignore){}
        }

    }


    public void ejbPassivate() {
        logger.log(BasicLevel.DEBUG, "");
    }


    public void ejbActivate() {
        logger.log(BasicLevel.DEBUG, "");
    }

    public void ejbPostCreate(String warehouseID,
                              int districtID, Integer customerID,
                             float orderID, Vector orderItems){
        logger.log(BasicLevel.DEBUG, "");
    }


    /**
     * This method is called when a client calls the OrderHome.create().  It creates
     * records in the database for the line items and the order header information.
     * @param warehouseID	   String Warehouse ID
     * @param districtID	   int District ID
     * @param customerID	   Integer Customer ID
     * @param orderID	   float Order ID - NOTE: must be passed in as parameter, it is not created by the bean
     * @param orderItems	    Vector of OrderDetail objects.  Each OrderDetail object represents one line item on the order.  The bean determines the order line number.
     * @exception             javax.ejb.CreateException
     * @exception             javax.ejb.RemoteException
     */
    /* Use separate conneciton objects for ordlin and orders */
    public OrderID  ejbCreate(String warehouseID, int districtID, Integer customerID,
                             float orderID, Vector orderItems)
        throws CreateException, RemoteException {
        logger.log(BasicLevel.DEBUG, "");
        ivWarehouseID = warehouseID;
        ivDistrictID = districtID;
        ivCustomerID = customerID;
        ivOrderID = orderID;
        ivNumberOfOrderLines = orderItems.size();
        ivOrderItems = orderItems;
        // Use JDBC to store the Order to the database
        Connection con = null;
        try {
            con = getConnection();
            // Iterate through each order line and insert a record into the database
            int orderLineNumber = 1;
            Enumeration enumer = ivOrderItems.elements();
            while(enumer.hasMoreElements()){
                OrderDetail od = (OrderDetail)enumer.nextElement();
                String orderlineSQL = "insert into " + orderlinesTable +" (OLOID, OLDID, OLWID, OLNBR, OLIID, OLQTY, OLAMNT) " +
                    "values ("     + ivOrderID +
                    ", "  + ivDistrictID +
                    ", '" + ivWarehouseID + "'" +
                    ", "  + orderLineNumber  +
                    ", '" + od.getItemID() + "'" +
                    ", "  + od.getItemQty() +
                    ", "  + od.getItemAmount() + ")";
                Statement stmtLine = con.createStatement();
                logger.log(BasicLevel.DEBUG, "orderlineSQL= "+orderlineSQL);
                int lineCount = stmtLine.executeUpdate(orderlineSQL);
                if (lineCount == 0) {
                    logger.log(BasicLevel.DEBUG, "lineCount == 0");
                    throw new CreateException ("Unable to create order line item: " + orderLineNumber);
                }
                stmtLine.close();
                od.setLineNumber(orderLineNumber);   //Store the line number in the order detail object.
                orderLineNumber++;
            }

            // Insert a record into the order table
            String insertSQL = "insert into " + ordersTable +
                 "(OWID, ODID, OCID, OOID, OLINES) values (" +
                "'" + ivWarehouseID + "', " +
                ivDistrictID + ", " +
                "'" + ivCustomerID + "', " +
                ivOrderID + ", " +
                ivNumberOfOrderLines +
                ")";
            Statement stmtOrder = con.createStatement();
            logger.log(BasicLevel.DEBUG, "insertSQL= "+insertSQL);
            int orderCount = stmtOrder.executeUpdate(insertSQL);
            if (orderCount == 0) {
                throw new CreateException ("Unable to create order");
            }
            stmtOrder.close();

            // Create the primary key
            OrderID oID = new OrderID(ivWarehouseID, ivDistrictID, ivOrderID);

            return oID;


        } catch (CreateException ce) {
            System.out.println("CreateException thrown: " + ce.getMessage());
            throw ce;
        } catch (SQLException sqe) {
            System.out.println("SQLException thrown: " + sqe.getMessage());
            throw new CreateException (sqe.getMessage());
        } finally {
            try{
                con.close();
            } catch (Exception ignore){}
        }



    }

    public OrderID ejbFindByPrimaryKey(OrderID pk) throws FinderException {
        logger.log(BasicLevel.DEBUG, "");
        if ( pk == null ) {
            throw new FinderException("ejbFindByPrimaryKey: null primary key");
        }

        Connection con = null;
        Statement stmt = null;

        try{
            con = getConnection();
            // Find the order in the orders table
            String selectOrderSQL = "select * from " + ordersTable + "  where " +
                "owid = '" + pk.ivWarehouseID + "' " +
                "and odid = " + pk.ivDistrictID + " " +
                "and ooid = "  + pk.ivOrderID;
            stmt = con.createStatement();
            ResultSet rsOrder = stmt.executeQuery(selectOrderSQL);
            if(rsOrder.next()){
				//Order found, don't throw exception
            }else{
				//Order not fount, throw exception
                throw new FinderException("Order " + pk.ivOrderID + " not found.");
            }
            rsOrder.close();
            stmt.close();

        } catch (SQLException sqe){
            //Unable to find the order because of an SQL error.
            throw new FinderException (sqe.getMessage());
        } finally {
            try {
                con.close();
            }catch (Exception ignore) {}
        }
        return pk;

    }

     /**
     * Finds an order given the warehouse, district and order IDs as Strings.
     * The method constructs an OrderID from the three parameters and calls
     * ejbFindByPrimaryKey().
     *
     * @param wID			String Warehouse ID
     * @param dID			String District ID
     * @param oID			String Order ID
     *
     * @exception     java.rmi.RemoteException
     * @exception     javax.ejb.FinderException
     *                thrown if the EJBean cannot be found.
     */
    public OrderID ejbFindByID(String wID, String dID, String oID)
	throws FinderException, RemoteException {

	OrderID pk = new OrderID(wID, dID, oID);
	return ejbFindByPrimaryKey(pk);

    }

    private Connection getConnection() throws SQLException {
        if (dataSource == null) {
            // Finds DataSource from JNDI
            try {
                initialContext = new InitialContext();
                dataSource = (DataSource)initialContext.lookup("java:comp/env/jdbc/Order");
            } catch (Exception e) {
                logger.log(BasicLevel.ERROR, "Pb with naming context");
                throw new javax.ejb.EJBException("Pb with naming context ");
            }
        }
        return dataSource.getConnection();
    }

    private Context initialContext = null;
    // ------------------------------------------------------------------
    // Order implementation
    // ------------------------------------------------------------------

    // *********************************************************************** //
    // Implementation of business methods defined in Order interface
    // *********************************************************************** //

    public Integer getCustomerID() throws RemoteException {
        return ivCustomerID;
    }
    public int getOrderLineCount() throws RemoteException {
        return ivNumberOfOrderLines;
    }
    public Vector getOrderItems() throws RemoteException {
        return ivOrderItems;
    }

}



