/*
 * MegaMek - Copyright (C) 2005 Ben Mazur (bmazur@sev.org)
 *
 *  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.
 */

package megamek.common;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Hashtable;

import java.util.Vector;

import megamek.common.event.BoardListener;

/**
 */
public interface IBoard {

    /**
     * 
     * @return Map widht in hexes
     */
    public abstract int getWidth();

    /**
     * 
     * @return Map height in hexes
     */
    public abstract int getHeight();

    /**
     * Creates a new data set for the board, with the
     * specified dimensions and data; notifies listeners
     * that a new data set has been created.
     *
     * @param width  the width dimension.
     * @param height the height dimension.
     * @param data new hex data appropriate for the board.
     */
    public abstract void newData(int width, int height, IHex[] data);

    /**
     * Creates a new data set for the board, with the
     * specified dimensions; notifies listeners that a
     * new data set has been created.
     *
     * @param width the width dimension.
     * @param height the height dimension.
     */
    public abstract void newData(int width, int height);

    /**
     * Determines if this Board contains the (x, y) Coords,
     * and if so, returns the Hex at that position.
     *
     * @return the <code>Hex</code>, if this Board contains the (x, y)
     * location; <code>null</code> otherwise.
     *
     * @param x the x Coords.
     * @param y the y Coords.
     */
    public abstract IHex getHex(int x, int y);
    
    /**
     * Gets the hex in the specified direction from the specified starting
     * coordinates.
     * 
     * @return the hex in the specified direction from the specified starting
     *         coordinates.
     * 
     * @param c starting coordinates
     * @param dir direction
     */
    public abstract IHex getHexInDir(Coords c, int dir);

    public abstract Enumeration getHexesAtDistance(Coords coords, int distance);
    
    /**
     * Gets the hex in the specified direction from the specified starting
     * coordinates.
     *
     * Avoids calls to Coords.translated, and thus, object construction.
     *
     * @return the hex in the specified direction from the specified starting
     *         coordinates.
     * 
     * @param x starting x coordinate
     * @param y starting y coordinate
     * @param dir direction
     */
    public abstract IHex getHexInDir(int x, int y, int dir);
    
    /**
     * Initialize a hex and the hexes around it
     */
    public abstract void initializeAround(int x, int y);
    
    /**
     * Determines whether this Board "contains" the specified
     * Coords.
     *
     * @return <code>true</code> if the board contains the specified
     *         coords
     *
     * @param x the x Coords.
     * @param y the y Coords.
     */
    public abstract boolean contains(int x, int y);
    
    /**
     * Determines whether this Board "contains" the specified
     * Coords.
     * 
     * @return <code>true</code> if the board contains the specified
     *         coords
     *
     * @param c the Coords.
     */
    public abstract boolean contains(Coords c);
    
    /**
     * Returns the Hex at the specified Coords.
     *
     * @param c the Coords.
     */
    public abstract IHex getHex(Coords c);
    
    /**
     * Determines if this Board contains the (x, y) Coords,
     * and if so, sets the specified Hex into that position
     * and initializes it.
     *
     * @param x the x Coords.
     * @param y the y Coords.
     * @param hex the hex to be set into position.
     */
    public abstract void setHex(int x, int y, IHex hex);
    
    /**
     * Sets the hex into the location specified by the
     * Coords.
     *
     * @param c the Coords.
     * @param hex the hex to be set into position.
     */
    public abstract void setHex(Coords c, IHex hex);
    
    /**
     * Adds the specified board listener to receive
     * board events from this board.
     *
     * @param listener the board listener.
     */
    public abstract void addBoardListener(BoardListener listener);
    
    /**
     * Removes the specified board listener.
     *
     * @param listener the board listener.
     */
    public abstract void removeBoardListener(BoardListener listener);
    
    /**
     * Can the player deploy an entity here?
     * There are no canon rules for the deployment phase (?!).  I'm using
     * 3 hexes from map edge.
     */
    public abstract boolean isLegalDeployment(Coords c, Player p);
    
    /**
     * Record that the given coordinates have recieved a hit from an inferno.
     *
     * @param   coords - the <code>Coords</code> of the hit.
     * @param   round  - the kind of round that hit the hex.
     * @param   hits   - the <code>int</code> number of rounds that hit.
     *          If a negative number is passed, then an
     *          <code>IllegalArgumentException</code> will be thrown.
     */
    public abstract void addInfernoTo(Coords coords, InfernoTracker.Inferno round, int hits);

