/***********************************************************************

GECCO, a platform for command and control gaming

Copyright (C) 2001 Henrik Bäärnhielm, Andreas Enblom, Niklas
Hallenfur, Karl Hasselström, Henrik Hägerström, Oskar Linde, Jing Fu
Zi and Jon Åslund

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program 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
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.

***********************************************************************/

package gecco.game.firefighter;

import java.util.*;

import gecco.server.automaton.*;
import gecco.server.core.UnitEvent;

/**
 *  Description of the Class
 *
 */
public class AutomatonImpl extends Automaton {

    /**
     *  Description of the Field
     */
    int burningTime = 0;
    /**
     *  Description of the Field
     */
    int waterAmount = 0;

    /**
     *  Description of the Field
     */
    final static String FIRE_EVENT_STRING = "FIRE";
    /**
     *  Description of the Field
     */
    final static String WATER_EVENT_STRING = "WATER";
    /**
     *  Description of the Field
     */
    final static int BURNING_TREE = 2;
    /**
     *  Description of the Field
     */
    final static int NON_BURNING_TREE = 1;
    /**
     *  Description of the Field
     */
    final static int BURNT_TREE = 3;
    /**
     *  Description of the Field
     */
    final static int ROCK = 4;
    /**
     *  Description of the Field
     */
    final static int GROUND = 5;
    /**
     *  Description of the Field
     */
    final static int WATER = 6;
    /**
     *  Description of the Field
     */
    final static int HALF_BURNT_TREE = 7;

    /**
     *  Description of the Field
     */
    final static HashMap stateToColour = new HashMap();


    /**
     *  Gets the UnitEventForCurrentState attribute of the AutomatonImpl object
     *
     * @param  unitType  Description of Parameter
     * @return           The UnitEventForCurrentState value
     */
    public UnitEvent getUnitEventForCurrentState(String unitType) {
        //System.out.println("AutomatonImpl getUnitEventState() executed");
        //if (getState() != BURNING_TREE)
        return null;
        //return new UnitEvent("FIRE", 10);
    }


    /**
     *  Description of the Method
     *
     * @param  initialState                  Description of Parameter
     * @exception  IllegalArgumentException  Description of Exception
     */
    public void initialize(int initialState) throws IllegalArgumentException {
        //System.out.println("AutomatonImpl instanciated!");
        if (!stateToColour.keySet().contains(new Integer(initialState))) {
            throw new IllegalArgumentException("Non-existent state");
        }

        setColour(initialState);

    }


    /**
     *  Description of the Method
     *
     * @param  neighbourStates  Description of Parameter
     * @return                  Description of the Returned Value
     */
    public AutomatonReturn update(int[][] neighbourStates) {
        //System.out.println("AutomatonImpl update() executed");
        switch (getState()) {
            case NON_BURNING_TREE:
                // Icke-brinnande träd...
                // System.out.println("Normal tree!");
                if (existsNeighboursWithState(neighbourStates, BURNING_TREE)) {
                    if (Math.random() < 0.75) {
                        setColour(BURNING_TREE);
                    }
                    //		return new AutomatonReturnQueueSelfAndNeighbours(2.0, 2.0);
                    // }
                    //else {
                    return new AutomatonReturnQueueSelfAndNeighbours(7.0, 7.0);
                }
                break;
            case BURNING_TREE:
                // Brinnande träd...
                // System.out.println("Burning tree!");
                burningTime += 1;
                if (Math.random() > burningTime / 10) {
                    // Har inte brunnit klart, kasta in grannar och själv i kön...
                    return fireReturn(neighbourStates);
                } else {
                    setColour(BURNT_TREE);
                }
                break;
            case BURNT_TREE:
                // Nedbränt träd...
                // Do nothing...
                break;
            case ROCK:
                // Berg
                break;
            case GROUND:
                // Mark
                break;
            case WATER:
                // Vatten
                break;
            case HALF_BURNT_TREE:
                break;
            default:
            // Strange...
        }
        return new AutomatonReturnNoAction();
    }


