package sema;

import java.awt.Color;
import java.util.Vector;


/**
 * Some area of a {@link Map}.
 * Often used to give a shape to an {@link Element}. <Br> All the methods verify that the <code>Area</code> does not go out of the <code>Map</code>.
 * In the instanciation, the <code>Area</code> is however authorized to be created out of the world.
 * It allows, for example, to create an <code>Element</code> which is not physically present on the <code>Map</code>.
 * @see Box#register(Element)
 * @see Box#unregister(Element)
 */
public interface Area {
    
    /**
     * Sets the element to which we want to link the area.
     * Indeed, when the area is used to represent the shape of an element, it must know him in order to manage the covered boxes.
     * @param el the corresponding element ( if one is used ).
     */
    public void setElement(Element el);
    
    /**
     * Returns the x-coordinate of the area's reference point.
     * This point is the one used to rotate around, and is used to represent
     * the coordinate of an element if one is tied to this shape.
     * @return the x-coordinate of the area's reference point.
     */
    public float getX();
    
    /**
     * Returns the y-coordinate of the area's reference point.
     * This point is the one used to rotate around, and is used to represent
     * the coordinate of an element if one is tied to this shape.
     * @return the y-coordinate of the area's reference point.
     */
    public float getY();
    
    /**
     * Modify the x-coordinate of the reference point, without going out of the <code Map> </code >.
     * Returns true if the modification is done, false otherwise.Renvoie true si la modification a eu lieu, false sinon.<br>
     * @param x the x-coordinate of the reference point.
     * @return whether the modification is done.
     * @see #getX()
     */
    public boolean setX(float x);
    
    /**
     * Modify the y-coordinate of the reference point, without going out of the <code Map> </code >.
     * Returns true if the modification is done, false otherwise.Renvoie true si la modification a eu lieu, false sinon.<br>
     * @param y the y-coordinate of the reference point.
     * @return whether the modification is done.
     * @see #getY()
     */
    public boolean setY(float y);
    
    /**
     * Returns the orientation ( in Radian )
     * @return the orientation ( in Radian )
     */
    public float getAngle();
    /**
     * Sets the orientation ( in radian )
     * Returns true if the modification is done, else false.
     * @param angle Sets the orientation ( in radian )
     * @return Returns true if the modification is done, else false.
     */
    public boolean setAngle(float angle);
    
    /**
     * Returns at least the boxes intersected by the area. A simplified vision can be used to computes the intersected boxes but il must respect this condition.
     * @return the boxes intersected by the area.
     * @see #setElement(Element)
     * @see Box#register(Element)
     * @see Box#unregister(Element)
     */
    public Vector getIntersectedBoxes();
    
    /**
     * Returns whether the point is in the area.
     * @param x the x-coordinate of the point.
     * @param y the y-coordinate of the point.
     * @return whether the point is in the area.
     */
    public boolean isIn(float x, float y);
    
    /**
     * Checks whether the area is included in te map.
     */
    public boolean inMap();
    
    /**
     * Returns true if there are other elements registered on the boxes where this area
     * is registered, or if the area is not included in the map.
     * Useful to quickly detect possible collisions between elements with a box centered vision.
     * This is a default method that can be called by an element to verify that his new position satisfies physical laws in 2D.
     * If it returns true, it means that the element has a valid position: he is in the map and does not share boxes with
     * other elements. But there could be false positives. The {@link #exactIsCrashingElements()} computes an exact result.
     * @return whether there are elements registered on the area's boxes.
     */
    public boolean isCrashingElements();
    public boolean isCrashingElements(Vector v);
    
    
    /**
     * Takes in argument a vector v returned by a simule method.
     * Returns true if there is any collision with the elements,
     * or if the area is not included in the map (going out of the map is, by default, considered as a crash with the map, and that means that v is null).
     * It computes a real intersection between the area of the elements registered in the covering boxes.
     * This is an exact method that can be called by an element to verify that his new position satisfies physical laws in 2D.
     * If it returns true, it means that the element has a valid position: he is in the map and does not intersect
     * other elements. There is no false positives. The {@link #isCrashingElements()} is a fast approximation of this method.
     * @return whether there are elements collision.
     */
    public boolean exactIsCrashingElements();
    public boolean exactIsCrashingElements(Vector v);
    
    /**
     * Returns a polygon aproximating the area.
     * It's represented as a vector of edges in the trigonometric order.
     * @return a polygone aproximating the area.
     */
    public Vector getPolygon();
    
