/*
 * SimManager.java
 *
 * Created on June 3, 2007, 11:09 AM
 */

package sidnet.core.simcontrol;

import sidnet.core.interfaces.SIDnetTimeDependable;
import sidnet.core.interfaces.SimulationTimeRunnable;
import sidnet.core.interfaces.SIDnetDrawableInterface;
import sidnet.core.interfaces.SIDnetMenuInterface;
import sidnet.core.interfaces.SIDnetRegistrable;
import sidnet.core.interfaces.SimControl;
import java.util.Hashtable;
import javax.swing.JLabel;
import javax.swing.JPanel;
import jist.runtime.JistAPI;
import jist.swans.Constants;
import sidnet.core.gui.PanelContext;
import sidnet.core.gui.SIDnetProgressBar;
import sidnet.core.misc.Sleeper;
import java.util.LinkedList;
import javax.swing.JPopupMenu;
import sidnet.core.interfaces.*;
import java.awt.Graphics;
import sidnet.core.misc.Node;
import sidnet.utilityviews.statscollector.StatsCollector;

/**
 *
 * @author  Oliver
 */
public class SimManager extends javax.swing.JPanel implements SimulationTimeRunnable, SimControl{
    public static byte DEMO = 0;
    public static byte EXPERIMENT = 1;
    
    /** self-referencing proxy entity. */
    public static final long serialVersionUID = 24362462L;
    
    private static byte runMode = 0;
    
    private SimulationTimeRunnable self;
    
    public static byte PAUSED   = 0;
    public static byte X1       = 1;        //REAL TIME
    public static byte X10      = 2;
    public static byte X100     = 3;
    public static byte X1000    = 4;
    public static byte ACCEL    = 5;
    public static byte MAX      = 6;
    
    private LinkedList<SIDnetRegistrable> registeredLayers;
    private Node[] nodesList = null;
    private LinkedList<PanelContext> panelContextSet;
    
    SIDnetProgressBar progressBar = null;
    
    JPanel fieldPanel = null;
    JPopupMenu fieldPopupMenu = null;
    
    public long runnerCount = 0;
    
    private static StatsCollector statistics = null;
    
    public void register(Node[] nList)
    {
        this.nodesList = nList;
    }
    
    public void register(SIDnetRegistrable registrableLayer, PanelContext panelContext)
    {
        registeredLayers.add(registrableLayer);
        
        if (registrableLayer instanceof StatsCollector)
            this.statistics = (StatsCollector)registrableLayer;
        
        if (registrableLayer instanceof SIDnetDrawableInterface)
        {
            if (panelContext != null)
                ((SIDnetDrawableInterface)registrableLayer).configureGUI(panelContext.getPanelGUI());
            else
                ((SIDnetDrawableInterface)registrableLayer).configureGUI(null);
        }
        
        if (registrableLayer instanceof SIDnetMenuInterface)
        {
            ((SIDnetMenuInterface)registrableLayer).configureMenu(panelContext.getMenu());
        }
    }
    
    /**
     * Creates new form SimManager
     */
    public SimManager(JPanel mainHostFramePanel, SIDnetProgressBar progressBar, byte runMode) {
        initComponents();
        
        this.runMode = runMode;
        
        registeredLayers = new LinkedList<SIDnetRegistrable>();
        panelContextSet = new LinkedList<PanelContext>();
        
        this.setSize(mainHostFramePanel.getSize());
        
        mainHostFramePanel.add(this);
        Hashtable labelTable = new Hashtable();
        labelTable.put(new Integer(PAUSED), new JLabel("PAUSED"));
        labelTable.put(new Integer(X1), new JLabel("1X"));
        labelTable.put(new Integer(X10), new JLabel("10X"));
        labelTable.put(new Integer(X100), new JLabel("100X"));
        labelTable.put(new Integer(X1000), new JLabel("1000X"));
        labelTable.put(new Integer(ACCEL), new JLabel("Accel"));
        labelTable.put(new Integer(MAX), new JLabel("MAX"));  // user should cut out graphics. This is for very high speed simulations
        jSlider1.setLabelTable(labelTable);
        jSlider1.setPaintLabels(true);
        this.setBounds(10,7, 300, 100);
        this.setVisible(true);  
        this.setOpaque(false);
        
        this.progressBar = progressBar;
        this.register(progressBar, null);
        
        this.self = (SimulationTimeRunnable)JistAPI.proxy(this, SimulationTimeRunnable.class );
    }
    
    public void managePanelContext(PanelContext panelContext)
    {
        panelContextSet.add(panelContext); 
    }
    
    public SIDnetProgressBar getSIDnetProgressBar()
    {
        return progressBar;
    }
    
    public int getSpeed()
    {
        return jSlider1.getValue();
    }
    
