package Interface;

import java.awt.CardLayout;
import java.awt.Color;
import java.io.File;
import java.io.RandomAccessFile;
import java.text.NumberFormat;
import javax.swing.JFormattedTextField;
import javax.swing.JOptionPane;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

import sema.Box;
import sema.Element;
import sema.Engine;
import sema.World;


/**
 * Class of the main frame of the graphic application.
 */
public class Sema extends javax.swing.JFrame {
    
    /**
     * Constructs the application window, with an empty world.
     */
    public Sema() {
        initComponents();
        setCenterPos(0,0);
        setEditing(false);
        semaThread.start();
        String s = (String) null;
        JOptionPane.setRootFrame(this);
    }
    
    
    ///////////////////////////////////////////////////////////
    //Monde simulé
    
    private final World defaultWorld = new World();
    private World world = defaultWorld;
    private int boxFactor = 0;
    private final SimFileRW ioSIM = new SimFileRW(); //gestion des entrées/sorties avec les fichiers SIM.
    private File currentfile;
    
    /**
     * Returns the current world.
     * @return  the current world
     */
    public World getWorld() {
        return world;
    }
    /**
     * Sets the world to simulate.
     * @param m the new world to use. If <code>null</code>, then doesn't change anything.
     */
    public void setWorld(World m){
        if (m==null) return;
        buttonaddEl.setEnabled(true);
        hasEnded = false;
        setPause(true);
        
        world = m;
        zGCarte.init(world);
        
        zoomMin = world.drawing.minZoom;
        zoomMax = world.drawing.maxZoom;
        setZoom(world.drawing.getZoom());
        setDefaultZoom(world.drawing.getZoom());
        
        facteurTemporelMin = world.drawing.minTfactor;
        facteurTemporelMax = world.drawing.maxTfactor;
        setTimeFactor(world.drawing.tFactor);
        
        
        setRealDisplayDelay(world.drawing.realDelay);
        setVirtualDisplayDelay(world.drawing.virtualDelay);
        
        checkActivateRDelay.setSelected(true);
        checkActivateVDelay.setSelected(false);
        lastRDelay = -1;
        lastVDelay = world.drawing.virtualDelay;
        
        setCenterPos(world.drawing.centerX,world.drawing.centerY);
        
        setSelectedElement(null);
        
        zGCarte.setSelectedBox(null);
        selectedBox = null;
        iconTerrain.setIcon(null);
        refreshTableBox();
        choixIndiv.removeAllItems();
        labelAchievedTF.setText("");
        
        wasRunning = false;
        pause_temp = false;
        semaThread.init();
        
        repaint();
    }
    private boolean loadCurrentWorld(){
        try {
            currentfile = simChooser.getSelectedFile();
            setWorld(ioSIM.open(currentfile,boxFactor));
            if (world!=null & currentfile !=null)
                setTitle("SEMA - "+world.getName()+" ("+currentfile+")");
            else
                setTitle("SEMA");
            return true;
        } catch (SimFileRW.InvalidSIMfile e) {
            JOptionPane.showMessageDialog(null,e.getMessage(), "Error in SEMA: invalid SIM file", JOptionPane.WARNING_MESSAGE);
            return false;
        }
    }
    private boolean selectWorld() {
        setPause(true);
        simChooser.setApproveButtonText("Open");
        if (simChooser.showOpenDialog(this) == simChooser.APPROVE_OPTION) {
            boxFactor = 1;
            return loadCurrentWorld();
        } else return false;
    }
    
    
    
    /////////////////////////////////////////////////////////////
    //Zoom
    
    private float zoom;
    private float defaultZoom;
    private float zoomMax;
    private float zoomMin;
    /**
     * Returns the current zoom.
     * @return the current zoom.
     */
    public float getZoom() {
        return zoom;
    }
    /**
     * Sets the zoom to z.
     * @param z the new zoom value.
     */
    public void setZoom(float z) {
        sliderZoom.setValue(zoomToSlider(z));
        Float value = new Float(z);
        fieldZoom.setValue(value);
        zoom = z;
        world.drawing.setZoom(z);
        resizeZonePreview();
        repaint();
    }
    /**
     * Returns the default zoom.
     * @return the default zoom
     */
    public float getdefaultZoom(){
        return defaultZoom;
    }
    /**
     * Sets the default zoom.
     * @param z the new default zoom.
     */
    public void setDefaultZoom(float z){
        defaultZoom = z;
    }
    private void resizeZonePreview() {
        float pbu = world.drawing.getPixelsByUnit(); //change avec le zoom
        float widthu = (float)zGCarte.getWidth()/pbu;
        float heightu = (float)zGCarte.getHeight()/pbu;
        zGApercu.setZoneSize(widthu/world.map.xLength,heightu/world.map.yLength);
    }
    
    
    
    //////////////////////////////////////////////////////////////
    //Position
    
    private float cxu;
    private float cyu;
    /**
     * Returns the current X-coordinate of the center of the view, in simulated unit.
     * @return the current X-coordinate of the center of the view, in simulated unit.
     */
    public float getCenterX() {
        return cxu;
    }
    /**
     * Returns the current Y-coordinate of the center of the view, in simulated unit.
     * @return the current Y-coordinate of the center of the view, in simulated unit.
     */
    public float getCenterY() {
        return cyu;
    }
    /**
     * Sets the center of the view.
     * @param X the X-coordinate in simulated unit
     * @param Y the Y-coordinate in simulated unit
     */
    public void setCenterPos(float X, float Y) {
        float bl2 = world.map.boxLength/2;
        //on vérifie les bornes
        if(X<bl2) X = bl2; else if (X>world.map.xLength-bl2) X = world.map.xLength-bl2;
        if(Y<bl2) Y = bl2; else if (Y>world.map.yLength-bl2) Y = world.map.yLength-bl2;
        //on calcul le coin supérieur gauche
        cxu = X;
        cyu = Y;
        //on actualise les valeurs
        float pbu = world.drawing.getPixelsByUnit();
        zGCarte.setCenterXu(cxu);
        zGCarte.setCenterYu(cyu);
        zGApercu.setCenterPosition(cxu/world.map.xLength,cyu/world.map.yLength);
    }
    /**
     * Move the view in order to center the selected element.
     */
    public void centerSelectedElement() {
        if(selectedElement != null) {
            setCenterPos(selectedElement.getArea().getX(), selectedElement.getArea().getY());
            repaint();
        }
    }
    /**
     * Move the view in order to center the selected Box.
     */
    public void centerSelectedBox(){
        if(selectedBox !=null) {
            float ubb = world.map.boxLength;
            setCenterPos(selectedBox.x*ubb+ubb/2,selectedBox.y*ubb+ubb/2);
            repaint();
        }
    }
    
    
    //////////////////////////////////////////////////////////////
    //Time Factor
    
    private float timeFactor;
    private float facteurTemporelMax;
    private float facteurTemporelMin;
    private void changeTimeFactor(float f) {
        timeFactor = f;
        refreshDelaiVirtuelAffSynchronized();
        semaThread.interrupt();
    }
    /**
     * Returns the current time factor.
     * @return the current time factor.
     */
    public float getTimeFactor(){
        return timeFactor;
    }
    /**
     * Sets the time factor.
     * @param z new time factor.
     */
    public void setTimeFactor(float z) {
        Float value = new Float(z);
        fieldFacteurTemporel.setValue(value);
        fieldZoomPropertyChange(new java.beans.PropertyChangeEvent(this,"value",null,value));
    }
    private void displayRealTimeFactor(double d) {
        labelAchievedTF.setText(Double.toString(d));
        if (d<timeFactor*.95) labelAchievedTF.setForeground(Color.RED);
        else labelAchievedTF.setForeground(Color.BLACK);
    }
    
    
    
    //////////////////////////////////////////////////////////////
    //Display delays
    
    private long RealDisplayDelay;
    private double VirtualDisplayDelay;
    private boolean timeFactorEnabled = true;
    private long lastRDelay = -1;
    private double lastVDelay = -1;
    private double delaiVirtuelAffSynchronized = Math.min((float)VirtualDisplayDelay,(float)RealDisplayDelay*timeFactor);
    /**
     * Returns the delay of real time between two drawings of the world.
     * The effective real delay is less or equal to this one, depending on the virtual display delay.
     * @see #getVirtualDisplayDelay()
     * @return the delay of real time (in millisecondes) between two internal calls to repaint().
     */
    public long getRealDisplayDelay() {
        return RealDisplayDelay;
    }
    /**
     * Returns the delay of virtual time between two drawings of the world.
     * The effective virtual delay is less or equal to this one depending on the real display delay.
     * @see #getRealDisplayDelay()
     * @return the delay of virtual time (in millisecondes) between two internal calls to repaint().
     */
    public double getVirtualDisplayDelay() {
        return VirtualDisplayDelay;
    }
    private void changeRealDisplayDelay(long t) {
        RealDisplayDelay = t;
        refreshDelaiVirtuelAffSynchronized();
        semaThread.interrupt();
    }
    /**
     * Sets the real display delay.
     * @see #getRealDisplayDelay()
     * @param t the new real display delay.
     */
    public void setRealDisplayDelay(long t) {
        changeRealDisplayDelay(t);
        fieldDelaiReel.setValue(new Double(t));
    }
    private void changeVirtualDisplayDelay(double t) {
        VirtualDisplayDelay = t;
        refreshDelaiVirtuelAffSynchronized();
        semaThread.interrupt();
    }
    /**
     * Sets the virtual display delay.
     * @see #getVirtualDisplayDelay()
     * @param t the new virtual display delay.
     */
    public void setVirtualDisplayDelay(double t) {
        changeVirtualDisplayDelay(t);
        fieldDelaiVirtuel.setValue(new Double(t));
    }
    private void refreshDelaiVirtuelAffSynchronized(){
        if (timeFactorEnabled)
            delaiVirtuelAffSynchronized = Math.min(VirtualDisplayDelay,RealDisplayDelay*timeFactor);
        else delaiVirtuelAffSynchronized = VirtualDisplayDelay;
    }
    
    
    //////////////////////////////////////////////////////////////////////////
    // Gestion des Threads (écoulement du temps simulé par rapport au temps réel et l'affichage)
    
