package sema;

import java.util.TreeSet;
import java.awt.Image;
import java.awt.Color;

/**
 * Square box. It's the pavement of the {@link Map}, used to draw the ground.
 * But it is also used as a hashtable, to detect the presence of <code>Elements</code>
 * in a given area of the map, without examining each element of the world. This is very
 * useful for the computations linked to collisions, or to searche for elements in an area of the world.
 * Is it typically used by the main application to refresh
 *  the drawing without unuseful computations ({@link SEMAbeans.ZGCarteSEMA#paintComponent(Graphics)}).
 */
public class Box{
    
    /**
     * Constructs a <code>Box</code>.
     * With his containing <code>Map</code>, his matrix coordinates, his height, his kind, and a main image.
     * @param map the map containing it.
     * @param drawing the drawing object of the simulation.
     * @param x the x-coordinate ( in the matrix of boxes, 0 is at the left)
     * @param y the x-coordinate ( in the matrix of boxes, 0 is at the top)
     * @param height the height.
     * @param kind the kind.
     * @param image The main image, used to draw itself and to create the icon.
     * @see Map
     * @see Drawing
     */
    public Box(Map map, Drawing drawing, int x, int y, float height, String kind, Image image) {
        this.map = map;
        this.x = x;
        this.y = y;
        this.height = height;
        this.kind = kind;
        map.boxes[x][y] = this;
        this.image = image;
        this.g  = drawing;
    }
    
    protected Map map;
    protected Drawing g;
    
    /**
     * the x-coordinate ( in the boxes' matrix 0 is at the left)
     */
    public final int x;
    /**
     * the y-coordinate ( in the boxes' matrix 0 is at the top)
     */
    public final int y;
    
    private float height;
    
    /**
     * Returns the height.
     * @return the height.
     */
    public float getHeight(){
        return height;
    }
    
    private String kind;
    
    /**
     * Returns the kind.
     * @return the kind.
     */
    public String getKind(){
        return kind;
    }
    
    protected Image image;
    /**
     * Returns the associated image (main image used to create icon and to draw the default)
     * @return the associated main image.
     */
    public Image getImage() {return image;}
    
    private TreeSet contents = new TreeSet(); //éléments contenus dans la case
    
    /**
     * Returns the registered <code>Elements</code> in the <code>Box</code>.
     * It returns a copy of the treeSet so that no external modification could be made.
     * @return the registered <code>Elements</code> in the <code>Box</code>.
     */
    public TreeSet getContents(){
        return (TreeSet)contents.clone();
    }
    
    /**
     * Determinate whether the <code>Box</code> can host the <code>Element</code>.
     * Very useful to design obstacles or restricted areas.
     * However, some special agents could ignore the advice of the box.
     * @param el the element to host.
     * @return whether the <code>Box</code> can host the <code>Element</code>.
     */
    public boolean isFreeFor(Element el){
        return true;
    }
    
    /**
     * Register an <code>Element</code> in the <code>Box</code>.
     * The call to this method should be made by : {@link Area#getIntersectedBoxes()}.
     * @param element the element to register.
     */
    public void register(Element element) {
        contents.add(element);
    }
    
    /**
     * Unregister an element from the <code>Box</code>.
     * The call to this method should be made by {@link Area#getIntersectedBoxes()} or {@link Element#death()}.
     * @param element the element to unregister.
     */
    public void unregister(Element element) {
        contents.remove(element);
    }
    
    /**
     * Returns the associated icon.
     * It has to be an icon of dimension smaller than 100x100.
     * It is used as the identity icon in the graphical interface.
     * By default it is the main image resized and transformed into an icon.
     * @return the associated icon.
     * @see javax.swing.Icon
     */
    public javax.swing.Icon getIcon() {
        if (image !=null) {
            float f = Math.max((float)image.getWidth(null)/100,(float)image.getHeight(null)/100);
            if (f==0) f=1;
            int x = (int)(image.getWidth(null)/f);
            int y = (int)(image.getHeight(null)/f);
            return(new javax.swing.ImageIcon(image.getScaledInstance(x,y,0)));
        } else return null;
    }
    
    /**
     * Draws the <code>Box</code>.
     * if the image is set it draw the image.
     */
    public void draw() {
        float bl = map.boxLength;
        g.setColor(Color.WHITE);
        g.fillRect(x*bl,y*bl,bl,bl);
        g.drawImage(image,x*bl,y*bl,bl,bl);
    }
    
    
    public void fill(Color c) {
        float bl = map.boxLength;
        g.setColor(c);
        g.fillRect(x*bl,y*bl,bl,bl);
    }
    
    public void drawBorder(Color c) {
        float bl = map.boxLength;
        g.setColor(c);
        g.drawRect(x*bl,y*bl,bl,bl);
    }
    
    /**
     * Highlight the <code>Box</code>.
     */
    public void highlight(Color c) {
        float bl = map.boxLength;
        g.setColor(c);
        g.fillRoundRect(x*bl,y*bl,bl,bl);
        g.setColor(Color.BLACK);
        g.drawRoundRect(x*bl,y*bl,bl,bl);
    }
    
    /**
     * Highlight the <code>Box</code> (used when the box is selected)
     * With the default blue color for a box.
     */
    public void highlight() {
        highlight(new Color(0,0,1,.3f));
    }
    
    /**
     * Returns the box's properties.
     * @see Engine#getProperties()
     * @return the element's properties.
     */
    public String[][] getProperties() {
        String[][] ret = new String[5][2];
        String[] p1 = {"x",new Integer(x).toString()};
        String[] p2 = {"y",new Integer(y).toString()};
        String[] p3 = {"height",new Float(height).toString()};
        String[] p4 = {"kind",kind};
        String[] p5 = {"nb of elements", new Integer(contents.size()).toString()};
        ret[0] = p1; ret[1] = p2; ret[2] = p3; ret[3] = p4; ret[4] = p5;
        return(ret);
    }
    
    /**
     * Try to sets the value to the property of the box.
     * The new value is ignored if the property is read_only or if the value isn't valid.
     * @see Engine#setProperties
     * @param property the property to change.
     * @param value the new value for the property.
     */
    public void setProperties(String property, String value) {
        try { if (property.equals("height")) {
            height = Float.parseFloat(value);
        } else
            if (property.equals("kind")) {
            kind = value;
            }
        } catch (Exception e) {}
    }
    
}