    public void setSpeed(int val)
    {
        jSlider1.setValue(val);
    }
    
    public long getSpeedUp()
    {
        if (jSlider1.getValue() == X10)
            return 10;
        if (jSlider1.getValue() == X100)
            return 100;
        if (jSlider1.getValue() == X1000)
            return 1000;
        if (jSlider1.getValue() == ACCEL)
            return 1800000;     // every 30 minutes
        if (jSlider1.getValue() == MAX)
            return 14400000;    // every 4 hours
        return 1;
    }
    
    public long getBaseTime()
    {
        if (jSlider1.getValue() == X10)
            return 2000;
        if (jSlider1.getValue() == X100)
            return 4000;
        if (jSlider1.getValue() == X1000)
            return 8000;
        if (jSlider1.getValue() == ACCEL)
            return 8000;     // every 30 minutes
        if (jSlider1.getValue() == MAX)
            return 16000;    // every 4 hours
        return 1000;
    }
    /** 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.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {
        jSlider1 = new javax.swing.JSlider();

        jSlider1.setMajorTickSpacing(1);
        jSlider1.setMaximum(6);
        jSlider1.setMinorTickSpacing(1);
        jSlider1.setPaintTicks(true);
        jSlider1.setSnapToTicks(true);
        jSlider1.setValue(0);
        jSlider1.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                jSlider1StateChanged(evt);
            }
        });

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(jSlider1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 279, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(jSlider1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void jSlider1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jSlider1StateChanged
        // TODO add your handling code here:
        for (SIDnetRegistrable layer: registeredLayers)
        {
            if (layer instanceof SIDnetTimeDependable)
                ((SIDnetTimeDependable)layer).updateSimulationTimeToCurrent();
            
              if (layer instanceof SIDnetDrawableInterface)
                  if(getSpeed() == MAX)
                      ((SIDnetDrawableInterface)layer).setVisibleGUI(false);
                  else
                  {
                      ((SIDnetDrawableInterface)layer).setVisibleGUI(true);           
                      //((SIDnetDrawableInterface)layer).repaintGUI();
                  }
        }
        
        if (nodesList != null)
            for (int i = 0; i < nodesList.length; i++)
            {
                if ( getSpeed() == MAX )
                {
                    if( nodesList[i].getNodeGUI().isVisible())
                        nodesList[i].getNodeGUI().setVisible(false);
                }
                else
                    if( !nodesList[i].getNodeGUI().isVisible())
                        nodesList[i].getNodeGUI().setVisible(true);        
            }
    }//GEN-LAST:event_jSlider1StateChanged
    
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JSlider jSlider1;
    // End of variables declaration//GEN-END:variables
 
    public void scheduleNextRun() throws JistAPI.Continuation
    {
        long time = System.currentTimeMillis();
        if (getSpeed() == SimManager.MAX)
            JistAPI.sleepBlock(getBaseTime() * Constants.MILLI_SECOND);
        else
            if (getSpeed() == SimManager.ACCEL)
                JistAPI.sleepBlock(getBaseTime() * Constants.MILLI_SECOND);
            else 
                if (getSpeed() == SimManager.X1 || 
                    getSpeed() == SimManager.X10 ||
                    getSpeed() == SimManager.X100 ||
                    getSpeed() == SimManager.X1000) 
                {
                        //long time = System.currentTimeMillis();
                        Sleeper.Sleep(getBaseTime() / getSpeedUp() );
                        JistAPI.sleepBlock(getBaseTime()* Constants.MILLI_SECOND);
                }
                else
                    if (getSpeed() == SimManager.PAUSED)
                        Sleeper.Sleep(1000);
                
    }
    
  public long getSleepPeriod()
  {
      if (getSpeed() == MAX)
          return 1000;
      if (getSpeed() == ACCEL)
          return 1000;
      if (getSpeed() == PAUSED)
          return 1000;
      return 1000;
  }
    
    public void run(String[] args)
    { 
        for (SIDnetRegistrable layer: registeredLayers)
        {       
            if (layer instanceof SIDnetTimeDependable)
                ((SIDnetTimeDependable)layer).updateSimulationTimeToCurrent(); // this refreshes the phenomena layer
            
              if (layer instanceof SIDnetDrawableInterface)
                  if(getSpeed() != SimManager.MAX)
                    ((SIDnetDrawableInterface)layer).repaintGUI(); 
        }
                
       scheduleNextRun();
    
       self.run();
    }
    
    public void run()
    {
        //runnerCount++;
        run(null);
    }
    
     protected void clear(Graphics g) {
       // super.paintComponent(g);
    }  
     
     
    public boolean isExperimentMode()
    {
        return runMode == EXPERIMENT;
    }
     
    
}