    private SEMAThread semaThread = new SEMAThread();
    private static Object calcul = new int[1];
    private static Object run = new int[1];
    private class SEMAThread extends Thread {
        
        private double lastDrawVirtualDate,virtualDuration;
        private long lastDrawRealDate,realDuration,attente;
        
        public void init() { //initialise l'affichage et les temps courants (simulés et réels)
            repaint();
            lastDrawVirtualDate = 1000.*world.engine.getTime();
            lastDrawRealDate = System.currentTimeMillis();
        }
        
        private void wait_run() {
            while(!isRunning) try {synchronized (run) {run.wait();}} catch
                    (Exception e) {
            }
        }
        
        public void run() {
            wait_run();// attend avant d'initialiser les valeurs d'être running
            init();
            if (world != null) {
                while(true) {
                    wait_run();
                    synchronized ( run ) { // lock en position running
                        next(); //on effectue le calcul pour le suivant
                    }
                    
                    double currentVirtualDate = 1000.*world.engine.getTime();
                    virtualDuration = currentVirtualDate-lastDrawVirtualDate; //durée simulée depuis le dernier affichage
                    realDuration = System.currentTimeMillis()-lastDrawRealDate; //durée réelle du calcul depuis le dernier affichage
                    
                    //ICI, COEUR DU SYNCHRONISME ENTRE CALCUL DE LA SIMULATION ET AFFICHAGE
                    if ((virtualDuration>delaiVirtuelAffSynchronized) || (realDuration > RealDisplayDelay )) { //si on a suffisamment calculé...
                        long attente = (long)(virtualDuration/timeFactor)-realDuration; //temps à attendre pour respecter le facteur temporel
                        if (attente>0 && timeFactorEnabled)
                            try {
                                Thread.sleep(attente); //toute la puissance de calcul n'est pas utilisée...
                            } catch (Exception e) {}
                        repaint(); //affichage de l'état actuel de la simulation
                        long lastDrawRealDateTemp = System.currentTimeMillis();
                        displayRealTimeFactor(virtualDuration/(lastDrawRealDateTemp-lastDrawRealDate));
                        lastDrawVirtualDate = currentVirtualDate;
                        lastDrawRealDate = lastDrawRealDateTemp;
                    }
                }
            }
        }
    }
    
