/*
 * MovingObjectsField.java
 *
 * Created on November 7, 2007, 1:22 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package sidnet.models.senseable.mob;

import sidnet.core.interfaces.XMLLoader;
import sidnet.core.gui.XMLLoaderGUI;
import sidnet.core.interfaces.XMLLoaderListener;
import java.awt.event.ActionEvent;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import jist.runtime.JistAPI;
import jist.swans.Constants;
import sidnet.core.misc.Location2D;
import sidnet.core.misc.LocationContext;
import sidnet.core.misc.NCS_Location2D;
import sidnet.models.senseable.phenomena.PhenomenaLayerInterface;
import sidnet.models.senseable.mob.Mob.LocationInTime;

/**
 *
 * @author Oliver
 */
public class MovingObjectsField extends PhenomenaLayerInterface implements XMLLoaderListener{
    
    /** Creates a new instance of MovingObjectsField */
    private LinkedList<Mob> mobList;

    private List<NCS_Location2D> mobs = new LinkedList<NCS_Location2D>();
    
    
    // Configuration
    private XMLLoader profileLoader;
    private String xmlDirectory = "src/Imported Packages/NWUextension/phenomena/mob/";
    private String xsdSchemaFilename = "MobSchema.xsd";
    private String frameTitle = "Loader for Moving Objects Profiles";
    
    // GUI
    private boolean show = false;
    private MovingObjectsPanel mobPanel;
    
    // Menu
    private JPopupMenu hostPopupMenu;
    private JMenuItem menuItemShowMob, xmlLoaderMenuItem;
    
    public MovingObjectsField() {
        profileLoader = new XMLLoaderGUI();
        mobList = null;
        mobPanel = new MovingObjectsPanel();
    }
    
    public void init()
    {
        // TODO
    }
    
    public void terminate()
    {
        // TODO
    }
    
    public void updateSimulationTimeToCurrent()
    {
        // TODO
    }
    
    public double readDataAt(Location2D location, LocationContext locationContext)
    {
        // TODO
        NCS_Location2D locationNCS = location.toNCS(locationContext);
        
         this.updateMobs();
         for (NCS_Location2D mob:mobs)
         {
             if ( mob.distanceTo(locationNCS) < 0.05)
                 return 100;
         }
         
         return 0;
    }
    
    public void configureGUI(JPanel hostPanel)
    {
        // TODO
        mobPanel.configureGUI(hostPanel);
    }
    
    public void repaintGUI()
    {
        // TODO
        this.updateMobs(); 
        mobPanel.updateMobs(mobs);
        mobPanel.repaintGUI();
    }

    
    public void setVisibleGUI(boolean visible)
    {
        mobPanel.setVisibleGUI(visible);
    }
    
     public void configureMenu(JPopupMenu hostPopupMenu)
    {
        this.hostPopupMenu = hostPopupMenu;
        menuItemShowMob = new JMenuItem("Show/Hide Moving Object Field");
        xmlLoaderMenuItem = new JMenuItem("Load Moving Object Profiles");
        xmlLoaderMenuItem.setVisible(false);
        menuItemShowMob.addActionListener(this);
        xmlLoaderMenuItem.addActionListener(this);
        hostPopupMenu.add(menuItemShowMob);
        hostPopupMenu.add(xmlLoaderMenuItem);
    }
     
     public void enableUI()
    {
        // nothing
    }
    
    public void disableUI()
    {
        // nothing
    }
    
     public void passMenuActionEvent(ActionEvent menuEvent)
    {
        // TODO
    }
     
     public void actionPerformed(ActionEvent e) {
        
        if (e.getActionCommand() == "Show/Hide Moving Object Field")
        {
            show = !show;
            xmlLoaderMenuItem.setVisible(show);
        }   
        if (e.getActionCommand() == "Load Moving Object Profiles")
        {
            System.out.println("Enable XML Loader");
            profileLoader.enableLoaderFromXML(xmlDirectory, xsdSchemaFilename, frameTitle, new Mob().getClass(), this);
        }   
     }
     
     public void handleParsedObjects(List<Object> parsedPojoList)
     {
         if (parsedPojoList == null)
         {
             mobList = null;
             return;
         }
         
         mobList = new LinkedList<Mob>();
         for (Object pojo: parsedPojoList)
         {
             mobList.add((Mob)pojo);
             ((Mob)pojo).printComponents();
         }
     }
     
     public void updateMobs()
     {
        
         /* get object periodicity */
         if (mobList == null)
             return;
         
         mobs.clear();
         for (Mob mob:mobList)
         {
                long currentTime = JistAPI.getTime()/getJistTimeConstant(mob.timeUnit);
                long periodicity = mob.path.locationInTime.getLast().timeStamp;
                
                long numberOfLoops = currentTime/periodicity;
                long residualTime = currentTime - numberOfLoops * periodicity;
                
                LocationInTime lastLocationInTime = null;
                LocationInTime nextLocationInTime = null;
                for (LocationInTime lit:mob.path.locationInTime)
                {
                    if (lastLocationInTime == null)
                        lastLocationInTime = lit;
                    else
                    {
                        if (lastLocationInTime.timeStamp  <= residualTime && residualTime < lit.timeStamp)
                        {
                            nextLocationInTime = lit;
                            break;
                        }
                        else
                            lastLocationInTime = lit;
                    }
                }
              
                
                int x, y;
                double timeFraction = ((double)(residualTime - lastLocationInTime.timeStamp))/(nextLocationInTime.timeStamp - lastLocationInTime.timeStamp);
                
                if (timeFraction < 0)
                    timeFraction = 0;
                if (timeFraction > 1)
                    timeFraction = 1;
                
                if (lastLocationInTime.xCoord > nextLocationInTime.xCoord)
                    x = (int)(nextLocationInTime.xCoord + (lastLocationInTime.xCoord - nextLocationInTime.xCoord) * (1-timeFraction));
                else
                    x = (int)(lastLocationInTime.xCoord + (- lastLocationInTime.xCoord + nextLocationInTime.xCoord) * timeFraction);
                
               if (lastLocationInTime.yCoord > nextLocationInTime.yCoord)
                    y = (int)(nextLocationInTime.yCoord + (lastLocationInTime.yCoord - nextLocationInTime.yCoord) * (1-timeFraction));
                else
                    y = (int)(lastLocationInTime.yCoord + (- lastLocationInTime.yCoord + nextLocationInTime.yCoord) * timeFraction);
                
                
              
                
                if (x >= 0 && x <= mob.fieldDimensions.length && 
                    y >= 0 && y <= mob.fieldDimensions.width )
                    /* get the segment (locationInTime) where the object is at current time */
                    mobs.add(new Location2D(x, y).toNCS(new LocationContext(mob.fieldDimensions.length, mob.fieldDimensions.width)));
                    
         }
     }
 
     public long getJistTimeConstant(String timeUnit)
     {
        if (timeUnit.equals("milisecond"))
             return Constants.MILLI_SECOND;
        if (timeUnit.equals("second"))
             return Constants.SECOND;
        if (timeUnit.equals("minute"))
             return Constants.MINUTE;
        if (timeUnit.equals("hour"))
             return Constants.HOUR;

        return -1;
     }
}