    /**
     *  Description of the Method
     *
     * @param  event  Description of Parameter
     * @return        Description of the Returned Value
     */
    public AutomatonReturn handleEvent(AutomatonEvent event) {
        //System.out.println("AutomatonImpl handleEvent() executed");

        if (event.getEventName().equals(FIRE_EVENT_STRING)) {
            // DET BRINNER! YEEEEHHHAAAAA!!!
            if (getState() == NON_BURNING_TREE) {
                // Jag är ett träd och börjar nu brinna!
                setColour(BURNING_TREE);
                return new AutomatonReturnQueueSelfAndNeighbours(3.0, 7.0);
            }
        }
        if (event.getEventName().equals(WATER_EVENT_STRING)) {
            // Någon har sprutat vatten på automaten
            if (getState() == BURNING_TREE) {
                //		waterAmount += event.getFactor();
                //		if (Math.random() < waterAmount / 100) {
                setColour(HALF_BURNT_TREE);
                //		    System.out.println("Switching state to halfburnt tree!");
                //		}
            }
        }
        return new AutomatonReturnNoAction();
    }


    /**
     *  Sets the Colour attribute of the AutomatonImpl object
     *
     * @param  state                         The new Colour value
     * @exception  IllegalArgumentException  Description of Exception
     */
    private void setColour(int state) throws IllegalArgumentException {
        if (!stateToColour.keySet().contains(new Integer(state))) {
            throw new IllegalArgumentException("Non-existent state");
        }

        Integer[] colours = (Integer[]) stateToColour.get(new Integer(state));
        if (colours != null) {
            setCurrentColor(colours[0].intValue(), colours[1].intValue(), colours[2].intValue());
        } else {
            throw new IllegalArgumentException("Non-existent state");
        }

        setState(state);
    }


    /**
     *  Description of the Method
     *
     * @param  neighbourStates  Description of Parameter
     * @return                  Description of the Returned Value
     */
    private AutomatonReturn fireReturn(int[][] neighbourStates) {
        // Kasta in alla grannar som inte redan brinner, och kasta in sig själv
        // för uppdatering om en liten stund.
        double[][] timeToExecute = new double[3][3];
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                int nState = neighbourStates[x][y];
                if (nState == NON_BURNING_TREE) {
                    // Icke-brinnande träd, ska börja brinna
                    timeToExecute[x][y] = 7.0 + Math.random() * 10;
                } else {
                    // Ska ej börja brinna
                    timeToExecute[x][y] = -1.0;
                }
            }
        }
        // Se till att automaten själv kastas in i kön
        timeToExecute[1][1] = 1.5 + Math.random() * 10;
        return new AutomatonReturnQueueSelective(timeToExecute);
    }


    /**
     *  Description of the Method
     *
     * @param  neighbourStates  Description of Parameter
     * @param  state            Description of Parameter
     * @return                  Description of the Returned Value
     */
    private boolean existsNeighboursWithState(int[][] neighbourStates,
            int state) {
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                if (neighbourStates[x][y] == state) {
                    return true;
                }
            }
        }
        return false;
    }

    static {
        Integer[] colours = new Integer[3];
        colours[0] = new Integer(206);
        colours[1] = new Integer(255);
        colours[2] = new Integer(198);
        stateToColour.put(new Integer(NON_BURNING_TREE), colours);
        colours = new Integer[3];
        colours[0] = new Integer(255);
        colours[1] = new Integer(70);
        colours[2] = new Integer(5);
        stateToColour.put(new Integer(BURNING_TREE), colours);
        colours = new Integer[3];
        colours[0] = new Integer(0);
        colours[1] = new Integer(0);
        colours[2] = new Integer(0);
        stateToColour.put(new Integer(BURNT_TREE), colours);
        colours = new Integer[3];
        colours[0] = new Integer(237);
        colours[1] = new Integer(192);
        colours[2] = new Integer(165);
        stateToColour.put(new Integer(ROCK), colours);
        colours = new Integer[3];
        colours[0] = new Integer(245);
        colours[1] = new Integer(90);
        colours[2] = new Integer(25);
        stateToColour.put(new Integer(GROUND), colours);
        colours = new Integer[3];
        colours[0] = new Integer(0);
        colours[1] = new Integer(151);
        colours[2] = new Integer(211);
        stateToColour.put(new Integer(WATER), colours);
        colours = new Integer[3];
        colours[0] = new Integer(42);
        colours[1] = new Integer(42);
        colours[2] = new Integer(42);
        stateToColour.put(new Integer(HALF_BURNT_TREE), colours);

    }
}