    /**
     * Go to the next date, executing events registered at this date.
     * It's synchronized with the display so that the display is coherent
     * and prevents from concurrent access to the world.
     * (coherent because the next method of the engine executes all the events registered at
     * the precise time, and so, there is no refresh in a odd state of the virtual time)
     * @see sema.Engine#next()
     */
    public void next() {
        try {
            synchronized( calcul ) { //lock l'affichage
                world.engine.next();
            }
        } catch (Engine.EndOfSimulation e) {
            JOptionPane.showMessageDialog(null,"END OF SIMULATION (no more events)", "The end...", JOptionPane.WARNING_MESSAGE);
            setPause(true);
            hasEnded = true;
        } catch (Engine.SimulationError e) {
            JOptionPane.showMessageDialog(null,"An error occured while treating the current event.\nSimulation was paused, but you can resume it."+e.toString(), "Simulation error", JOptionPane.WARNING_MESSAGE);
            setPause(true);
        }
    }
    /**
     * Go to the indicated date without refreshing nor wainting.
     * @param t the date to go to.
     * @see sema.Engine#gotoDate(Double)
     */
    public void goToDate(double t) {
        try {
            synchronized( calcul ) { //lock l'affichage
                world.engine.gotoDate(new Double(t));
            }
        } catch (Engine.EndOfSimulation e) {
            JOptionPane.showMessageDialog(null,"END OF SIMULATION (no more events)", "The end...", JOptionPane.WARNING_MESSAGE);
            hasEnded = true;
            setPause(true);
        } catch (Engine.SimulationError e) {
            JOptionPane.showMessageDialog(null,"An error occured while treating the current event.\nSimulation was paused, but you can resume it."+e.getMessage(), "Simulation error", JOptionPane.WARNING_MESSAGE);
            setPause(true);
        }
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // Gestion de la pause
    
    /**
     * Pause or resume the simulation.
     * @param pause mode.
     */
    public void setPause(boolean pause) {
        if (pause) {
            isRunning = false;
            wasRunning = false;
            semaThread.interrupt();
            checkPause.setSelected(true);
            repaint();
        } else {
            if (hasEnded) {
                checkPause.setSelected(true);
                JOptionPane.showMessageDialog(null,"END OF SIMULATION (no more events)", "The end...", JOptionPane.WARNING_MESSAGE);
            } else  {
                resume();
                checkPause.setSelected(false);
            }
        }
    }
    private void resume() {
        synchronized(run) {
            try {
                semaThread.init();
                isRunning = true;
                run.notifyAll();
            } catch (Exception e) {}
        }
    }
    private void pause_temporaire() {
        if (isRunning) {
            wasRunning = true;
            isRunning = false;
            semaThread.interrupt();
        } else if (!pause_temp) wasRunning = false;
        pause_temp = true;
    }
    private void resume_temporaire() {
        if (wasRunning) resume();
        pause_temp = false;
    }
    
    
    ///////////////////////////////////////////////////////////////////////
    // Gestion de la Selection
    
    private class ChoixObject {
        public ChoixObject(Element e) {
            this.e = e;
        }
        public String toString() {
            if (e==null) return "(none)"; else
                return e.getName();
        }
        public Element e;
    }
    /**
     * Sets selection at the given point.
     * It computes the corresponding box and element,
     * and call setSelectedElement ans setSelectedBox with the right arguments.
     * @param x the X-coordinate (in simulated unit) of the selection point.
     * @param y the Y-coordinate (in simulated unit) of the selection point.
     * @see #setSelectedElement(Element e)
     * @see #setSelectedBox(Box b)
     */
    public void setSelection(float x, float y) {
        synchronized(run) {
            
            setSelectedBox(world.map.boxes[(int)(x/world.map.boxLength)][(int)(y/world.map.boxLength)]);
            
            choixIndiv.removeAllItems(); //actualise la liste des éléments du choix
            java.util.Iterator i = selectedBox.getContents().iterator();
            float bestDistance = world.map.xLength+world.map.yLength;
            Element element = null;
            Element currentEl;
            ChoixObject selectedItem = new ChoixObject(null);
            float currentD;
            choixIndiv.addItem(selectedItem);
            while(i.hasNext()) { //choix de l'individu de la case sélectionnée, le plus proche du point cliqué
                currentEl = (Element)i.next();
                ChoixObject currentItem = new ChoixObject(currentEl);
                choixIndiv.addItem(currentItem);
                currentD = (currentEl.getArea().getX()-x)*(currentEl.getArea().getX()-x) + (currentEl.getArea().getY()-y)*(currentEl.getArea().getY()-y);
                if (currentD <= bestDistance & currentEl.getArea().isIn(x,y)) {
                    bestDistance = currentD;
                    element = currentEl;
                    selectedItem = currentItem;
                }
            }
            choixIndiv.setSelectedItem(selectedItem);
            //if (element!=null) //on peut vouloir cliquer là où il n'y a pas d'élément pour le déslectionner, c naturel
            setSelectedElement(element);
        }
        repaint();
    }
    
    
    
    ////////////////////////////////////////////////////////////////////////
    // Selected Box
    
    private Box selectedBox;
    /**
     * Sets the selected box.
     * @param b the box to set selected.
     */
    public void setSelectedBox(Box b) {
        if(b!=null) {iconTerrain.setIcon(b.getIcon());} else iconTerrain.setIcon(null);
        selectedBox = b;
        zGCarte.setSelectedBox(selectedBox);
        refreshTableBox();
        repaint();
    }
    
    
    ////////////////////////////////////////////////////////////////////////
    // Selected Element
    
    private Element selectedElement;
    /**
     * Sets the selected element.
     * @param e the element to set selected.
     */
    public void setSelectedElement(Element e) {
        selectedElement = e;
        if (e!=null) {
            iconIndiv.setIcon(e.getIcon());
            checkMarked.setSelected(e.isMarked());
        } else
            iconIndiv.setIcon(null);
        
        zGCarte.setSelectedElement(e);
        refreshTableElement();
        repaint();
    }
    
    
    ////////////////////////////////////////////////////////////////////////
    // Affichage synchronisé avec le contenu : met en pause les next et assure de ne pas etre au milieu d'un next
    
    private void refreshTableElement() {
        if (selectedElement != null) {
            final Object[] colonneNom = {"Property","Value"};
            tablePropIndiv.setModel(new DefaultTableModel(selectedElement.getProperties(),colonneNom));
            tablePropIndiv.getModel().addTableModelListener(new TableModelListener() {
                public void tableChanged(TableModelEvent e) {
                    int row = e.getFirstRow();
                    String s1 = (String) tablePropIndiv.getModel().getValueAt(row,0);
                    String s2 = (String) tablePropIndiv.getModel().getValueAt(row,1);
                    selectedElement.setProperties(s1,s2);
                    ioSIM.elementChanged(selectedElement);
                    refreshTableElement();
                    repaint();
                }
            });
        } else {
            tablePropIndiv.setModel(new javax.swing.table.DefaultTableModel(new Object [][] {{null, null}},	new String [] {"Properties", "Values"}));
        }
    }
    private void refreshTableBox(){
        if (selectedBox != null) {
            final Object[] colonneNom = {"Property","Value"};
            tablePropTerrain.setModel(new DefaultTableModel(selectedBox.getProperties(),colonneNom));
            tablePropTerrain.getModel().addTableModelListener(new TableModelListener() {
                public void tableChanged(TableModelEvent e) {
                    int row = e.getFirstRow();
                    String s1 = (String) tablePropTerrain.getModel().getValueAt(row,0);
                    String s2 = (String) tablePropTerrain.getModel().getValueAt(row,1);
                    selectedBox.setProperties(s1,s2);
                    ioSIM.boxChanged(selectedBox);
                    refreshTableBox();
                    repaint();
                }
            });
        } else {
            tablePropTerrain.setModel(new javax.swing.table.DefaultTableModel(new Object [][] {{null, null}},	new String [] {"Properties", "Values"}));
        }
    }
    private void refreshTableMonde() {
        if(world != null && world != defaultWorld) {
            final Object[] colonneNom = {"Property","Value"};
            tablePropMonde.setModel(new DefaultTableModel(world.getProperties(),colonneNom));
            tablePropMonde.getModel().addTableModelListener(new TableModelListener() {
                public void tableChanged(TableModelEvent e) {
                    int row = e.getFirstRow();
                    String s1 = (String) tablePropMonde.getModel().getValueAt(row,0);
                    String s2 = (String) tablePropMonde.getModel().getValueAt(row,1);
                    world.setProperties(s1,s2);
                    refreshTableMonde();
                    repaint();
                }
            });
        } else tablePropMonde.setModel(new javax.swing.table.DefaultTableModel(new Object [][] {{null, null}},	new String [] {"Properties", "Values"}));
    }
    /**
     * Paints the component synchronized with the simulation.
     * painting and next calls to the engine are never simultaneous,
     * so that during the painting process, the state of the world is fixed and not odd.
     * @param g the Graphics context in which to paint
     * @see #next()
     */
    public void paint(java.awt.Graphics g) {
        synchronized (calcul) {
            if(isFollowing && selectedElement != null)
                setCenterPos(selectedElement.getArea().getX(), selectedElement.getArea().getY());
            if(fieldDate != null)
                fieldDate.setValue(new Double(world.engine.getTime()));
            refreshTableMonde();
            refreshTableElement();
            refreshTableBox();
            super.paint(g);
        }
    }
    
    
    ///////////////////////////////////////////////////////////////////////
    // Modes d'éditions, d'interaction avec la carte, etc.
    
    private boolean isMouvingElement = false;
    private boolean isEditing = true;
    private boolean isFollowing = false;
    private boolean wasRunning = false;
    private boolean pause_temp = false;
    private boolean isRunning = false;
    private boolean hasEnded = true;
    /**
     * Return the current editing state.
     * (true if editing, false if simulating)
     * @return the current editing state.
     */
    public boolean getIsEditing() {
        return isEditing;
    }
    /**
     * Sets the editing state.
     * @param b the editing state.
     */
    public void setEditing(boolean b) {
        
        isEditing = b;
        if (b) {
            ((CardLayout)barreDoutil.getLayout()).show(barreDoutil, "EditingCard");
            if (world!=null & currentfile !=null)
                setTitle("SEMA - "+world.getName()+" ("+currentfile+")"+" [EDITING]");
            else
                setTitle("SEMA");
        } else {
            ((CardLayout)barreDoutil.getLayout()).show(barreDoutil, "SimulatingCard");
            if (world!=null & currentfile !=null)
                setTitle("SEMA - "+world.getName()+" ("+currentfile+")");
            else
                setTitle("SEMA");
        }
        
        
        buttonaddEl.setVisible(!b);
        checkLock.setSelected(!b);
    }
    
    
    ///////////////////////////////////////////////////////////////////////
    // Edition
    
    private String lastCodeEntered = "sema.Agent(sema.Area modelling.RectangularArea(selfType map, float 1, float 1, float 1, float 1),float 1, Image \"filename\")";
    /**
     * If in editing mode, asks the user for the string code of a new element
     * and add it to the current world.
     */
    public void addEl() {
        if (world != null) {
            String s = JOptionPane.showInputDialog(null, "Give the code of the element: ", lastCodeEntered);
            if (s == null) return;
            try {
                setSelectedElement(ioSIM.addElement(s,world));
                centerSelectedElement();
            } catch (Exception e) {
                JOptionPane.showMessageDialog(null,"Unable to add element : "+e.getMessage(),"Error while adding element",JOptionPane.ERROR_MESSAGE);
            }
            repaint();
        }
    }
    /**
     * Kill the selected element after asking for a confirmation.
     */
    public void killSelected(){
        if (selectedElement != null) {
            int r = JOptionPane.showConfirmDialog(null,"Confirm kill of "+selectedElement.toString(),"Kill element",JOptionPane.YES_NO_OPTION,JOptionPane.WARNING_MESSAGE);
            if (r == JOptionPane.OK_OPTION) { //deletion
                if (selectedElement.kill(null)) {
                    setSelectedElement(null);
                } else JOptionPane.showMessageDialog(null,"Impossible to kill "+selectedElement.toString(),"Kill element echec",JOptionPane.WARNING_MESSAGE);
            }
        }
    }
    
    /////////////////////////////////////////////////////////////////////////
    //File fonctions
    
    private void save() {
        try {
            //attention, le bouton sauver ne doit être activé que quand boxFactor = 1 sinon c la merde...
            if (boxFactor!= 1) {throw(new Exception("boxfactor != 1 !! impossible de sauver"));}
            simChooser.setApproveButtonText("Save");
            if (simChooser.showOpenDialog(this) == simChooser.APPROVE_OPTION) {
                currentfile = simChooser.getSelectedFile();
                ioSIM.save(currentfile, world);
            }
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null,"Unknown Error Occurred during save");
        }
    }
    private boolean confirmResetAction(String action) {
        if (isEditing) {
            int r = JOptionPane.showConfirmDialog(null,"Do you want to save ?","Save",JOptionPane.YES_NO_CANCEL_OPTION);
            if (r == JOptionPane.YES_OPTION) save();
            else if (r!=JOptionPane.NO_OPTION)
                return false;
        } else if(world != null && world != defaultWorld) {
            int r = JOptionPane.showConfirmDialog(null,action+" will erase current state.","Are you sure?",JOptionPane.YES_NO_OPTION,JOptionPane.WARNING_MESSAGE);
            if (r != JOptionPane.YES_OPTION) return false;
        }
        return true;
    }
    /**
     * Resets the simulation with the current file.
     * Asks for user confirmation.
     * @param withBoxfactor says whether we will ask for a boxfactor or use the sim one.
     */
    public void reset(boolean withBoxfactor) {
        if (confirmResetAction("Reseting the simulation")) {
            if (currentfile!=null) {
                if (withBoxfactor) { //on demande le box factor
                    int i = -1;
                    while(i<0) {
                        try {
                            String s = JOptionPane.showInputDialog(null, "Box factor (a positive integer \nshouldn't be too high \n0 means sim default): ", "0");
                            if (s == null) return;
                            i = Integer.parseInt(s);
                        } catch (Exception e) {i = -1;}
                    }
                    boxFactor = i;
                }
                loadCurrentWorld();
            }
        }
    }
    /**
     * Asks confirmation and open a new simulation.
     */
    public void open() {
        if(confirmResetAction("Opening another simulation"))
            if (selectWorld())
                setEditing(false);
    }
    /**
     * Asks confirmation and open to edit a simulation.
     */
    public void edit() {
        if(confirmResetAction("Editing a simulation")) {
            boxFactor = 1; //à mettre AVANT l'appel à selectWorld!!
            if (selectWorld()) {
                setEditing(true); //à mettre après comme ca si le gars a annulé la fenetre de fichier on reste en seteditin ancienne valeur
            }
        }
    }
    /**
     * If in editing mode, run the current edited simulation.
     */
    public void run() {
        if(isEditing) {
            if (confirmResetAction("Running the simulation"))
                setEditing(false);
        }
    }
    /**
     * Creates a new simulation asking for severals parameters.
     */
    public void newSim() {
        if (confirmResetAction("Creating a new simulation")) {
            String fileContent = "";
            String last = "";
            while (last.equals("")) {
                last = JOptionPane.showInputDialog(null, "Simulation name: ", "");
                if (last==null) return; //user cancelled
            }
            fileContent = fileContent+"NAME="+last+"\n";
            
            int r = JOptionPane.showConfirmDialog(null,"Set 1 :\nYou'll have to choose some parameters of the map :\n -number of boxes\n -dimensions\n -default box type \nPress NO to skip step.", "STEP 1 of 4", JOptionPane.YES_NO_CANCEL_OPTION);
            if (r == JOptionPane.OK_OPTION) {
                last = JOptionPane.showInputDialog(null, "Number of boxes on X side: ", "10");
                fileContent = fileContent+"XMBOXES="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Number of boxes on Y side: ", "10");
                fileContent = fileContent+"YMBOXES="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Length of each square box (in simulated space units): ", "1");
                fileContent = fileContent+"MBOXLENGTH="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Number of pixels by box when zoom=1: ", "80");
                fileContent = fileContent+"PIXELSBYMBOX="+last+"\n";
            }
            if (r == JOptionPane.CANCEL_OPTION) return;
            
            r = JOptionPane.showConfirmDialog(null,"Step 2 :\nYou'll have to choose some parameters for the interface :\n -zoom\n -time factor,\n -delays \nPress NO to skip step.", "STEP 2 of 4", JOptionPane.YES_NO_CANCEL_OPTION);
            if (r== JOptionPane.YES_OPTION) {
                last = JOptionPane.showInputDialog(null, "Minimal zoom possible for this simulation: ", "0");
                fileContent = fileContent+"MINZOOM="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Maximal zoom possible for this simulation: ", "50");
                fileContent = fileContent+"MAXZOOM="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Default zoom for this simulation: ", "1");
                fileContent = fileContent+"ZOOM="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Minimal time factor possible for this simulation: ", "0");
                fileContent = fileContent+"MINTFACTOR="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Maximal time factor possible for this simulation: ", "100");
                fileContent = fileContent+"MAXTFACTOR="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Default time factor for this simulation: ", "1");
                fileContent = fileContent+"TFACTOR="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Default virtual display delay for this simulation: ", "20000");
                fileContent = fileContent+"VIRTUALDISPLAYDELAY="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Default real display delay for this simulation: ", "200");
                fileContent = fileContent+"REALDISPLAYDELAY="+last+"\n";
            }
            if (r == JOptionPane.CANCEL_OPTION) return;
            
            r =JOptionPane.showConfirmDialog(null,"Step 3 :\nYou can share images and declare variables.\nPress NO to skip step.", "STEP 3 of 4", JOptionPane.YES_NO_CANCEL_OPTION);
            if (r==JOptionPane.OK_OPTION) {
                last = "...";
                while (!last.equals("")) {
                    last = JOptionPane.showInputDialog(null, "New variable or image? Syntax: imageName=imagefile or #variable=value", "");
                    if (last == null) break;
                    fileContent = fileContent+last+"\n";
                }
            }
            if (r == JOptionPane.CANCEL_OPTION) return;
            
            r = JOptionPane.showConfirmDialog(null,"Step 4 :\nYou'll have to choose the classes to use for this simulation.\nThese classes must be accessible by Java (this means, in java/lib for example).\nThe default classes of Sema are always accessible.\nPress NO to skip step.", "STEP 4 of 4",JOptionPane.YES_NO_CANCEL_OPTION);
            if (r == JOptionPane.OK_OPTION) {
                last = JOptionPane.showInputDialog(null, "Engine class: ", "sema.Engine");
                fileContent = fileContent+"ENGINE="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Map class: ", "sema.Map");
                fileContent = fileContent+"MAP="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Drawing class: ", "sema.Drawing");
                fileContent = fileContent+"DRAWING="+last+"\n";
                last = JOptionPane.showInputDialog(null, "Nature class: ", "sema.Nature");
                fileContent = fileContent+"NATURE="+last+"\n";
                last = JOptionPane.showInputDialog(null, "World class: ", "sema.World");
                fileContent = fileContent+"MODELISATION="+last+"\n";
            }
            if (r==JOptionPane.CANCEL_OPTION) return;
            
            simChooser.setApproveButtonText("Create");
            if (simChooser.showOpenDialog(this) == simChooser.APPROVE_OPTION) {
                try {
                    currentfile = simChooser.getSelectedFile();
                    currentfile.delete();
                    currentfile.createNewFile();
                    RandomAccessFile ch = new RandomAccessFile(currentfile,"rw");
                    ch.writeBytes("//SIM file generated by Sema\n"+fileContent+"\n\nELEMENTS:\n");
                    ch.close();
                    if (loadCurrentWorld()) {
                        JOptionPane.showMessageDialog(null,"The new simulation has been created.", "Congratulations!", JOptionPane.INFORMATION_MESSAGE);
                        setEditing(true);
                    } else
                        JOptionPane.showMessageDialog(null,"Cannot create the new simulation. Invalid parameters.", "Sorry!", JOptionPane.WARNING_MESSAGE);
                    
                } catch (Exception e) {
                    JOptionPane.showMessageDialog(null,"Cannot create file: "+currentfile, "Sorry!", JOptionPane.WARNING_MESSAGE);
                }
                setEditing(true);
            }
        }
    }
    
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents
        java.awt.GridBagConstraints gridBagConstraints;

