/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2004 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package lb;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.Iterator;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.FinderException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.TransactionRolledbackLocalException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

/**
 * Manager Implementation
 * @author Philippe Durieux
 */
public class ManagerSF implements SessionBean {

    SessionContext ejbContext;

    ManacLocalHome manacLocalHome = null;

    int c1 = 0;

    int d1 = 0;

    ManacLocal cred1, deb1;

    int initialValue = 1000;

    int value = 10;

    // ------------------------------------------------------------------
    // init DataBase for Manac beans
    // ------------------------------------------------------------------
    private void initDB() {

        // Get my DataSource from JNDI
        DataSource ds = null;
        InitialContext ictx = null;
        try {
            ictx = new InitialContext();
        } catch (Exception e) {
            System.out.println("new InitialContext() : " + e);
            throw new EJBException("Cannot get JNDI InitialContext");
        }
        try {
            ds = (DataSource) ictx.lookup("java:comp/env/jdbc/mydb");
        } catch (Exception e) {
            System.out.println("cannot lookup datasource " + e);
            throw new EJBException("cannot lookup datasource");
        }

        // Drop table
        Connection conn = null;
        Statement stmt = null;
        // myTable must be <jdbc-table-name> from jonas-xml file (Manac bean)
        String myTable = "manacsample";
        try {
            conn = ds.getConnection();
            stmt = conn.createStatement();
            stmt.execute("drop table " + myTable);
            stmt.close();
        } catch (SQLException e) {
            // The first time, table will not exist.
        }

        // Create table.
        try {
            stmt = conn.createStatement();
            stmt.execute("create table " + myTable
                    + "(c_name varchar(30) not null primary key, c_num integer, c_balance integer)");
            stmt.close();
            conn.close();
        } catch (SQLException e) {
            System.out.println("Exception in createTable : " + e);
            throw new EJBException("Exception in createTable");
        }
    }

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

    /**
     * Set the associated session context. The container calls this method after
     * the instance creation. The enterprise Bean instance should store the
     * reference to the context object in an instance variable. This method is
     * called with no transaction context.
     * @param sessionContext A SessionContext interface for the instance.
     * @throws EJBException Thrown by the method to indicate a failure caused by
     *         a system-level error.
     */
    public void setSessionContext(SessionContext ctx) {
        ejbContext = ctx;
    }

    /**
     * A container invokes this method before it ends the life of the session
     * object. This happens as a result of a client's invoking a remove
     * operation, or when a container decides to terminate the session object
     * after a timeout. This method is called with no transaction context.
     * @throws EJBException Thrown by the method to indicate a failure caused by
     *         a system-level error.
     */
    public void ejbRemove() {
    }

    /**
     * The Session bean must define 1 or more ejbCreate methods.
     * @throws CreateException Failure to create a session EJB object.
     */
    public void ejbCreate(int ival) throws CreateException {

        // lookup ManacLocalHome
        try {
            Context ictx = new InitialContext();
            manacLocalHome = (ManacLocalHome) ictx.lookup("java:comp/env/ejb/manac");
        } catch (NamingException e) {
            System.out.println("ManagerSF : Cannot get ManacLocalHome:" + e);
            throw new CreateException("Cannot get ManacLocalHome");
        }

        initialValue = ival;
    }

    /**
     * A container invokes this method on an instance before the instance
     * becomes disassociated with a specific EJB object.
     */
    public void ejbPassivate() {
    }

    /**
     * A container invokes this method when the instance is taken out of the
     * pool of available instances to become associated with a specific EJB
     * object.
     */
    public void ejbActivate() {
    }

    // ------------------------------------------------------------------
    // Manager implementation
    // ------------------------------------------------------------------

    public void createAll(int nb) throws RemoteException {

        // init database for Manac bean
        initDB();

        // create accounts
        for (int i = 0; i < nb; i++) {
            try {
                manacLocalHome.createWithDefaultName(i, initialValue);
            } catch (CreateException e) {
                System.out.println("createAll:\n" + e);
                throw new RemoteException("Cannot create Manac");
            }
        }
    }

    public void setAccounts(int d1, int c1) throws RemoteException {
        this.d1 = d1;
        this.c1 = c1;
        try {
            deb1 = manacLocalHome.findByNum(d1);
            cred1 = manacLocalHome.findByNum(c1);
        } catch (FinderException e) {
            System.out.println("Cannot find manac bean:" + e);
            throw new RemoteException("Cannot find manac bean");
        }
    }

    public void setValue(int v) throws RemoteException {
        this.value = v;
    }

    public void movement() throws RemoteException {

        // credit accounts first because we don't want a rollback if
        // same account is debited and credited in the same operation.
        try {
            cred1.credit(value);
        } catch (EJBException e) {
            System.out.println("ManagerSF: Cannot credit account:" + e);
            throw new RemoteException("ManagerSF: Cannot credit account");
        }

        // debit accounts
        try {
            deb1.debit(value);
        } catch (TransactionRolledbackLocalException e) {
            System.out.println("ManagerSF: Rollback transaction");
        } catch (EJBException e) {
            System.out.println("ManagerSF debit:" + e);
        }
    }

    public boolean checkAccount(int a) throws RemoteException {

        boolean ret = false;
        ManacLocal m = null;

        try {
            m = manacLocalHome.findByNum(a);
            int b = m.getBalance();
            if (b >= 0) {
                ret = true;
            } else {
                System.out.println("ManagerSF checkAccount: bad balance=" + b);
            }
            return ret;
        } catch (Exception e) {
            System.out.println("ManagerSF checkAccount: cannot check account: " + e);
            return false;
        }
    }

    public boolean checkAll() throws RemoteException {

        int count = 0;
        int total = 0;
        try {
            Collection accCol = manacLocalHome.findAll();
            for (Iterator accIter = accCol.iterator(); accIter.hasNext();) {
                count++;
                ManacLocal a = (ManacLocal) accIter.next();
                int balance = a.getBalance();
                if (balance < 0) {
                    System.out.println("checkAllAccounts: bad balance: " + balance);
                    return false;
                }
                String name = a.getName();
                total += balance;
            }
        } catch (Exception e) {
            System.out.println("checkAllAccounts:" + e);
            return false;
        }
        int exp = initialValue * count;
        if (total != exp) {
            System.out.println("checkAllAccounts: bad total: " + total + " (expected: " + exp + ")");
            return false;
        }
        return true;
    }

}