package sema;

import java.awt.Graphics2D;
import java.util.TreeMap;


/**
 * Simulated world.
 * It has his {@link Engine}, his {@link Map},
 * his {@link Drawing} interface, his {@link Nature},and his {@link Element}s.
 */
public class World {
    
    /**
     *Constructs a World with an engine a map a drawing and a nature.
     *
     * Elements register itself to the world.
     */
    public World(Engine engine, Map map, Nature nature, Drawing drawing, String name, String comments){
	this.currentID = 0;
	this.engine = engine;
	this.map = map;
	this.nature = nature;
	this.elements = new TreeMap(); //on ajoutera les éléments du monde ensuite
	this.drawing = drawing;
	this.name = name;
	this.comments = comments;
    }
    
    /**
     * Default world
     */
    public World() {
	this.engine = new Engine();
	Box[][] boxes = new Box[0][0];
	this.map = new Map(0,0,1,boxes);
	this.nature = new Nature(engine,map);
	this.elements = new TreeMap();
	this.drawing = new Drawing(100,1,0,10,0,50,1,1, 100000, 200,0,0,1);
	this.name = "No simulation";
    }
    
    /**
     * Name of the world and comments.
     */
    private String name,comments;
    
    /**
     * Returns the name.
     */
    public String getName(){
	return name;
    }
    
    /**
     * Returns the comments.
     */
    public String getComments(){
	return comments;
    }
    
    /**
     * Draws some things of the world.
     * 
     */
    
    public void draw() {

    }
    
    /**
     * The engine associated with this world.
     */
    public final Engine engine ;
    
    /**
     * The drawing interface associated with this world.
     */
    public final Drawing drawing;
    
    /**
     * The map associated with this world.
     */
    public final Map map;
    
    /**
     * The Nature associated with this world.
     */
    public final Nature nature;
    
    private TreeMap elements;
    
    /**
     * Elements of the world.
     * The TreeMap associates an element to it's ID
     * Returns a copy of the real treemap.
     */
    public TreeMap getElements(){
	return (TreeMap)elements.clone();
    }
    
    /**
     * Unique ID associated with the elements.
     */
    private int currentID;
    private Integer newID() {
	return(new Integer(currentID++));
    }
    
    /**
     * Registers an element and returns its new ID.<br>
     * It's automatically called by the constructor of an <code>Element</code>.
     */
    protected Integer register(Element el) {
	Integer id = newID();
	elements.put(id,el);
	return id;
    }
    
    /**
     * Unregisters an element.
     * <br>It's automatically called when an element die ({@link Element#death}).
     */
    protected void unregister(Element el) {
	elements.remove(el.id);
    }
    
    /**
     * Returns the elements corresponding to the ID and null if the ID is not attributed.
     */
    public Element id2element(Integer id) {
	Element el = null;
	try {el = (Element)elements.get(id);} catch (Exception e) {};
	return el;
    }
    
    /**
     * Returns the properties of the world
     * @see Engine#getProperties()
     * @return the element's properties.
     */
    public String[][] getProperties() {
	String[][] ret = new String[3][2];
	String[] p1 = {"name",name};
	String[] p2 = {"comments",comments};
	String[] p4 = {"Number of elements",new Integer(elements.size()).toString()};
	ret[0] = p1; ret[1] = p2; ret[2] = p4;
	return(union(ret,union(map.getProperties(),union(nature.getProperties(),engine.getProperties()))));
    }
    
    private static String[][] union(String[][] p1, String[][] p2) { //fait l'union de deux listes de propriétés
	int n1 = p1.length;
	int n2 = p2.length;
	String[][] np = new String[n1+n2][2];
	for (int i=0; i<n1;i++) {
	    np[i] = p1[i];
	}
	for (int i=0; i<n2;i++) {
	    np[n1+i] = p2[i];
	}
	return(np);
    }
    
    /**
     * Try to sets the value to the property of the world.
     * The new value is ignored if the property is read_only or if the value isn't valid.
     * @see Engine#setProperties
     * @param s1 the property to change.
     * @param s2 the new value for the property.
     */
    public void setProperties(String s1, String s2) {
	map.setProperties(s1,s2);
	engine.setProperties(s1,s2);
	nature.setProperties(s1,s2);
    }
}