package tutorial.jdo;

import java.util.*;
import javax.jdo.*;

public class Rabbit
    extends Animal {
    // the resale price of a rabbit
    public static final float RESALE_PRICE = 3.0f;

    private boolean isFemale = false;
    private boolean isDead = false;
    private Set parents = new HashSet();
    private Set children = new HashSet();
    protected Snake eater;

    // some rabbit names; used by breedHelper() to name new rabbits
    private static final String[] maleRabbitNames = {
        "Bugs",
        "Peter",
        "Roger",
        "Buttons",
        "John",
        "Ed",
        "Elvis",
    };
    private static final String[] femaleRabbitNames = {
        "Babs",
        "Fluffy",
        "Cottontail",
        "Daisie",
        "Poofy",
        "Flower",
        "Britney",
    };

    public Rabbit(String name, boolean isFemale) {
        super(name, RESALE_PRICE);
        this.isFemale = isFemale;
    }
    
    public Rabbit(String name, Rabbit mother, Rabbit father, boolean isFemale) {
        super(name, RESALE_PRICE);
        parents.add(mother);
        parents.add(father);
        this.isFemale = isFemale;
    }

    /**
     * Return <code>true</code> if this rabbit is female; else 
     * <code>false</code>.
     */
    public boolean isFemale() {
        return isFemale;
    }

    /**
     * Designate that this rabbit is dead.
     */
    public void kill() {
        isDead = true;
    }

    /**
     * Adds <code>child</code> to this rabbit's children collection.
     * Performs no validation.
     */
    public void addChild(Rabbit child) {
        children.add(child);
    }

    public String toString(boolean detailed) {
        StringBuffer buf = new StringBuffer(512);
        buf.append("Rabbit ").append(getName());
        buf.append(" (").append((isFemale) ? "female" : "male").append(")");

        if (detailed) {
            buf.append(" sells for ").append(getPrice());
            buf.append(" dollars.\n\tparents: ").append(parents);
            buf.append("\n\tchildren: ").append(children);
        } else
            buf.append("; has " + children.size() + " children.");

        return buf.toString();
    }

    public static void main(String[] args) {
        // create some new rabbits
        try {
            if (args.length == 2 && args[0].equals("breed")) {
                int iters = Integer.parseInt(args[1]);
                breed(iters);
                return;
            }
        } catch (NumberFormatException e) {
        }

        // if we get here, something went wrong
        System.out.println("Usage:");
        System.out.println("\tjava tutorial.Rabbit breed 'iterations'");
    }

    /**
     * Find two random compatible rabbits in the database, toss them
     * in a dark room for a little while, and repeat <code>iterations</code> 
     * times.
     */
    public static void breed(int iterations) {
        PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory 
            ("META-INF/jdo.properties");
        PersistenceManager pm = pmf.getPersistenceManager();
        Transaction t = pm.currentTransaction();
        t.begin();
        while (iterations > 0) {
            breedHelper(pm);
            iterations--;
        }
        t.commit();
        pm.close();
        pmf.close();
    }

    private static void breedHelper(PersistenceManager pm) {
        Random random = new Random();

        // find a female rabbit
        Query femaleQuery = pm.newQuery(Rabbit.class, 
            "isFemale == true && isDead == false");
        List females = (List) femaleQuery.execute();
        if (females.isEmpty())
            throw new RuntimeException("No females in db. Please create one.");
        Rabbit female = (Rabbit) females.get(random.nextInt(females.size()));

        // find a male rabbit
        Query maleQuery = pm.newQuery(Rabbit.class, 
            "isFemale == false && isDead == false");
        List males = (List) maleQuery.execute();
        if (males.isEmpty())
            throw new RuntimeException("No males in db. Please create one.");
        Rabbit male = (Rabbit) males.get(random.nextInt(males.size()));

        // breed the two
        for (int count = random.nextInt(3) + 1; count > 0; count--) {
            boolean isFemale = random.nextBoolean();
            String[] names;
            if (isFemale)
                names = femaleRabbitNames;
            else
                names = maleRabbitNames;
            String name = names[random.nextInt(names.length)];
            Rabbit kid = new Rabbit(name, female, male, isFemale);
            female.addChild(kid);
            male.addChild(kid);
            pm.makePersistent(kid);
            System.out.println("New rabbit born: " + kid);
        }
    }
}