// OrderEntryClerkSFR.java
// Stateful Session Bean

package org.objectweb.jonas.stests.appli;

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

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.rmi.PortableRemoteObject;
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 OrderEntryClerkSFR implements SessionBean {

    static private Logger logger = null;
    SessionContext ejbContext;
    private transient Connection dbConn = null;
    private static String whid = "0001";
    private static String did = "1";

    // table names
    private static String customersTable = null;
    private static String stocksTable  = null;
    private static String itemsTable =  null;
    private static String ordersTable =  null;
    private static String orderlinesTable =  null;

    // Following is the state in this stateful session bean
    public Integer custID;
    public Vector items;

    // (The DataSource can be shared among all instances)
    protected static DataSource dataSource = null;

    // ------------------------------------------------------------------
    // SessionBean implementation
    // ------------------------------------------------------------------


    public void setSessionContext(SessionContext ctx) {
        if (logger == null) {
            logger = Log.getLogger("org.objectweb.jonas_tests");
        }
        logger.log(BasicLevel.DEBUG, "");
        ejbContext = ctx;
        if ( customersTable == null) {
            try {
                InitialContext initialContext = new InitialContext();
                customersTable = (String) initialContext.lookup("java:comp/env/CustomerTableName");
                stocksTable = (String) initialContext.lookup("java:comp/env/StockTableName");
                itemsTable = (String) initialContext.lookup("java:comp/env/ItemTableName");
                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 ejbRemove() {
        logger.log(BasicLevel.DEBUG, "");
    }
        

    public void ejbCreate() throws CreateException {
        logger.log(BasicLevel.DEBUG, "");
        items = new Vector();
        custID = null;
    }

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

    public void ejbActivate() {
        logger.log(BasicLevel.DEBUG, "");
    }
    
    // ------------------------------------------------------------------
    // OrderEntryClerk implementation
    // ------------------------------------------------------------------

    // Set the current customer
    public void setCustomer(Integer cid) throws RemoteException {
        logger.log(BasicLevel.DEBUG, "customer = "+cid);
        if ( verifyCustomer(cid) ) {
            custID = cid;
        } else {
            throw new CpwejbException("Customer id " + cid + " not valid");
        }
    }

    // Find all available customers
    public Vector findAllCustomers() throws RemoteException{
        logger.log(BasicLevel.DEBUG, "");
        Vector customerVector = new Vector();

        Customer customer = null;
        try {
            Connection con = getConnection();
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("select cid, cfirst, clast, cinit, caddr1, caddr2, ccity, cstate, czip from "+ customersTable);
            while ( rs != null && rs.next() ) {
                String customerString[] = new String[9];
                customerString[0] = new Integer(rs.getInt("cid")).toString();
                customerString[1] = rs.getString("clast");
                customerString[2] = rs.getString("cfirst");
                customerString[3] = rs.getString("cinit");
                customerString[4] = rs.getString("caddr1");
                customerString[5] = rs.getString("caddr2");
                customerString[6] = rs.getString("ccity");
                customerString[7] = rs.getString("cstate");
                customerString[8] = rs.getString("czip");
                customerVector.addElement(customerString);
            }
            stmt.close();
            releaseConnection(con);
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        return customerVector;

    }

    // Add an item and quantity to the order
    public void addOrderLine(Integer iid, int quantity) throws RemoteException {
        logger.log(BasicLevel.DEBUG, "item = "+iid+" qty = "+quantity);
        if ( custID == null ) {
            throw new CpwejbException("OrderEntryClerkBean:  Customer ID must be set first");
        }
        
        if ( items.size() == 25 ) {
            throw new CpwejbException("OrderEntryClerkBean:  Maximum of 25 lines per order reached");
        }
        Item item = null;
        try {
            InitialContext initCtx = new InitialContext();
            ItemHome home = 
                (ItemHome) PortableRemoteObject.narrow(initCtx.lookup("ItemHome"), ItemHome.class);
            item = home.findByPrimaryKey(iid);
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        OrderDetail ol = new OrderDetail(iid, item.getItemPrice()*quantity, quantity);
        items.addElement(ol);
    }


    // Reset the bean state ie the current customer and the current order
    public void undoAll() throws RemoteException {
        logger.log(BasicLevel.DEBUG, "");
        // Clear out the state of the session bean at this point
        items = new Vector();
        custID = null;
    }
   // Verify an existing customer
    public boolean verifyCustomer(Integer cid) throws RemoteException {
        logger.log(BasicLevel.DEBUG,  "cid = "+cid);
        Customer customer = null;
        boolean retval = false;
        try {
            Connection con = getConnection();
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("select cid from "+ customersTable +" where cid = '" + cid + "'");
            if ( rs != null && rs.next())
                retval = true;
            stmt.close();
            releaseConnection(con);
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        return retval;
    }

    // Place an order
    public String placeOrder() throws RemoteException {
        logger.log(BasicLevel.DEBUG,  "");
        String orderNumber = null;
        if ( custID == null ) {
	    throw new CpwejbException("OrderEntryClerkBean:  Customer ID must be set before placing an order");
        }
        if ( items.size() == 0 ) {
            throw new CpwejbException("OrderEntryClerkBean:  No order lines.  Cannot place order.");
	}

        try {
            InitialContext initCtx = new InitialContext();
            OrderPlacementHome home = (OrderPlacementHome) PortableRemoteObject.narrow(initCtx.lookup("OrderPlacementHome"), OrderPlacementHome.class);
            OrderPlacement placement = home.create();
            float number = placement.placeOrder(whid, did, custID, items);
            orderNumber = Float.toString(number);
            orderNumber = orderNumber.substring(0,orderNumber.length()-2);
            // Clear out the state of the session bean at this point
            items = new Vector();
            custID = null;
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        return orderNumber;
    }
   
   // Find a range of items
    public Vector findRangeOfItems(Integer lowID, Integer highID) throws RemoteException {
        logger.log(BasicLevel.DEBUG,  "low = "+lowID+" high = "+highID);
        Vector itemVector = new Vector();

        Item item = null;
        try {
            Connection con = getConnection();
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery("select iid, iname, iprice, idata, stqty from "+itemsTable+" , " + stocksTable +" where iid = stiid and iid >= '" + lowID +
					     "' and iid <= '" + highID + "'");
            while ( rs != null && rs.next() ) {
                String itemString[] = new String[5];
                itemString[0] = rs.getString("iid");
                itemString[1] = rs.getString("iname");
                itemString[2] = "$" + Float.toString(rs.getFloat("iprice"));
                itemString[3] = Integer.toString(rs.getInt("stqty"));
                itemString[4] = rs.getString("idata");
                itemVector.addElement(itemString);
            }
            stmt.close();
            releaseConnection(con);
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        return itemVector;
    }

    public Vector findAllItems() throws RemoteException{
        logger.log(BasicLevel.DEBUG,  "");
        Vector itemVector = new Vector();
        Item item = null;
        try {
            Connection con = getConnection();
            Statement stmt = con.createStatement();

            ResultSet rs = stmt.executeQuery("select ProdId, Name, Price, Descrip, stqty from "+ customersTable + " , " + stocksTable + " where ProdId = stiid");

            logger.log(BasicLevel.DEBUG,"select ProdId, Name, Price, Descrip, stqty from itemtable,stocktable where ProdId = stiid");
            while ( rs != null && rs.next() ) {
                String itemString[] = new String[5];
                itemString[0] = rs.getString("ProdId");
                itemString[1] = rs.getString("Name");
                String price = "$" + Float.toString(rs.getFloat("Price"));
                // make sure the price ends with .00 for even dollar amounts
                if ( price.endsWith(".0") ) {
                    price += "0";
                }
                itemString[2] = price;
                itemString[3] = Integer.toString(rs.getInt("stqty"));
                itemString[4] = rs.getString("Descrip");
                itemVector.addElement(itemString);
            }
            stmt.close();
            releaseConnection(con);
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        return itemVector;
    }
    public String[] getCustomerForOrder(String wid, int did, int oid) 
        throws RemoteException, CpwejbException {
        logger.log(BasicLevel.DEBUG,  "oid = "+oid);
        Integer customerID = null;
        String custInfo[] = new String[4];
        try {
            Connection con = getConnection();
            Statement stmt = con.createStatement();
            String stmtString = "select ocid from " + ordersTable + " where owid = '" + wid + "' and odid = " + did +
                " and oid = " + oid;
            ResultSet rs = stmt.executeQuery(stmtString);
            if ( rs != null && rs.next() ) {
                customerID = new Integer(rs.getInt("ocid"));
                custInfo[0] = custID.toString();
                if ( rs.next() ) {
                    // There were multiple orders with the same key -- severe error
                    throw new RemoteException("Duplicate Key Error: " + wid + "/" + did + "/" + oid);
                }
                InitialContext initCtx = new InitialContext();
                CustomerHome cHome = (CustomerHome) PortableRemoteObject.narrow(initCtx.lookup("CustomerHome"), CustomerHome.class);
                Customer customer = (Customer)cHome.findByPrimaryKey(customerID);
                custInfo[1] = customer.getFirstName();
                custInfo[2] = customer.getMiddleInitials();
                custInfo[3] = customer.getLastName();
            } else {
                // order does not exist
                throw new CpwejbException("Order does not exists for warehouse " + wid +
					  " district " + did + " order " + oid);
            }
            stmt.close();
            releaseConnection(con);
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        return custInfo;
    }


    public Vector getItemsForOrder(String wid, int did, int oid) 
        throws RemoteException, CpwejbException {
        logger.log(BasicLevel.DEBUG,  "oid = "+oid);
        Vector itemVector = new Vector();
        try {
            Connection con = getConnection();
            Statement stmt = con.createStatement();
            String stmtString = "select oliid, olqty, olamnt from " + orderlinesTable + " where olwid = '" + wid + "' and oldid = " + did +
                " and oloid = " + oid;
            ResultSet rs = stmt.executeQuery(stmtString);
            InitialContext initCtx = new InitialContext();
            ItemHome iHome = (ItemHome) PortableRemoteObject.narrow(initCtx.lookup("ItemHome"), ItemHome.class);
            while ( rs != null && rs.next() ) {
                String itemInfo[] = new String[4];
                Integer ItemID = new Integer(rs.getInt("oliid"));
                itemInfo[0] = ItemID.toString();
                itemInfo[2] = Integer.toString(rs.getInt("olqty"));
                itemInfo[3] = Float.toString(rs.getFloat("olamnt"));
                Item item = (Item)iHome.findByPrimaryKey(ItemID);
                itemInfo[1] = item.getItemName();
                itemVector.addElement(itemInfo);
            }
            stmt.close();
            releaseConnection(con);
        } catch (Exception e) {
            throw new RemoteException(e.getMessage());
        }
        return itemVector;
    }

    public void createAllTables() {
        logger.log(BasicLevel.DEBUG, "");
        createCustomersTable();
        createItemsTable();
        createStocksTable(); 
        createDistrictsTable();
        createOtherTables();
 
    }

    public void createOtherTables() {
        createOrdersTable();
        createOrderlinesTable();
    }

    public void createOrdersTable() {
            logger.log(BasicLevel.DEBUG, "");
        // Drop table
        Connection conn = null;
        Statement stmt = null;
        try {
            conn = getConnection();
            stmt = conn.createStatement();
            stmt.execute("drop table jt2_appli_order");
        } catch (Exception e) {
            // The first time, table will not exist.
            logger.log(BasicLevel.INFO, "Exception in dropTable : " + e);
        }

        // Create table.
        try {
            stmt.execute("create table jt2_appli_order(owid varchar(4),odid integer,ocid integer,ooid float,olines integer,primary key (owid,odid,ooid))");
            stmt.close();
            conn.close();
            logger.log(BasicLevel.DEBUG,  "jt2_appli_order created");
        } catch (SQLException e) {
            logger.log(BasicLevel.ERROR, "Exception in createOrderTable : " + e);
            throw new EJBException("Exception in createOrderTable");
        }
    }


    public void createOrderlinesTable() {
        logger.log(BasicLevel.DEBUG, "");
        // Drop table
        Connection conn = null;
        Statement stmt = null;
        try {
            conn = getConnection();
            stmt = conn.createStatement();
            stmt.execute("drop table jt2_appli_orderline");
        } catch (Exception e) {
            // The first time, table will not exist.
            logger.log(BasicLevel.INFO, "Exception in dropTable : " + e);
        }

        // Create table.
        try {
            stmt.execute("create table jt2_appli_orderline (OLOID float not null, OLDID integer not null, OLWID varchar(4) not null, OLNBR integer not null,OLIID integer, OLQTY integer, OLAMNT float,primary key (OLWID,OLDID,OLOID,OLNBR))");
            stmt.close();
            conn.close();
            logger.log(BasicLevel.DEBUG,  "jt2_appli_orderline created");
        } catch (SQLException e) {
            logger.log(BasicLevel.ERROR, "Exception in createOrderlinesTable : " + e);
            throw new EJBException("Exception in createOrderlinesTable");
        }
  }
 
  private void createDistrictsTable() {
        logger.log(BasicLevel.DEBUG, "");
 
        try {
            InitialContext initCtx = new InitialContext();
            DistrictHome home = 
                (DistrictHome) PortableRemoteObject.narrow(initCtx.lookup("DistrictHome"), 
                                                           DistrictHome.class);
            home.create(1,"0001","Belgique",0);
            home.create(2,"0001","Espagne",0);
            home.create(3,"0001","Finlande",0);
            home.create(4,"0001","Irlande",0);
            logger.log(BasicLevel.DEBUG,  "jt2_appli_district created");
        } catch  (Exception e) {
            logger.log(BasicLevel.ERROR, "Exception in createTable : " + e);
            throw new EJBException("Exception in createTable");
        }
  }

  private void createCustomersTable() {
        logger.log(BasicLevel.DEBUG, "");
 
        try {
            InitialContext initCtx = new InitialContext();
            CustomerHome home = 
                (CustomerHome) PortableRemoteObject.narrow(initCtx.lookup("CustomerHome"), CustomerHome.class);
            home.create( new Integer(1),"Paul","Desgranges","PD","1 rue du bourg","",
                   "Nice","06","","04050607",1000);
            home.create( new Integer(2),"François","Exertier","FE","16 avenue J. jaures","",
                   "Grenoble","38","","0476276115",1000);
            home.create( new Integer(3),"Florent","Benoit","FB","20 place de la gare","",
                   "Lyon","69","","04286745",1000);
            home.create( new Integer(4),"Gérard","Vandome","GV","13 rue A. Einstein","",
                   "Marseille","13","","04122436",1000);
            home.create( new Integer(5),"Philippe","Coq","PC","3 rue du Village","",
                   "Nice","06","","0405060713",1000);
            home.create( new Integer(6),"Philippe","Durieux","PD","6 avenue J. Valles","",
                   "Grenoble","38","","0476276115",1000);
            home.create( new Integer(7),"Hélène","Joanin","HJ","30 place du Tramway","",
                   "Lyon","69","","0428674513",1000);
            home.create( new Integer(8),"Adriana","Danes","AD","23 rue Galilé","",
                   "Marseille","13","","0412243613",1000);
            home.create( new Integer(9),"Jacques","Cayuela","JC","29 rue de la Clef","",
                   "Nice","06","","0405060717",1000);

            home.create( new Integer(10),"Eric","Hardesty","EC","41 rue de la gare","",
                   "Nancy","54","","0302060627",1000);
            home.create( new Integer(11),"Goulven","Lejeune","GL","37 rue du Hameau","",
                   "Nice","06","","0405060717",1000);
            home.create( new Integer(12),"Christophe","Loridan","CL","26 avenue Gambetta","",
                   "Grenoble","38","","0476276117",1000);
            home.create( new Integer(13),"Jerome","Camilleri","JC","30 place des VFD","",
                   "Lyon","69","","0428674519",1000);
            home.create( new Integer(14),"Guillaume","Sauthier","GS","37 rue B.Giordano","",
                   "Marseille","13","","0412243196",1000);
           logger.log(BasicLevel.DEBUG,  "jt2_appli_customer created");
        } catch  (Exception e) {
            logger.log(BasicLevel.ERROR, "Exception in createTable : " + e);
            throw new EJBException("Exception in createTable");
        }
  }
    private void createItemsTable() {
        logger.log(BasicLevel.DEBUG, "");
 
        try {
            InitialContext initCtx = new InitialContext();
            ItemHome home = 
                (ItemHome) PortableRemoteObject.narrow(initCtx.lookup("ItemHome"), ItemHome.class);
            home.create(new Integer(1),"Beaujolais 95",19,"Grumage - Domaine des Averlys");
            home.create(new Integer(2),"Beaujolais 95",20,"Domaine des Averlys");
            home.create(new Integer(3),"Beaujolais 96",18,"Cuvée Antique - Domaine de Rochecorbière");
            home.create(new Integer(4),"Beaujolais 96",19,"Vin de garde - Domaine des Averlys");
            home.create(new Integer(5),"Beaujolais 96",22,"Domaine des Fortières");
            home.create(new Integer(6),"Beaujolais 97",28,"Médaille Or - Paul Champier Producteur");
            home.create(new Integer(7),"Beaujolais 97",21,"Domaine du Berret");
            home.create(new Integer(8),"Beaujolais 98",21,"Domaine des Fortières");
            home.create(new Integer(9),"Beauj Rosé 96",19,"Domaine de Rochecorbière");
            home.create(new Integer(10),"Beauj Rosé 96",19,"Domaine de la Croix Ange");
            home.create(new Integer(11),"Beauj Rosé 97",21,"Domaine de la Chambarde");
            home.create(new Integer(12),"Beauj Rosé 97",18,"Domaine des Averlys");
            home.create(new Integer(13),"Beauj Blanc 96",24,"Domaine de Rochcorbière");
            home.create(new Integer(14),"Beauj Blanc 96",21,"Domaine du Berret");
            home.create(new Integer(15),"Beauj Nouveau",20,"Domaine du Berret");
            home.create(new Integer(16),"Beauj Nouveau",21,"Domaine des Fortières");
            home.create(new Integer(17),"Beauj Nouveau",19,"Domaine de la Chambarde");
            home.create(new Integer(18),"Beauj Nouveau",18,"Domaine de la Croix Ange");
            home.create(new Integer(19),"Beauj Villages",25,"Agrément Terra Vitis");
            home.create(new Integer(20),"Brouilly",22,"Paul Champier Producteur");
            home.create(new Integer(21),"Brouilly 1994",35,"Domaine dit Barron");
            home.create(new Integer(22),"Brouilly 1996",28,"Médaille de Bronze - Paul Champier Producteur");
            home.create(new Integer(23),"Brouilly 1997",71,"Médaille Or - Paul Champier Producteur");
            home.create(new Integer(24),"Côte de Br 94",30,"Paul Champier Producteur");
            home.create(new Integer(25),"Côte de Br 97",32,"Les Muses - Château de Briante");
            home.create(new Integer(26),"Morgon 1997",29,"Domaine dit Barron");
            home.create(new Integer(27),"Régnié",26,"Cercle des Bulliats");
            home.create(new Integer(28),"Régnié 1998",26,"Cercle des Bulliats");
            logger.log(BasicLevel.DEBUG,  "jt2_appli_item created");
        } catch  (Exception e) {
            logger.log(BasicLevel.ERROR, "Exception in createTable : " + e);
            throw new EJBException("Exception in createTable");
        }            
    }

   private void createStocksTable() {
        logger.log(BasicLevel.DEBUG, "");
 
        try {
            InitialContext initCtx = new InitialContext();
            StockHome home = 
                (StockHome) PortableRemoteObject.narrow(initCtx.lookup("StockHome"), StockHome.class);
            home.create("0001", new Integer(1),1000);
            home.create("0001", new Integer(2),1000);
            home.create("0001", new Integer(3),1000);
            home.create("0001", new Integer(4),1000);
            home.create("0001", new Integer(5),1000);
            home.create("0001", new Integer(6),1000);
            home.create("0001", new Integer(7),1000);
            home.create("0001", new Integer(8),1000);
            home.create("0001", new Integer(9),1000);
            home.create("0001", new Integer(10),1000);
            home.create("0001", new Integer(11),1000);
            home.create("0001", new Integer(12),1000);
            home.create("0001", new Integer(13),1000);
            home.create("0001", new Integer(14),1000);
            home.create("0001", new Integer(15),1000);
            home.create("0001", new Integer(16),1000);
            home.create("0001", new Integer(17),1000);
            home.create("0001", new Integer(18),1000);
            home.create("0001", new Integer(19),1000);
            home.create("0001", new Integer(20),1000);
            home.create("0001", new Integer(21),1000);
            home.create("0001", new Integer(22),1000);
            home.create("0001", new Integer(23),1000);
            home.create("0001", new Integer(24),1000);
            home.create("0001", new Integer(25),1000);
            home.create("0001", new Integer(26),1000);
            home.create("0001", new Integer(27),1000);
            home.create("0001", new Integer(28),1000);
            logger.log(BasicLevel.DEBUG,  "jt2_appli_stock created");
        } catch  (Exception e) {
            logger.log(BasicLevel.ERROR, "Exception in createTable : " + e);
            throw new EJBException("Exception in createTable");
        }            
    }
    // ------------------------------------------------------------------
    // Internal methods
    // ------------------------------------------------------------------

    private Connection getConnection() throws SQLException,RemoteException{
        if (dataSource == null) {

            Context    initialContext = null;
            try {
                initialContext = new InitialContext(); 
            } catch (Exception e) {
                throw new RemoteException("Cannot get InitialContext ", e);
            }
            String dataSourceName = "java:comp/env/jdbc/OrderEntryClerk";  
            
            try {
                dataSource = (DataSource)initialContext.lookup(dataSourceName);
            } catch (Exception e) {
                throw new RemoteException("cannot lookup " + dataSourceName, e);
            }
        }
        return dataSource.getConnection();
    }

    // Return a JDBC connection to the pool
    private void releaseConnection(Connection con) {
        try{
            con.close();
        } catch (Exception ignore) {}
    }





}

