/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 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 org.objectweb.jonas.jtests.beans.relation.family;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.EntityContext;
import javax.ejb.FinderException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;

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

/**
 * Bean implementation. This is an example of bean with relation between
 * instances of the same bean. Each instance represents a people, the PK
 * is the name, and he may have a mother, a father, and a spouse.
 * @author Philippe Durieux
 */
public abstract class PeopleEC2 implements javax.ejb.EntityBean {

    private static Logger logger = null;
    private EntityContext ejbContext;
    private InitialContext ictx;
    private Context myEnv;
    private PeopleHomeLocal homeLocal = null;
    private PeopleHome home = null;

    // ---------------------------------------------------------------------
    //  CMP fields 
    // ---------------------------------------------------------------------
    public abstract String getName();
    public abstract void setName(String name);

    // ---------------------------------------------------------------------
    //  CMR fields 
    // ---------------------------------------------------------------------
    public abstract Collection getChildren();
    public abstract void setChildren(Collection c);

    public abstract PeopleLocal getFather();
    public abstract void setFather(PeopleLocal p);

    public abstract PeopleLocal getMother();
    public abstract void setMother(PeopleLocal p);

    public abstract PeopleLocal getUnion();
    public abstract void setUnion(PeopleLocal p);

    // ---------------------------------------------------------------------
    //  Home operations
    // ---------------------------------------------------------------------

    public java.lang.String ejbCreate(String name, String papa, String maman) throws javax.ejb.CreateException {
        logger.log(BasicLevel.DEBUG, getName());
        setName(name);
        return null;
    }

    public void ejbPostCreate(String name, String papa, String maman) throws javax.ejb.CreateException {
        logger.log(BasicLevel.DEBUG, getName());
        if (papa != null) {
            try {
                PeopleLocal father = homeLocal.findByPrimaryKey(papa);
                setFather(father);
            } catch (FinderException e) {
                throw new CreateException("Father unknown");
            }
        }
        if (maman != null) {
            try {
                PeopleLocal mother = homeLocal.findByPrimaryKey(maman);
                setMother(mother);
            } catch (FinderException e) {
                throw new CreateException("Mother unknown");
            }
        }
    }

    /**
     * Home method.
     */
    public void ejbHomeUnion(String name1, String name2) throws FinderException, RemoteException {
        logger.log(BasicLevel.DEBUG, name1 + " with " + name2);
        try {
            PeopleLocal p1 = homeLocal.findByPrimaryKey(name1);
            PeopleLocal p2 = homeLocal.findByPrimaryKey(name2);
            p1.setUnion(p2);
        } catch (FinderException e) {
            logger.log(BasicLevel.ERROR, "Cannot find people");
            throw e;
        }
    }

    /**
     * Home method.
     */
    public void ejbHomeDivorce(String name1, String name2) throws FinderException, RemoteException {
        logger.log(BasicLevel.DEBUG, name1 + " with " + name2);
        try {
            PeopleLocal p1 = homeLocal.findByPrimaryKey(name1);
            PeopleLocal p2 = homeLocal.findByPrimaryKey(name2);
            if (p1.getUnion() != p2) {
                logger.log(BasicLevel.ERROR, name1 + " and " + name2 + " were not united yet");
                throw new RemoteException(name1 + " and " + name2 + " were not united yet");
            }
            p1.setUnion(null);
        } catch (FinderException e) {
            logger.log(BasicLevel.ERROR, "Cannot find people");
            throw e;
        }
    }


    // ---------------------------------------------------------------------
    //  EJB standard callbacks
    // ---------------------------------------------------------------------

    public void setEntityContext(javax.ejb.EntityContext ctx) {
        // init the logger
        if (logger == null) {
            logger = Log.getLogger("org.objectweb.jonas_tests");
        }
        logger.log(BasicLevel.DEBUG, getName());
        ejbContext = ctx;
        try {
            // Get initial Context
            ictx = new InitialContext();
            myEnv = (Context) ictx.lookup("java:comp/env");
        } catch (NamingException e) {
            throw new EJBException("PeopleEC2: Cannot get filehome:" + e);
        }
        checkEnv("setEntityContext");
        home = (PeopleHome) ejbContext.getEJBHome();
        homeLocal = (PeopleHomeLocal) ejbContext.getEJBLocalHome();
    }

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