    /**
     * Extinguish inferno at the target hex.
     *
     * @param   coords - the <code>Coords</code> of the hit.
     */
    public abstract void removeInfernoFrom(Coords coords);
    
    /**
     * Determine if the given coordinates has a burning inferno.
     *
     * @param   coords - the <code>Coords</code> being checked.
     * @return  <code>true</code> if those coordinates have a burning
     *          inferno round. <code>false</code> if no inferno has hit
     *          those coordinates or if it has burned out.
     */
    public abstract boolean isInfernoBurning(Coords coords);
    
    /**
     * Record that a new round of burning has passed for the given coordinates.
     * This routine also determines if the fire is still burning.
     *
     * @param   coords - the <code>Coords</code> being checked.
     * @return  <code>true</code> if those coordinates have a burning
     *          inferno round. <code>false</code> if no inferno has hit
     *          those coordinates or if it has burned out.
     */
    public abstract boolean burnInferno(Coords coords);
    
    /**
     * Get an enumeration of all coordinates with infernos still burning.
     *
     * @return  an <code>Enumeration</code> of <code>Coords</code> that
     *          have infernos still burning.
     */
    public abstract Enumeration getInfernoBurningCoords();
    
    /**
     * returns a hash of the inferno trackers
     * 
     * @return an <code>Hashtable</code of <code>InfernoTrackers</code> on the board.
     */
    public abstract Hashtable getInfernos();
    
    /**
     * 
     * Determine the remaining number of turns the given coordinates will have
     * a burning inferno.
     *
     * @param   coords - the <code>Coords</code> being checked.
     *          This value must not be <code>null</code>.  Unchecked.
     * @return  the <code>int</code> number of burn turns left for all infernos
     *          This value will be non-negative.
     */
    public abstract int getInfernoBurnTurns(Coords coords);
    
    /**
     * 
     * Determine the remaining number of turns the given coordinates will have
     * a burning Inferno IV round.
     *
     * @param   coords - the <code>Coords</code> being checked.
     *          This value must not be <code>null</code>.  Unchecked.
     * @return  the <code>int</code> number of burn turns left for Arrow IV
     *          infernos.  This value will be non-negative.
     */
    public abstract int getInfernoIVBurnTurns(Coords coords);
    
    /**
     * Get an enumeration of all buildings on the board.
     *
     * @return  an <code>Enumeration</code> of <code>Building</code>s.
     */
    public abstract Enumeration getBuildings();
    
    /**
     * Get the building at the given coordinates.
     *
     * @param   coords - the <code>Coords</code> being examined.
     * @return  a <code>Building</code> object, if there is one at the
     *          given coordinates, otherwise a <code>null</code> will
     *          be returned.
     */
    public abstract Building getBuildingAt(Coords coords);

    /**
     * Collapse an array of buildings.
     *
     * @param   bldgs - the <code>Vector</code> of <code>Building</code>
     *          objects to be collapsed.
     */
    public abstract void collapseBuilding(Vector bldgs);
    
    /**
     * The given building has collapsed.  Remove it from the board and
     * replace it with rubble.
     *
     * @param   other - the <code>Building</code> that has collapsed.
     */
    public abstract void collapseBuilding(Building bldg);
    
    /**
     * Update the construction factors on an array of buildings.
     *
     * @param   bldgs - the <code>Vector</code> of <code>Building</code>
     *          objects to be updated.
     */
    public abstract void updateBuildingCF(Vector bldgs);

    /**
     * Get the current value of the "road auto-exit" option.
     *
     * @return  <code>true</code> if roads should automatically exit onto
     *          all adjacent pavement hexes.  <code>false</code> otherwise.
     */
    public abstract boolean getRoadsAutoExit();

    /**
     * Set the value of the "road auto-exit" option.
     *
     * @param   value - The value to set for the option; <code>true</code>
     *          if roads should automatically exit onto all adjacent pavement
     *          hexes.  <code>false</code> otherwise.
     */
    public abstract void setRoadsAutoExit(boolean value);

    /**
     * Loads this board from a filename in data/boards
     * @param filename filename to load from
     */
    public abstract void load(String filename);
    
    /**
     * Loads this board from an InputStream
     * @param is input stream
     */
    public abstract void load(InputStream is);

    /**
     * Writes data for the board, as text to the OutputStream
     * @param os output stream
     */
    public abstract void save(OutputStream os);
}