package tutorial.persistence.solutions;

import java.util.*;
import javax.persistence.*;

/**
 * A snake is an animal that is likely to eat rabbits.
 * This class will be used in Chapter V.
 */
@Entity(name = "Snake")
public class Snake
    extends Animal {

    // the resale price of a snake
    public static final float RESALE_PRICE = 150.0f;

    // member variable declarations go here
    @Basic
    @Column(name = "SNAKE_LENGTH")
    private short length = 0;

    // This list will be persisted into the database as
    // a one-to-many relation.
    @OneToMany(mappedBy = "eater")
    private Set<Rabbit> giTract = new HashSet<Rabbit>();

    /**
     * Constructor.
     *
     * @param name the name of this snake
     * @param feet the length of the snake, in feet
     */
    public Snake(String name, short feet) {
        super(name, RESALE_PRICE);
        length = feet;
    }

    public String toString(boolean detailed) {
        StringBuffer buf = new StringBuffer(1024);
        buf.append("Snake ").append(getName());

        if (detailed) {
            buf.append(" (").append(length).append(" feet long) sells for ");
            buf.append(getPrice()).append(" dollars.");
            buf.append("  Its gastrointestinal tract contains:\n");
            for (Rabbit rabbit : giTract)
                buf.append("\t").append(rabbit).append("\n");
        } else
            buf.append("; ate " + giTract.size() + " rabbits.");

        return buf.toString();
    }

    /**
     * Kills the specified rabbit and eats it.
     */
    public void eat(Rabbit dinner) {
        // Consume the rabbit.
        dinner.kill();
        dinner.setEater(this);
        giTract.add(dinner);
        System.out.println("Snake " + getName() + " ate rabbit "
            + dinner.getName() + ".");
    }

    /**
     * Locates the specified snake and tells it to eat a rabbit.
     */
    public static void eat(EntityManager em, String filter) {
        em.getTransaction().begin();

        // Find the desired snake(s) in the data store.
        Query query = em.createQuery(filter);
        List<Snake> results = query.getResultList();
        if (results.isEmpty()) {
            System.out.println("No snakes matching '" + filter + "' found");
            return;
        }

        Query uneatenQuery = em.createQuery
            ("select r from Rabbit r where r.isDead = false");
        Random random = new Random();
        for (Snake snake : results) {
            // Run a query for a rabbit whose 'isDead' field indicates
            // that it is alive.
            List<Rabbit> menu = uneatenQuery.getResultList();
            if (menu.isEmpty()) {
                System.out.println("No live rabbits in DB.");
                break;
            }

            // Select a random rabbit from the list.
            Rabbit dinner = menu.get(random.nextInt(menu.size()));

            // Perform the eating.
            System.out.println(snake + " is eating:");
            snake.eat(dinner);
        }

        em.getTransaction().commit();
    }

    public static void main(String[] args) {
        if (args.length == 2 && args[0].equals("eat")) {
            EntityManagerFactory emf = Persistence.
                createEntityManagerFactory(null);
            EntityManager em = emf.createEntityManager();
            eat(em, args[1]);
            em.close();
            emf.close();
            return;
        }

        // If we get here, something went wrong.
        System.out.println("Usage:");
        System.out.println("  java tutorial.Snake eat \"snakequery\"");
	}
}