package org.lucci.madhoc.gui;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

import org.lucci.gui.ScreenshotableJFrame;
import org.lucci.madhoc.network.Connection;
import org.lucci.madhoc.simulation.MadhocSimulation;
import org.lucci.madhoc.simulation.Simulation;
import org.lucci.madhoc.simulation.SimulationListener;

/*
 * Created on Jul 3, 2004
 */

/**
 * @author luc.hogie
 */
public class SimulationRuntime implements Runnable
{
    private MadhocSimulation simulation;
    
    // the thread in which the stations will be asked to act
    private Thread thread;

    // the user may want to run a limited number of iteration
    // it can then define an iteration step
    private int step = 1;

    public static final int STATE_SLEEPING = 1;
    public static final int STATE_RUNNING = 2;
    public static final int STATE_COMPLETED = 3;

    // the current station of the simulation
    private int state = -1;

    // the state asked by the user
    private int requiredState = STATE_SLEEPING;

    private Collection<SimulationRuntimeListener> listeners = new HashSet<SimulationRuntimeListener>();

    private ScreenshotableJFrame frame;

    public SimulationRuntime(MadhocSimulation s)
    {
        this.simulation = s;
        thread = new Thread(this);
        
        SimulationListener simulationListener = new SimulationListener()
        {
            public void iterationHasCompleted(Simulation simulation)
            {
                for (SimulationRuntimeListener listener : listeners) listener.iterationPerformed();
            }

            public void iterationStarting(Simulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void beforeTheStationsMove(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void afterTheStationsMove(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void beforeStationsDo(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void afterStationsDo(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void beforeDataTransfer(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void afterDataTransfer(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void beforeSensing(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void afterSensing(MadhocSimulation simulation)
            {
                // TODO Auto-generated method stub
                
            }

            public void connectionsHaveVanished(MadhocSimulation simulation, Collection<Connection> removedConnections)
            {
                // TODO Auto-generated method stub
                
            }

            public void connectionsHaveAppeared(MadhocSimulation simulation, Collection<Connection> addedConnections)
            {
                // TODO Auto-generated method stub
                
            }
            
        };
        
        this.simulation.getSimulationListeners().add(simulationListener);
    }
    
    public void start()
    {
        thread.start();
    }

    public int getState()
    {
        return state;
    }

    public void setRequiredState(int requiredState)
    {
        if (requiredState != state)
        {
            if (requiredState == STATE_RUNNING && state == STATE_SLEEPING)
            {
                thread.resume();
            }

            this.requiredState = requiredState;
        }
    }

    public void run()
    {
        state = STATE_RUNNING;
        fireStateChanged();

        // decreases until 0, which means that the number of steps to execute
        // has expired
        // the simulation should then be paused
        int stepper = getNumberOfStepsToExecute();

        while (requiredState != STATE_COMPLETED)
        {
            if (requiredState == STATE_SLEEPING || stepper == 0)
            {
                state = STATE_SLEEPING;
                fireStateChanged();
                thread.suspend();
                state = STATE_RUNNING;
                fireStateChanged();
                stepper = getNumberOfStepsToExecute();
            }

            simulation.resetIterationScopedValues();
            simulation.iterate(false);
            
            if (frame != null)
            {
                frame.shootTheFrame();
            }

            --stepper;
        }

        state = STATE_COMPLETED;
        fireStateChanged();
    }

    public int getNumberOfStepsToExecute()
    {
        return step;
    }

    public void setNumberOfStepToExecute(int i)
    {
        step = i;
    }

    public void addSimulationRuntimeListener(SimulationRuntimeListener l)
    {
        listeners.add(l);
    }
    
    private void fireStateChanged()
    {
        for (SimulationRuntimeListener listener : listeners)
        {
            listener.stateChanged();
        }
    }

    /**
     * @return Returns the simulation.
     */
    public MadhocSimulation getSimulation()
    {
        return simulation;
    }

    /**
     * @param frame
     */
    public void setScreenshotableFrame(ScreenshotableJFrame frame)
    {
        this.frame = frame;
    }
}