    /**
     * Returns whether the area is a polygon.
     * @return whether the area is a polygon.
     */
    public boolean isPolygon();
    
    /**
     * Returns whether the area intersect the segment (ax,ay),(bx,by)
     * @param ax x-coordinate of the 'a' point.
     * @param ay y-coordinate of the 'a' point.
     * @param bx x-coordinate of the 'b' point.
     * @param by y-coordinate of the 'b' point.
     * @return whether the area intersect the segment (ax,ay),(bx,by)
     */
    public boolean intersect(float ax, float ay, float bx, float by);
    
    /**
     * Returns whether the area intersect these one.
     * Indeed it verify whether their is an intersection between the polygone of one with the other or the opposite.
     * It respects : a.intersect(b) == b.intersect(a).
     * @param a the area to test.
     * @return whether the area intersect these one.
     */
    public boolean intersect(Area a);
    
    /**
     * Returns whether the polygon intersects this area.
     * @param polygon the polygon to test.{@link #getPolygon()}
     * @return whether the polygon intersects this area.
     */
    public boolean intersect(Vector polygon);
    
    /**
     * Translates the area by the (x,y) vector without going out of the map.
     * Returns true if the modification is done (can be done).
     * @param x x-coordinate of the translation vector.
     * @param y x-coordinate of the translation vector.
     * @return true if the modification is done (can be done).
     */
    public boolean translate(float x, float y);
    /**
     * Rotates the area by the angle around the reference point {@link #getX()} without going out of the <code>Map</code>.
     * Returns true if the transformation has been done, false otherwise.
     * @param angle the angle of the rotation ( in radian )
     * @return true if the transformation has been done, false otherwise.
     */
    public boolean rotate(float angle);
    /**
     * Rescale by a 'x' and a 'y' factor without going out of the <code>Map</code>.
     * Returns true if the transformation has been done, false otherwise.
     * @param x the x-factor.
     * @param y the y-factor.
     * @return true if the transformation has been done, false otherwise.
     */
    public boolean rescale(float x, float y);
    
    /**
     * Returns the covering boxes which would result of the (x,y) translation of the area.
     * It's used to foresee your position and so determine whether you can move.
     * Null if out of the map.
     * @param x the x-coordinate of the translation.
     * @param y the y-coordinate of the translation.
     * @return the covering boxes which would result of the (x,y) translation of the area.
     */
    public Vector simuleTranslate(float x, float y);
    /**
     * Returns the covering boxes which would result of the rotation.
     * Null if out of the map.
     * @param angle the angle of the simulated rotation.
     * @return the covering boxes which would result of the rotation.
     */
    public Vector simuleRotate(float angle);
    /**
     * Returns the covering boxes which would result of the rescale.
     * Null if goes out of the map.
     * @param x the x-factor of the simulated rescale.
     * @param y the y-factor of the simulated rescale.
     * @return the covering boxes which would result of the rescale.
     */
    public Vector simuleRescale(float x, float y);
    
    /**
     * Confirms the last move simulated with a simule method of the area.
     * The interest of using these two separate fonctions is to allow the collision detections
     * or other computation before confirming the move. So, it is possible for an element to know
     * the boxes that it would occupy after a spcified move, and then it can decide whether this move
     * is suitable for it.
     * We gain a lot of time here, not computing two times the same thing.
     */
    public void confirmSimuled();
    
    /**
     * Draws the <code>Area</code> and eventually the image of the associated element.
     * It gives a default method to draw elements.
     * @param g the {@link Drawing} object containing the graphics context.
     */
    public void draw(Drawing g); //
    
    /**
     * Fills the area with the given color.
     */
    public void fill(Drawing g, Color c);
    
    /**
     * Draws the borders of the area with the given color.
     */
    public void drawBorder(Drawing g, Color c);

    /**
     * Highlights the <code>Area</code>. is used when it's selected in the interface.
     * It's better to give a transparent color in order to have something nice.
     * @param g the {@link Drawing} object.
     * @param c the {@link java.awt.Color} used to highlight.
     */
    public void highlight(Drawing g, Color c);
    
    /**
     * Returns the Area's properties.
     * @see Engine#getProperties()
     * @return the element's properties.
     */
    public String[][] getProperties();
    
    /**
     * Sets the value of a property of the area.
     * 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);
    
    /**
     * Clone the area.
     */
    public Object clone();
    
}