        simChooser = new javax.swing.JFileChooser();
        centerPanel = new javax.swing.JSplitPane();
        panelG_Carte = new javax.swing.JSplitPane();
        panelGauche = new javax.swing.JPanel();
        labelApercu = new javax.swing.JLabel();
        zGApercu = new SEMAbeans.ZGPreviewSEMA();
        sliderZoom = new javax.swing.JSlider();
        zoomOptions = new javax.swing.JPanel();
        fieldZoom = new JFormattedTextField(NumberFormat.getInstance());
        buttonFit = new javax.swing.JButton();
        Default = new javax.swing.JButton();
        jSeparator1 = new javax.swing.JSeparator();
        labelPropMonde = new javax.swing.JLabel();
        panelpropWorld = new java.awt.Panel();
        jScrollPane1 = new javax.swing.JScrollPane();
        tablePropMonde = new javax.swing.JTable();
        zGCarte = new SEMAbeans.ZGCarteSEMA();
        PanelDroit = new javax.swing.JSplitPane();
        paneDroitHaut = new java.awt.Panel();
        groundPanel = new javax.swing.JPanel();
        iconTerrain = new javax.swing.JLabel();
        GroundOptions = new javax.swing.JPanel();
        buttonCenterBox = new javax.swing.JButton();
        checkShow = new javax.swing.JCheckBox();
        jScrollPane2 = new javax.swing.JScrollPane();
        tablePropTerrain = new javax.swing.JTable();
        panelDroitBas = new javax.swing.JPanel();
        labelElementChoice = new javax.swing.JLabel();
        choixIndiv = new javax.swing.JComboBox();
        elementPanel = new javax.swing.JPanel();
        iconIndiv = new javax.swing.JLabel();
        elementOptions = new javax.swing.JPanel();
        buttonCenter = new javax.swing.JButton();
        checkFollow = new javax.swing.JCheckBox();
        checkMarked = new javax.swing.JCheckBox();
        buttonKill = new javax.swing.JButton();
        buttonaddEl = new javax.swing.JButton();
        checkLock = new javax.swing.JCheckBox();
        labelPropIndiv = new javax.swing.JLabel();
        elPropPanel = new java.awt.Panel();
        jScrollPane3 = new javax.swing.JScrollPane();
        tablePropIndiv = new javax.swing.JTable();
        barreDoutil = new javax.swing.JPanel();
        barreDoutilEdition = new javax.swing.JPanel();
        buttonaddElbig = new javax.swing.JButton();
        buttonDuplicateEl = new javax.swing.JButton();
        buttonChangeBox = new javax.swing.JButton();
        buttonSave = new javax.swing.JButton();
        buttonRun = new javax.swing.JButton();
        barreDoutilSimulation = new javax.swing.JPanel();
        sliderTemporel = new javax.swing.JSlider();
        fieldFacteurTemporel = new JFormattedTextField(NumberFormat.getInstance());
        checkPause = new javax.swing.JCheckBox();
        checkBoost = new javax.swing.JCheckBox();
        fieldDate = new JFormattedTextField(NumberFormat.getInstance());
        fieldDelaiReel = new JFormattedTextField(NumberFormat.getInstance());
        buttonNext = new javax.swing.JButton();
        fieldPasNext = new JFormattedTextField(NumberFormat.getIntegerInstance());
        buttonDate = new javax.swing.JButton();
        labelAchievedTF = new javax.swing.JLabel();
        fieldDelaiVirtuel = new JFormattedTextField(NumberFormat.getInstance());
        checkActivateRDelay = new javax.swing.JCheckBox();
        checkActivateVDelay = new javax.swing.JCheckBox();
        menuBar = new javax.swing.JMenuBar();
        menuFile = new javax.swing.JMenu();
        menuNewFile = new javax.swing.JMenuItem();
        menuOpenFile = new javax.swing.JMenuItem();
        menuEditFile = new javax.swing.JMenuItem();
        menuResetFile = new javax.swing.JMenuItem();
        menuResetWithBF = new javax.swing.JMenuItem();
        menuHelp = new javax.swing.JMenu();
        menuItemHelp = new javax.swing.JMenuItem();
        menuAbout = new javax.swing.JMenuItem();

        simChooser.setDialogTitle("Choose Simulation");
        simChooser.setFileFilter(new FileExtFilter("sim","Simulation files"));

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("SEMA");
        setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        setName("frameMain");
        centerPanel.setDividerSize(3);
        centerPanel.setResizeWeight(0.9);
        panelG_Carte.setDividerSize(3);
        panelG_Carte.setResizeWeight(0.1);
        panelGauche.setLayout(new javax.swing.BoxLayout(panelGauche, javax.swing.BoxLayout.Y_AXIS));

        labelApercu.setText("Preview");
        labelApercu.setAlignmentX(0.5F);
        panelGauche.add(labelApercu);