    public void ejbRemove() throws javax.ejb.RemoveException {
        logger.log(BasicLevel.DEBUG, getName());
    }

 
    public void ejbLoad() {
        logger.log(BasicLevel.DEBUG, getName());
        checkEnv("ejbLoad");
    }


    public void ejbStore() {
        logger.log(BasicLevel.DEBUG, getName());
        checkEnv("ejbStore");
    }
        

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


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

    // ---------------------------------------------------------------------
    //  Implementation of the Remote interface
    // ---------------------------------------------------------------------

    /**
     * Retrieve my Father, as a Remote Object.
     * Mainly convert Local object to Remote Object.
     */
    public People myFather() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        People father = null;
        PeopleLocal f = getFather();
        if (f == null) {
            return null;
        }
        try {
            father = home.findByPrimaryKey(f.getName());
        } catch (FinderException e) {
            throw new RemoteException("Lost father");
        }
        return father;
    }

    /**
     * Retrieve my Mother, as a Remote Object.
     * Mainly convert Local object to Remote Object.
     */
    public People myMother() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        People mother = null;
        PeopleLocal f = getMother();
        if (f == null) {
            return null;
        }
        try {
            mother = home.findByPrimaryKey(f.getName());
        } catch (FinderException e) {
            throw new RemoteException("Lost mother");
        }
        return mother;
    }

    /**
     * Retrieve my children, as a Collection of Remote Objects.
     * Mainly convert Local objects to Remote Objects.
     */
    public Collection myChildren() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        Collection ret = new ArrayList(); 
        Collection c = getChildren();
        if (c.size() == 0) {
            // If no children, maybe it's because I'm the father.
            // In this case, must use a finder method (uni-directional relation)
            try {
                c = homeLocal.findChildren(getName());
            } catch (FinderException e) {
                throw new RemoteException("Cannot get children");
            }
        }
        for (Iterator i = c.iterator(); i.hasNext(); ) {
            PeopleLocal p = (PeopleLocal) i.next();
            try {
                People pr = home.findByPrimaryKey(p.getName());
                ret.add(pr);
            } catch (FinderException e) {
                throw new RemoteException("Lost child");
            }
        }
        return ret;
    }

    /**
     * Return true if not married
     */
    public boolean isSingle() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        return (getUnion() == null);
    }

    /**
     * Return true if no father
     */
    public boolean hasNoFather() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        return (getFather() == null);
    }

    /**
     * Return true if no mother
     */
    public boolean hasNoMother() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        return (getMother() == null);
    }

    /**
     * @return the People we are married with
     */
    public People mySpouse() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        People ret = null;
        PeopleLocal f = getUnion();
        if (f == null) {
            return null;
        }
        try {
            ret = home.findByPrimaryKey(f.getName());
        } catch (FinderException e) {
            throw new RemoteException("Lost spouse");
        }
        return ret;
    }

    public int kidNumber() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        int ret = getChildren().size();
        if (ret == 0) {
            // maybe I'm the father...
            try {
                ret = homeLocal.findChildren(getName()).size();
            } catch (FinderException e) {
                throw new RemoteException("Cannot get my children");
            }
        }
        return ret;
    }

    /**
     * @return true if orphan
     */
    public boolean isOrphan() throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        return (getMother() == null && getFather() == null);
    }

    /**
     * @return true if is brother or sister with other People
     * @param c name of the other people.
     */
    public boolean brotherSisterOf(String c) throws RemoteException {
        logger.log(BasicLevel.DEBUG, getName());
        try {
            PeopleLocal p = homeLocal.findByPrimaryKey(c);
            if (getMother() != null && p.getMother() == getMother()) {
                return true;
            }
            if (getFather() != null && p.getFather() == getFather()) {
                return true;
            }
        } catch (FinderException e) {
        }
        return false;
    }

    // ---------------------------------------------------------------------
    //  private methods
    // ---------------------------------------------------------------------

    /**
     * Check environment variables
     */
    void checkEnv(String method) {
        try {
            String value = (String) myEnv.lookup("myname");
            if (!value.equals("myentity")) {
                logger.log(BasicLevel.ERROR, ": myEnv.lookup failed: myname=" + value);
                throw new EJBException("PeopleEC2 1: " + method);
            }
        } catch (NamingException e) {
            logger.log(BasicLevel.ERROR, ": myEnv.lookup raised exception:\n" + e);
            throw new EJBException("PeopleEC2 2: " + method);
        }
    }

}