        zGApercu.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
        zGApercu.setOpaque(true);
        zGApercu.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                zGApercuMouseDragged(evt);
            }
        });
        zGApercu.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                zGApercuMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                zGApercuMouseReleased(evt);
            }
        });

        panelGauche.add(zGApercu);

        sliderZoom.setMaximum(1000);
        sliderZoom.setValue(zoomToSlider(1));
        sliderZoom.setMaximumSize(new java.awt.Dimension(200, 24));
        sliderZoom.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderZoomStateChanged(evt);
            }
        });

        panelGauche.add(sliderZoom);

        zoomOptions.setMaximumSize(new java.awt.Dimension(32767, 43));
        fieldZoom.setBorder(new javax.swing.border.TitledBorder(null, "Zoom ( X )", javax.swing.border.TitledBorder.LEFT, javax.swing.border.TitledBorder.TOP));
        fieldZoom.setHorizontalAlignment(javax.swing.JTextField.CENTER);
        fieldZoom.setAlignmentX(1.0F);
        fieldZoom.setMaximumSize(new java.awt.Dimension(100, 43));
        fieldZoom.setMinimumSize(new java.awt.Dimension(100, 43));
        fieldZoom.setPreferredSize(new java.awt.Dimension(100, 43));
        fieldZoom.setValue(new Float(sliderToZoom(sliderZoom.getValue())));
        fieldZoom.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                fieldZoomPropertyChange(evt);
            }
        });

        zoomOptions.add(fieldZoom);

        buttonFit.setText("Fit");
        buttonFit.setMargin(new java.awt.Insets(2, 5, 2, 5));
        buttonFit.setMaximumSize(new java.awt.Dimension(35, 25));
        buttonFit.setMinimumSize(new java.awt.Dimension(35, 25));
        buttonFit.setPreferredSize(new java.awt.Dimension(35, 25));
        buttonFit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonFitActionPerformed(evt);
            }
        });

        zoomOptions.add(buttonFit);

        Default.setText("Default");
        Default.setMargin(new java.awt.Insets(2, 5, 2, 5));
        Default.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                DefaultActionPerformed(evt);
            }
        });

        zoomOptions.add(Default);

        panelGauche.add(zoomOptions);

        jSeparator1.setMaximumSize(new java.awt.Dimension(32767, 100));
        panelGauche.add(jSeparator1);

        labelPropMonde.setText("World's Properties");
        labelPropMonde.setAlignmentX(0.5F);
        panelGauche.add(labelPropMonde);

        panelpropWorld.setLayout(new java.awt.GridLayout(1, 0));

        jScrollPane1.setPreferredSize(new java.awt.Dimension(200, 419));
        tablePropMonde.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
        tablePropMonde.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null}
            },
            new String [] {
                "Properties", "Values"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, true
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        tablePropMonde.setCellSelectionEnabled(true);
        tablePropMonde.setModel(new javax.swing.table.DefaultTableModel(new Object [][] {{null, null}},	new String [] {"Properties", "Values"}));
        tablePropMonde.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                tablePropMondeFocusGained(evt);
            }
        });

        jScrollPane1.setViewportView(tablePropMonde);

        panelpropWorld.add(jScrollPane1);

        panelGauche.add(panelpropWorld);

        panelG_Carte.setLeftComponent(panelGauche);

        zGCarte.init(defaultWorld);
        zGCarte.setDoubleBuffered(true);
        zGCarte.setMinimumSize(new java.awt.Dimension(200, 200));
        zGCarte.setOpaque(true);
        zGCarte.setPreferredSize(new java.awt.Dimension(32767, 32767));
        zGCarte.addComponentListener(new java.awt.event.ComponentAdapter() {
            public void componentResized(java.awt.event.ComponentEvent evt) {
                zGCarteComponentResized(evt);
            }
        });
        zGCarte.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseDragged(java.awt.event.MouseEvent evt) {
                zGCarteMouseDragged(evt);
            }
        });
        zGCarte.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                zGCarteFocusGained(evt);
            }
        });
        zGCarte.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                zGCarteKeyPressed(evt);
            }
            public void keyTyped(java.awt.event.KeyEvent evt) {
                zGCarteKeyTyped(evt);
            }
        });
        zGCarte.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                zGCarteMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                zGCarteMouseReleased(evt);
            }
        });

        panelG_Carte.setRightComponent(zGCarte);

        centerPanel.setLeftComponent(panelG_Carte);

        PanelDroit.setDividerSize(3);
        PanelDroit.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
        PanelDroit.setResizeWeight(0.5);
        paneDroitHaut.setLayout(new javax.swing.BoxLayout(paneDroitHaut, javax.swing.BoxLayout.Y_AXIS));

        groundPanel.setLayout(new java.awt.GridBagLayout());

        iconTerrain.setIcon(new javax.swing.ImageIcon("C:\\Documents and Settings\\Moi\\Mes documents\\pititanglaise.png"));
        iconTerrain.setAlignmentX(0.5F);
        iconTerrain.setBorder(new javax.swing.border.TitledBorder("Ground"));
        iconTerrain.setDoubleBuffered(true);
        iconTerrain.setMaximumSize(new java.awt.Dimension(112, 127));
        iconTerrain.setMinimumSize(new java.awt.Dimension(112, 127));
        iconTerrain.setOpaque(true);
        iconTerrain.setPreferredSize(new java.awt.Dimension(112, 127));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.weightx = 0.5;
        groundPanel.add(iconTerrain, gridBagConstraints);

        GroundOptions.setLayout(new javax.swing.BoxLayout(GroundOptions, javax.swing.BoxLayout.Y_AXIS));

        buttonCenterBox.setText("Center");
        buttonCenterBox.setAlignmentX(0.5F);
        buttonCenterBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonCenterBoxActionPerformed(evt);
            }
        });

        GroundOptions.add(buttonCenterBox);

        checkShow.setText("Highlight");
        checkShow.setAlignmentX(0.5F);
        checkShow.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                checkShowItemStateChanged(evt);
            }
        });

        GroundOptions.add(checkShow);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.weightx = 0.5;
        groundPanel.add(GroundOptions, gridBagConstraints);

        paneDroitHaut.add(groundPanel);

        jScrollPane2.setPreferredSize(new java.awt.Dimension(100, 404));
        tablePropTerrain.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
        tablePropTerrain.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null}
            },
            new String [] {
                "Properties", "Values"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, true
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        tablePropTerrain.setCellSelectionEnabled(true);
        tablePropTerrain.setModel(new javax.swing.table.DefaultTableModel(new Object [][] {{null, null}},	new String [] {"Properties", "Values"}));
        tablePropTerrain.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                tablePropTerrainFocusGained(evt);
            }
        });

        jScrollPane2.setViewportView(tablePropTerrain);

        paneDroitHaut.add(jScrollPane2);

        PanelDroit.setTopComponent(paneDroitHaut);

        panelDroitBas.setLayout(new javax.swing.BoxLayout(panelDroitBas, javax.swing.BoxLayout.Y_AXIS));

        labelElementChoice.setText("Choose Element");
        labelElementChoice.setAlignmentX(0.5F);
        panelDroitBas.add(labelElementChoice);

        choixIndiv.setMaximumSize(new java.awt.Dimension(1000, 30));
        choixIndiv.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                choixIndivActionPerformed(evt);
            }
        });

        panelDroitBas.add(choixIndiv);

        elementPanel.setLayout(new java.awt.GridBagLayout());

        iconIndiv.setIcon(new javax.swing.ImageIcon("C:\\Documents and Settings\\Moi\\Mes documents\\pititanglaise.png"));
        iconIndiv.setAlignmentX(1.0F);
        iconIndiv.setBorder(new javax.swing.border.TitledBorder("Element's Icon"));
        iconIndiv.setDoubleBuffered(true);
        iconIndiv.setMaximumSize(new java.awt.Dimension(112, 127));
        iconIndiv.setMinimumSize(new java.awt.Dimension(112, 127));
        iconIndiv.setOpaque(true);
        iconIndiv.setPreferredSize(new java.awt.Dimension(112, 127));
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.weightx = 0.5;
        elementPanel.add(iconIndiv, gridBagConstraints);

        elementOptions.setLayout(new javax.swing.BoxLayout(elementOptions, javax.swing.BoxLayout.Y_AXIS));

        elementOptions.setMaximumSize(new java.awt.Dimension(112, 127));
        elementOptions.setPreferredSize(new java.awt.Dimension(73, 127));
        buttonCenter.setText("Center");
        buttonCenter.setAlignmentX(0.5F);
        buttonCenter.setMaximumSize(new java.awt.Dimension(100, 100));
        buttonCenter.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonCenterActionPerformed(evt);
            }
        });

        elementOptions.add(buttonCenter);

        checkFollow.setText("Follow");
        checkFollow.setAlignmentX(0.5F);
        checkFollow.setMaximumSize(new java.awt.Dimension(100, 100));
        checkFollow.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                checkFollowItemStateChanged(evt);
            }
        });

        elementOptions.add(checkFollow);

        checkMarked.setText("Marked");
        checkMarked.setAlignmentX(0.5F);
        checkMarked.setMaximumSize(new java.awt.Dimension(100, 100));
        checkMarked.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                checkMarkedItemStateChanged(evt);
            }
        });

        elementOptions.add(checkMarked);

        buttonKill.setText("Kill");
        buttonKill.setAlignmentX(0.5F);
        buttonKill.setMaximumSize(new java.awt.Dimension(100, 100));
        buttonKill.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonKillActionPerformed(evt);
            }
        });

        elementOptions.add(buttonKill);

        buttonaddEl.setText("New...");
        buttonaddEl.setActionCommand("New El");
        buttonaddEl.setAlignmentX(0.5F);
        buttonaddEl.setEnabled(false);
        buttonaddEl.setMargin(new java.awt.Insets(2, 8, 2, 8));
        buttonaddEl.setMaximumSize(new java.awt.Dimension(100, 100));
        buttonaddEl.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonaddElActionPerformed(evt);
            }
        });

        elementOptions.add(buttonaddEl);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.weightx = 0.5;
        elementPanel.add(elementOptions, gridBagConstraints);

        panelDroitBas.add(elementPanel);

        checkLock.setSelected(true);
        checkLock.setText("Locked for Mouse");
        checkLock.setActionCommand("Lock Element");
        panelDroitBas.add(checkLock);

        labelPropIndiv.setText("Element's Properties");
        labelPropIndiv.setAlignmentX(0.5F);
        labelPropIndiv.setPreferredSize(new java.awt.Dimension(97, 20));
        panelDroitBas.add(labelPropIndiv);
        labelPropIndiv.getAccessibleContext().setAccessibleName("Element Properties");

        elPropPanel.setLayout(new javax.swing.BoxLayout(elPropPanel, javax.swing.BoxLayout.Y_AXIS));

        jScrollPane3.setPreferredSize(new java.awt.Dimension(100, 404));
        tablePropIndiv.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true));
        tablePropIndiv.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null},
                {null, null}
            },
            new String [] {
                "Properties", "Values"
            }
        ) {
            Class[] types = new Class [] {
                java.lang.String.class, java.lang.String.class
            };
            boolean[] canEdit = new boolean [] {
                false, true
            };

            public Class getColumnClass(int columnIndex) {
                return types [columnIndex];
            }

            public boolean isCellEditable(int rowIndex, int columnIndex) {
                return canEdit [columnIndex];
            }
        });
        tablePropIndiv.setCellSelectionEnabled(true);
        tablePropIndiv.setModel(new javax.swing.table.DefaultTableModel(new Object [][] {{null, null}},	new String [] {"Properties", "Values"}));
        tablePropIndiv.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                tablePropIndivFocusGained(evt);
            }
        });

        jScrollPane3.setViewportView(tablePropIndiv);

        elPropPanel.add(jScrollPane3);

        panelDroitBas.add(elPropPanel);

        PanelDroit.setBottomComponent(panelDroitBas);

        centerPanel.setRightComponent(PanelDroit);

        getContentPane().add(centerPanel, java.awt.BorderLayout.CENTER);

        barreDoutil.setLayout(new java.awt.CardLayout());

        barreDoutilEdition.setLayout(new java.awt.GridLayout(1, 0));

        barreDoutilEdition.setBackground(new java.awt.Color(255, 255, 255));
        buttonaddElbig.setText("Add Element");
        buttonaddElbig.setAlignmentX(0.5F);
        buttonaddElbig.setMargin(new java.awt.Insets(2, 8, 2, 8));
        buttonaddElbig.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonaddElbigActionPerformed(evt);
            }
        });

        barreDoutilEdition.add(buttonaddElbig);

        buttonDuplicateEl.setText("Duplicate Selected Element");
        buttonDuplicateEl.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonDuplicateElActionPerformed(evt);
            }
        });

        barreDoutilEdition.add(buttonDuplicateEl);

        buttonChangeBox.setText("Modify Selected Box");
        buttonChangeBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonChangeBoxActionPerformed(evt);
            }
        });

        barreDoutilEdition.add(buttonChangeBox);

        buttonSave.setText("Save");
        buttonSave.setMargin(new java.awt.Insets(2, 8, 2, 8));
        buttonSave.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonSaveActionPerformed(evt);
            }
        });

        barreDoutilEdition.add(buttonSave);

        buttonRun.setText("Run");
        buttonRun.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonRunActionPerformed(evt);
            }
        });

        barreDoutilEdition.add(buttonRun);

        barreDoutil.add(barreDoutilEdition, "EditingCard");

        barreDoutilSimulation.setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());

        sliderTemporel.setMaximum(10000);
        sliderTemporel.setValue(1000);
        sliderTemporel.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                sliderTemporelStateChanged(evt);
            }
        });

        barreDoutilSimulation.add(sliderTemporel, new org.netbeans.lib.awtextra.AbsoluteConstraints(10, 60, -1, -1));

        fieldFacteurTemporel.setBorder(new javax.swing.border.TitledBorder("Time factor"));
        fieldFacteurTemporel.setValue(new Float(sliderToFacteur(sliderTemporel.getValue())));
        fieldFacteurTemporel.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                fieldFacteurTemporelPropertyChange(evt);
            }
        });

        barreDoutilSimulation.add(fieldFacteurTemporel, new org.netbeans.lib.awtextra.AbsoluteConstraints(10, 10, 84, -1));

        checkPause.setSelected(true);
        checkPause.setText("Pause");
        checkPause.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                checkPauseItemStateChanged(evt);
            }
        });

        barreDoutilSimulation.add(checkPause, new org.netbeans.lib.awtextra.AbsoluteConstraints(170, 10, -1, -1));

        checkBoost.setText("Boost");
        checkBoost.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                checkBoostItemStateChanged(evt);
            }
        });

        barreDoutilSimulation.add(checkBoost, new org.netbeans.lib.awtextra.AbsoluteConstraints(170, 30, -1, -1));

        fieldDate.setBorder(new javax.swing.border.TitledBorder("Date"));
        fieldDate.setValue(new Double(0f)/*TODO récupérer du moteur ce qu'il faut*/);
        fieldDate.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                fieldDateFocusGained(evt);
            }
        });

        barreDoutilSimulation.add(fieldDate, new org.netbeans.lib.awtextra.AbsoluteConstraints(240, 3, 120, -1));

        fieldDelaiReel.setBorder(new javax.swing.border.TitledBorder("Display real delay (ms)"));
        fieldDelaiReel.setValue(new Float(200));
        fieldDelaiReel.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                fieldDelaiReelPropertyChange(evt);
            }
        });

        barreDoutilSimulation.add(fieldDelaiReel, new org.netbeans.lib.awtextra.AbsoluteConstraints(470, 3, 150, -1));

        buttonNext.setText("Next date");
        buttonNext.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonNextActionPerformed(evt);
            }
        });

        barreDoutilSimulation.add(buttonNext, new org.netbeans.lib.awtextra.AbsoluteConstraints(370, 60, -1, -1));

        fieldPasNext.setBorder(new javax.swing.border.TitledBorder("Next's steps"));
        fieldPasNext.setValue(new Integer(1));
        barreDoutilSimulation.add(fieldPasNext, new org.netbeans.lib.awtextra.AbsoluteConstraints(250, 50, 100, 40));

        buttonDate.setText("Go to Date");
        buttonDate.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buttonDateActionPerformed(evt);
            }
        });

        barreDoutilSimulation.add(buttonDate, new org.netbeans.lib.awtextra.AbsoluteConstraints(370, 10, -1, -1));

        labelAchievedTF.setFont(new java.awt.Font("MS Sans Serif", 0, 10));
        labelAchievedTF.setBorder(new javax.swing.border.TitledBorder("Achieved"));
        labelAchievedTF.setPreferredSize(new java.awt.Dimension(12, 43));
        barreDoutilSimulation.add(labelAchievedTF, new org.netbeans.lib.awtextra.AbsoluteConstraints(94, 10, 76, -1));

        fieldDelaiVirtuel.setBorder(new javax.swing.border.TitledBorder("Display virtual delay (ms)"));
        fieldDelaiVirtuel.setEnabled(false);
        fieldDelaiVirtuel.setValue(new Float(5000));
        fieldDelaiVirtuel.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                fieldDelaiVirtuelPropertyChange(evt);
            }
        });

        barreDoutilSimulation.add(fieldDelaiVirtuel, new org.netbeans.lib.awtextra.AbsoluteConstraints(470, 50, 150, -1));

        checkActivateRDelay.setSelected(true);
        checkActivateRDelay.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                checkActivateRDelayItemStateChanged(evt);
            }
        });

        barreDoutilSimulation.add(checkActivateRDelay, new org.netbeans.lib.awtextra.AbsoluteConstraints(620, 10, -1, -1));

        checkActivateVDelay.setSelected(true);
        checkActivateVDelay.addItemListener(new java.awt.event.ItemListener() {
            public void itemStateChanged(java.awt.event.ItemEvent evt) {
                checkActivateVDelayItemStateChanged(evt);
            }
        });

        barreDoutilSimulation.add(checkActivateVDelay, new org.netbeans.lib.awtextra.AbsoluteConstraints(620, 60, -1, -1));

        barreDoutil.add(barreDoutilSimulation, "SimulatingCard");

        getContentPane().add(barreDoutil, java.awt.BorderLayout.SOUTH);

        menuFile.setText("File");
        menuNewFile.setText("New file...");
        menuNewFile.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuNewFileActionPerformed(evt);
            }
        });

        menuFile.add(menuNewFile);

        menuOpenFile.setText("Open file...");
        menuOpenFile.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuOpenFileActionPerformed(evt);
            }
        });

        menuFile.add(menuOpenFile);

        menuEditFile.setText("Edit file...");
        menuEditFile.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuEditFileActionPerformed(evt);
            }
        });

        menuFile.add(menuEditFile);

        menuResetFile.setText("Reset current file");
        menuResetFile.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuResetFileActionPerformed(evt);
            }
        });

        menuFile.add(menuResetFile);

        menuResetWithBF.setText("Reset with boxfactor");
        menuResetWithBF.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuResetWithBFActionPerformed(evt);
            }
        });

        menuFile.add(menuResetWithBF);

        menuBar.add(menuFile);

        menuHelp.setText("Help");
        menuItemHelp.setText("Help");
        menuItemHelp.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuItemHelpActionPerformed(evt);
            }
        });

        menuHelp.add(menuItemHelp);

        menuAbout.setText("About");
        menuAbout.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                menuAboutActionPerformed(evt);
            }
        });

        menuHelp.add(menuAbout);

        menuBar.add(menuHelp);

        setJMenuBar(menuBar);

        pack();
    }//GEN-END:initComponents
    
    private void checkShowItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkShowItemStateChanged
        if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) zGCarte.setHighlightSelectedBox(true);
        else zGCarte.setHighlightSelectedBox(false);
        repaint();
    }//GEN-LAST:event_checkShowItemStateChanged
    
    private int xMoveApercu = 0;
    private int yMoveApercu = 0;
    private boolean isPreviewMoving = false;
    private boolean isPreviewDragued = false;
    
    private void zGApercuMouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_zGApercuMouseDragged
        isPreviewDragued = true;
        if (isPreviewMoving) {
            setCenterPos((evt.getX()-xMoveApercu)/(float)zGApercu.width*world.map.xLength,
                    (evt.getY()-yMoveApercu)/(float)zGApercu.height*world.map.yLength);
            repaint();
        }
    }//GEN-LAST:event_zGApercuMouseDragged
    
    private void zGApercuMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_zGApercuMousePressed
        if (zGApercu.isInZone(evt.getX(),evt.getY())){
            xMoveApercu = evt.getX()-zGApercu.getCenterX();
            yMoveApercu = evt.getY()-zGApercu.getCenterY();
            isPreviewMoving = true;
        } else isPreviewMoving = false;
    }//GEN-LAST:event_zGApercuMousePressed
    
    private void checkMarkedItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkMarkedItemStateChanged
        if (selectedElement != null) {
            if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) selectedElement.setMarked(true);
            else selectedElement.setMarked(false);
            repaint();
        }
    }//GEN-LAST:event_checkMarkedItemStateChanged
    
    private void buttonRunActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRunActionPerformed
        if (world!=null)
            if (currentfile!=null)
                setTitle("SEMA - "+world.getName()+" ("+currentfile+")");
            else
                setTitle("SEMA - "+world.getName());
        run();
    }//GEN-LAST:event_buttonRunActionPerformed
    
    
    private void buttonaddElbigActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonaddElbigActionPerformed
        addEl();
    }//GEN-LAST:event_buttonaddElbigActionPerformed
    
    private void menuResetWithBFActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuResetWithBFActionPerformed
        reset(true);
    }//GEN-LAST:event_menuResetWithBFActionPerformed
    
    private void menuItemHelpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuItemHelpActionPerformed
        JOptionPane.showMessageDialog(null, "[GENERAL]\n---------\n Arrows or click on Preview to move the map\n SPACE to pause/resume the simulation\n + and - to zoom\n PgDwn and PgUp to change time factor\n Click on the map to select a box or an element\n\n[SELECTED ELEMENT]\n------------------\n L to lock/unlock\n F to follow,\n M to mark,\n DEL to kill,\n (and, when unlocked:)\n Left mouse drag on the map to move,\n Right mouse drag to rotate\n","Help on Sema",JOptionPane.INFORMATION_MESSAGE);
    }//GEN-LAST:event_menuItemHelpActionPerformed
    
    private void menuAboutActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuAboutActionPerformed
        JOptionPane.showMessageDialog(null, "SystèmeExtensibleMultiAgents v1.04, by POOGL","About SEMA",JOptionPane.INFORMATION_MESSAGE);
    }//GEN-LAST:event_menuAboutActionPerformed
    
    private void menuOpenFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuOpenFileActionPerformed
        open();
    }//GEN-LAST:event_menuOpenFileActionPerformed
    
    private void menuNewFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuNewFileActionPerformed
        newSim();
    }//GEN-LAST:event_menuNewFileActionPerformed
    
    private void menuEditFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuEditFileActionPerformed
        edit();
    }//GEN-LAST:event_menuEditFileActionPerformed
    
    private void menuResetFileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuResetFileActionPerformed
        reset(false);
    }//GEN-LAST:event_menuResetFileActionPerformed
    
    private void buttonChangeBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonChangeBoxActionPerformed
        if (selectedBox!=null) {
            int x = selectedBox.x;
            int y = selectedBox.y;
            Box b = world.map.boxes[x][y];
            try {
                String oldBoxCode = ioSIM.codeOf(b);
                String boxCode = JOptionPane.showInputDialog(null, "New box code: ", oldBoxCode );
                if (boxCode !=null)
                    if (!boxCode.equals("") && !boxCode.equals(oldBoxCode)) {
                    ioSIM.changeBox(world,x,y,boxCode);
                    repaint();
                    }
            } catch (Exception e) {
                JOptionPane.showMessageDialog(null,e.getMessage(), "Invalid box.", JOptionPane.WARNING_MESSAGE);
            }
        }
    }//GEN-LAST:event_buttonChangeBoxActionPerformed
    
    private void buttonDuplicateElActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDuplicateElActionPerformed
        if (selectedElement==null) return;
        lastCodeEntered = ioSIM.codeOf(selectedElement);
        addEl();
    }//GEN-LAST:event_buttonDuplicateElActionPerformed
    
    
    
    private void buttonaddElActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonaddElActionPerformed
        addEl();
    }//GEN-LAST:event_buttonaddElActionPerformed
    
    private void buttonSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSaveActionPerformed
        save();
    }//GEN-LAST:event_buttonSaveActionPerformed
    
    
    
    
    private void buttonKillActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonKillActionPerformed
        killSelected();
    }//GEN-LAST:event_buttonKillActionPerformed
    
    
    private float xMove = 0, yMove = 0;    //pour déplacer l'élément sélectionné avec la souris
    private boolean isRotatingElement = false;
    private float angleMove = 0;
    
    private void zGCarteMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_zGCarteMouseReleased
        if(isMouvingElement || isRotatingElement) {ioSIM.elementChanged(selectedElement);
        resume_temporaire(); isMouvingElement=false; isRotatingElement=false;}
    }//GEN-LAST:event_zGCarteMouseReleased
    
    private void zGCarteMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_zGCarteMousePressed
        if (!pause_temp || !wasRunning ) {
            float pbu = world.drawing.getPixelsByUnit();
            float xClick = (float)evt.getX()/pbu+zGCarte.getXu();
            float yClick = (float)evt.getY()/pbu+zGCarte.getYu();
            try {
                setSelection(xClick,yClick);
            } catch (ArrayIndexOutOfBoundsException e) { //on a pu cliquer sur une zone non recouverte par la carte
            }
            if (selectedElement!=null){
                xMove = xClick - selectedElement.getArea().getX();
                yMove = yClick - selectedElement.getArea().getY();
                angleMove = (float)Math.atan2(xMove,-yMove) - selectedElement.getArea().getAngle();
                if (!checkLock.isSelected() && selectedElement.getArea().isIn(xClick,yClick)) {
                    if (evt.getButton()==evt.BUTTON1)
                        isMouvingElement = true;
                    else isRotatingElement = true;
                    pause_temporaire();
                }
            }
        }
    }//GEN-LAST:event_zGCarteMousePressed
    
    private void zGCarteMouseDragged(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_zGCarteMouseDragged
        float pbu = world.drawing.getPixelsByUnit();
        if (isMouvingElement) {
            selectedElement.getArea().setX((float)evt.getX()/pbu+zGCarte.getXu()-xMove);
            selectedElement.getArea().setY((float)evt.getY()/pbu+zGCarte.getYu()-yMove);
            repaint();
        } else if (isRotatingElement) {
            float xClick = (float)evt.getX()/pbu+zGCarte.getXu();
            float yClick = (float)evt.getY()/pbu+zGCarte.getYu();
            xMove = xClick - selectedElement.getArea().getX();
            yMove = yClick - selectedElement.getArea().getY();
            selectedElement.getArea().setAngle((float)Math.atan2(xMove,-yMove)-angleMove);
            repaint();
        }
    }//GEN-LAST:event_zGCarteMouseDragged
    
    private void zGCarteKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_zGCarteKeyPressed
        
        switch (evt.getKeyCode()) {
            case java.awt.event.KeyEvent.VK_RIGHT :
                setCenterPos(getCenterX()+zGCarte.getWidthu()/25,getCenterY());
                repaint();
                break;
            case java.awt.event.KeyEvent.VK_LEFT :
                setCenterPos(getCenterX()-zGCarte.getWidthu()/25,getCenterY());
                repaint();
                break;
            case java.awt.event.KeyEvent.VK_UP :
                setCenterPos(getCenterX(),getCenterY()-zGCarte.getHeightu()/25);
                repaint();
                break;
            case java.awt.event.KeyEvent.VK_DOWN :
                setCenterPos(getCenterX(),getCenterY()+zGCarte.getHeightu()/25);
                repaint();
                break;
            case java.awt.event.KeyEvent.VK_SPACE :
                setPause(!checkPause.isSelected());
                break;
            case java.awt.event.KeyEvent.VK_PAGE_UP :
                setTimeFactor(getTimeFactor()*1.1f);
                break;
            case java.awt.event.KeyEvent.VK_PAGE_DOWN :
                setTimeFactor(getTimeFactor()/1.1f);
                break;
            case java.awt.event.KeyEvent.VK_DELETE:
                killSelected();
                break;
            case java.awt.event.KeyEvent.VK_F:
                checkFollow.setSelected(!checkFollow.isSelected());
                break;
            case java.awt.event.KeyEvent.VK_L:
                checkLock.setSelected(!checkLock.isSelected());
                break;
            case java.awt.event.KeyEvent.VK_M:
                checkMarked.setSelected(!checkMarked.isSelected());
                break;
        }
    }//GEN-LAST:event_zGCarteKeyPressed
    
    private void zGCarteKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_zGCarteKeyTyped
        switch	(evt.getKeyChar()) {
            case '+' :
                setZoom(getZoom()*1.1f);
                break;
                
            case '-' :
                setZoom(getZoom()/(1.1f));
                break;
        }
    }//GEN-LAST:event_zGCarteKeyTyped
    
    
    private void checkActivateVDelayItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkActivateVDelayItemStateChanged
        if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
            if(lastVDelay >-1) setVirtualDisplayDelay(lastVDelay);
            fieldDelaiVirtuel.setEnabled(true);
        } else {
            lastVDelay = getVirtualDisplayDelay();
            setVirtualDisplayDelay(Double.POSITIVE_INFINITY);
            fieldDelaiVirtuel.setValue(new Double(Double.POSITIVE_INFINITY));
            fieldDelaiVirtuel.setEnabled(false);
        }
    }//GEN-LAST:event_checkActivateVDelayItemStateChanged
    
    
    private void checkActivateRDelayItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkActivateRDelayItemStateChanged
        if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
            setRealDisplayDelay(lastRDelay);
            fieldDelaiReel.setEnabled(true);
        } else {
            lastRDelay = getRealDisplayDelay();
            setRealDisplayDelay(Long.MAX_VALUE);
            fieldDelaiReel.setValue(new Double(Double.POSITIVE_INFINITY));
            fieldDelaiReel.setEnabled(false);
        }
    }//GEN-LAST:event_checkActivateRDelayItemStateChanged
    
    private void buttonCenterBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCenterBoxActionPerformed
        centerSelectedBox();
    }//GEN-LAST:event_buttonCenterBoxActionPerformed
    
    private void checkFollowItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkFollowItemStateChanged
        if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) isFollowing = true;
        else isFollowing = false;
        repaint();
    }//GEN-LAST:event_checkFollowItemStateChanged
    
    private void buttonCenterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCenterActionPerformed
        centerSelectedElement();
    }//GEN-LAST:event_buttonCenterActionPerformed
    
    private void DefaultActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_DefaultActionPerformed
        setZoom(defaultZoom);
    }//GEN-LAST:event_DefaultActionPerformed
    
    private void checkBoostItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkBoostItemStateChanged
        if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
            timeFactorEnabled = false; fieldFacteurTemporel.setEnabled(false); sliderTemporel.setEnabled(false);
            delaiVirtuelAffSynchronized = VirtualDisplayDelay;
        } else {
            timeFactorEnabled = true; fieldFacteurTemporel.setEnabled(true); sliderTemporel.setEnabled(true);
            delaiVirtuelAffSynchronized = Math.min(VirtualDisplayDelay,RealDisplayDelay*timeFactor);
        }
        refreshDelaiVirtuelAffSynchronized();
    }//GEN-LAST:event_checkBoostItemStateChanged
    
    private void tablePropTerrainFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_tablePropTerrainFocusGained
        pause_temporaire();
    }//GEN-LAST:event_tablePropTerrainFocusGained
    
    private void zGCarteFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_zGCarteFocusGained
        resume_temporaire();
    }//GEN-LAST:event_zGCarteFocusGained
    
    private void buttonFitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonFitActionPerformed
        if (world!=null) {
            float pbu1x = world.drawing.pixelsByUnitZoom1x;
            setZoom(1f/Math.max(pbu1x*world.map.xLength/zGCarte.getWidth(),pbu1x*world.map.yLength/zGCarte.getHeight()));
            setCenterPos(world.map.xLength/2, world.map.yLength/2);
            repaint();
        }
    }//GEN-LAST:event_buttonFitActionPerformed
    
    private void zGCarteComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_zGCarteComponentResized
        resizeZonePreview(); //réactualise l'apercu
    }//GEN-LAST:event_zGCarteComponentResized
    
    
    private void buttonDateActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonDateActionPerformed
        goToDate(((Number) fieldDate.getValue()).doubleValue());
        repaint();
    }//GEN-LAST:event_buttonDateActionPerformed
    
    private void fieldDateFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_fieldDateFocusGained
        pause_temporaire();
    }//GEN-LAST:event_fieldDateFocusGained
    
    
    private void tablePropMondeFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_tablePropMondeFocusGained
        pause_temporaire();
    }//GEN-LAST:event_tablePropMondeFocusGained
    
    private void tablePropIndivFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_tablePropIndivFocusGained
        pause_temporaire();
    }//GEN-LAST:event_tablePropIndivFocusGained
    
    
    private void choixIndivActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_choixIndivActionPerformed
        if(choixIndiv.getSelectedItem() != null) {
            setSelectedElement(((ChoixObject)choixIndiv.getSelectedItem()).e);
            repaint();
        }
    }//GEN-LAST:event_choixIndivActionPerformed
    
    private void fieldDelaiVirtuelPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_fieldDelaiVirtuelPropertyChange
        changeVirtualDisplayDelay(((Number) fieldDelaiVirtuel.getValue()).doubleValue());
    }//GEN-LAST:event_fieldDelaiVirtuelPropertyChange
    
    private void fieldDelaiReelPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_fieldDelaiReelPropertyChange
        changeRealDisplayDelay(((Number) fieldDelaiReel.getValue()).longValue());
    }//GEN-LAST:event_fieldDelaiReelPropertyChange
    
    private void zGApercuMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_zGApercuMouseReleased
        if (!isPreviewDragued) {
            setCenterPos((evt.getX())/(float)zGApercu.width*world.map.xLength,
                    (evt.getY())/(float)zGApercu.height*world.map.yLength);
            repaint();
        }
        isPreviewDragued = false;
    }//GEN-LAST:event_zGApercuMouseReleased
    
    
    private void buttonNextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonNextActionPerformed
        if (world!=null)
            try {
                for(int i =0; i< ((Number) fieldPasNext.getValue()).intValue();i++) {
                    world.engine.next();
                }
            } catch (Engine.EndOfSimulation e) {
                setPause(true);
                hasEnded = true;
            } catch (Engine.SimulationError e) {
                setPause(true);
                JOptionPane.showMessageDialog(null,"An error occured while treating the current event.\nSimulation was paused, but you can resume it."+e.getMessage(), "Simulation error", JOptionPane.WARNING_MESSAGE);
            }
        this.repaint();
    }//GEN-LAST:event_buttonNextActionPerformed
    
    private void checkPauseItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_checkPauseItemStateChanged
        if (evt.getStateChange() == java.awt.event.ItemEvent.SELECTED) { setPause(true); } else {if (world!=null) setPause(false);}
    }//GEN-LAST:event_checkPauseItemStateChanged
    
    private int zoomToSlider(float f) {
        float ff = Math.min(zoomMax,Math.max(zoomMin,f));
        return Math.round((ff-zoomMin)/(zoomMax-zoomMin)*(sliderZoom.getMaximum()-sliderZoom.getMinimum())+sliderZoom.getMinimum());
    }
    private void fieldZoomPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_fieldZoomPropertyChange
        Number z = ((Number) fieldZoom.getValue());
        if(sliderZoom!=null && z!=null) {
            float fz = z.floatValue();
            if (fz > zoomMax) {fz = zoomMax;fieldZoom.setValue(new Float(fz));};
            if (fz < zoomMin) {fz = zoomMin;fieldZoom.setValue(new Float(fz));};
            sliderZoom.setValue(zoomToSlider(fz));
            setZoom(fz);
            repaint();
        }
    }//GEN-LAST:event_fieldZoomPropertyChange
    
    private float sliderToZoom(int i) {
        return (zoomMax-zoomMin)*(i-sliderZoom.getMinimum())/(sliderZoom.getMaximum()-sliderZoom.getMinimum())+zoomMin;
    }
    private void sliderZoomStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderZoomStateChanged
        float z = sliderToZoom(sliderZoom.getValue());
        if (!sliderZoom.getValueIsAdjusting()) { //done adjusting
            fieldZoom.setValue(new Float(z)); //update z value
        } else { //value is adjusting; just set the text
            fieldZoom.setText(String.valueOf(z));
        }
    }//GEN-LAST:event_sliderZoomStateChanged
    
    
    private int facteurToSlider(float f) {
        float ff = Math.min(facteurTemporelMax,Math.max(facteurTemporelMin,f));
        return Math.round((ff-facteurTemporelMin)/(facteurTemporelMax-facteurTemporelMin)*(sliderTemporel.getMaximum()-sliderTemporel.getMinimum())+sliderTemporel.getMinimum());
    }
    private void fieldFacteurTemporelPropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_fieldFacteurTemporelPropertyChange
        Number fxt = ((Number) fieldFacteurTemporel.getValue());
        if(sliderTemporel!=null && fxt!=null) {
            float ffxt = fxt.floatValue();
            if (ffxt > facteurTemporelMax) {ffxt = facteurTemporelMax;fieldZoom.setValue(new Float(ffxt));};
            if (ffxt < facteurTemporelMin) {ffxt = facteurTemporelMin;fieldZoom.setValue(new Float(ffxt));};
            sliderTemporel.setValue(facteurToSlider(ffxt));
            changeTimeFactor(ffxt);
            repaint();
        }
    }//GEN-LAST:event_fieldFacteurTemporelPropertyChange
    
    private float sliderToFacteur(int i){
        return (facteurTemporelMax-facteurTemporelMin)*(i-sliderTemporel.getMinimum())/(sliderTemporel.getMaximum()-sliderTemporel.getMinimum())+facteurTemporelMin;
    }
    private void sliderTemporelStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_sliderTemporelStateChanged
        float fxt = sliderToFacteur(sliderTemporel.getValue());
        if (!sliderTemporel.getValueIsAdjusting()) { //done adjusting
            fieldFacteurTemporel.setValue(new Float(fxt)); //update fxt value
        } else { //value is adjusting; just set the text
            fieldFacteurTemporel.setText(String.valueOf(fxt));
        }
    }//GEN-LAST:event_sliderTemporelStateChanged
    
    /**
     * Run SEMA.
     * @param args the command line arguments
     */
    
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                Sema f = new Sema();
                f.setExtendedState(f.MAXIMIZED_BOTH);
                f.pack();
                f.setVisible(true);
            }
        });
    }
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton Default;
    private javax.swing.JPanel GroundOptions;
    private javax.swing.JSplitPane PanelDroit;
    private javax.swing.JPanel barreDoutil;
    private javax.swing.JPanel barreDoutilEdition;
    private javax.swing.JPanel barreDoutilSimulation;
    private javax.swing.JButton buttonCenter;
    private javax.swing.JButton buttonCenterBox;
    private javax.swing.JButton buttonChangeBox;
    private javax.swing.JButton buttonDate;
    private javax.swing.JButton buttonDuplicateEl;
    private javax.swing.JButton buttonFit;
    private javax.swing.JButton buttonKill;
    private javax.swing.JButton buttonNext;
    private javax.swing.JButton buttonRun;
    private javax.swing.JButton buttonSave;
    private javax.swing.JButton buttonaddEl;
    private javax.swing.JButton buttonaddElbig;
    private javax.swing.JSplitPane centerPanel;
    private javax.swing.JCheckBox checkActivateRDelay;
    private javax.swing.JCheckBox checkActivateVDelay;
    private javax.swing.JCheckBox checkBoost;
    private javax.swing.JCheckBox checkFollow;
    private javax.swing.JCheckBox checkLock;
    private javax.swing.JCheckBox checkMarked;
    private javax.swing.JCheckBox checkPause;
    private javax.swing.JCheckBox checkShow;
    private javax.swing.JComboBox choixIndiv;
    private java.awt.Panel elPropPanel;
    private javax.swing.JPanel elementOptions;
    private javax.swing.JPanel elementPanel;
    private javax.swing.JFormattedTextField fieldDate;
    private javax.swing.JFormattedTextField fieldDelaiReel;
    private javax.swing.JFormattedTextField fieldDelaiVirtuel;
    private javax.swing.JFormattedTextField fieldFacteurTemporel;
    private javax.swing.JFormattedTextField fieldPasNext;
    private javax.swing.JFormattedTextField fieldZoom;
    private javax.swing.JPanel groundPanel;
    private javax.swing.JLabel iconIndiv;
    private javax.swing.JLabel iconTerrain;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JLabel labelAchievedTF;
    private javax.swing.JLabel labelApercu;
    private javax.swing.JLabel labelElementChoice;
    private javax.swing.JLabel labelPropIndiv;
    private javax.swing.JLabel labelPropMonde;
    private javax.swing.JMenuItem menuAbout;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JMenuItem menuEditFile;
    private javax.swing.JMenu menuFile;
    private javax.swing.JMenu menuHelp;
    private javax.swing.JMenuItem menuItemHelp;
    private javax.swing.JMenuItem menuNewFile;
    private javax.swing.JMenuItem menuOpenFile;
    private javax.swing.JMenuItem menuResetFile;
    private javax.swing.JMenuItem menuResetWithBF;
    private java.awt.Panel paneDroitHaut;
    private javax.swing.JPanel panelDroitBas;
    private javax.swing.JSplitPane panelG_Carte;
    private javax.swing.JPanel panelGauche;
    private java.awt.Panel panelpropWorld;
    private javax.swing.JFileChooser simChooser;
    private javax.swing.JSlider sliderTemporel;
    private javax.swing.JSlider sliderZoom;
    private javax.swing.JTable tablePropIndiv;
    private javax.swing.JTable tablePropMonde;
    private javax.swing.JTable tablePropTerrain;
    private SEMAbeans.ZGPreviewSEMA zGApercu;
    private SEMAbeans.ZGCarteSEMA zGCarte;
    private javax.swing.JPanel zoomOptions;
    // End of variables declaration//GEN-END:variables
}