/*
 * NodeGUIimpl.java
 *
 * Created on April 27, 2007, 12:34 PM
 */

package sidnet.core.gui;

import sidnet.core.gui.*;
import sidnet.core.gui.GroupSelectionTool;
import sidnet.colorprofiles.ColorPair;
import sidnet.models.energy.batteries.BatteryControl;
import sidnet.core.interfaces.ColorProfile;
import sidnet.core.interfaces.NodeGUI;
import sidnet.core.interfaces.TerminalCallbackInterface;
import sidnet.core.terminal.Terminal;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import sidnet.core.misc.Location2D;
import sidnet.core.misc.LocationContext;
import sidnet.core.misc.Node;
import sidnet.core.terminal.TerminalDataSet;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import sidnet.colorprofiles.ColorProfileGeneric;
import sidnet.core.misc.NodeEntry;
import sidnet.core.simcontrol.SimManager;


/**
 *
 * @author  Oliver
 */
public class NodeGUIimpl extends JPanel implements ActionListener, MouseListener, TerminalCallbackInterface, NodeGUI{
    private static final Ellipse2D.Double MarkSendSymbol = new Ellipse2D.Double(2, 2, 6, 6);
    private static final Ellipse2D.Double innerCircle = new Ellipse2D.Double(0, 0, 10, 10);      // Create a visual symbol for a sensor node
    private static final Ellipse2D.Double outerCircle = new Ellipse2D.Double(0, 0, 11, 11);      // Create a visual symbol for a sensor node
    private static final Ellipse2D.Double symbol2D3rd = new Ellipse2D.Double(2, 2, 6, 6);        // Small circle

    public ColorProfile colorCode = null;
    private boolean selectionMarked = false;
    
    public Location2D panelLocation;
    
    private static JProgressBar progressBar;
  
    public Node node;
    
    private static PanelContext hostPanelContext;
    private static Graphics2D hostG2D;
    
    public TerminalDataSet localTerminalDataSet;
    
    // Built-in menus
    private JPopupMenu nodePopupMenu;
    
    private JMenuItem menuItemTerminal;
    private  JMenuItem menuItemIP;
    private  JMenuItem menuItemLocation;
    private  JMenuItem menuItemEnergy;
    private  JMenuItem menuItemKill;
    private JMenuItem menuItemNeighbors;
    private JMenuItem menuItemUdefData1;
    private JMenuItem menuItemUdefData2;
    private JMenuItem menuItemUdefData3;
    
    private int userDefinedData1 = 0;
    private int userDefinedData2 = 0;
    private int userDefinedData3 = 0;
    
    private boolean displayIP             = false;
    private boolean displayLocation       = false;
    private boolean displayEnergy         = false;
    private boolean displayNeighbors      = false;
    private boolean displayUdefData1      = false;
    private boolean displayUdefData2      = false;
    private boolean displayUdefData3      = false;
    
    private int displayItemCount = 0;
    
    // Terminal 
    private static Terminal terminal;
    
    private static LocationContext locationContext;
    
    // Group Interaction
    private static GroupSelectionTool groupSelectionTool = null;
    
    /**
     * Creates new form NodeGUIimpl
     */
    public Graphics2D getHostGUIPanel()
    {
        return hostG2D;
    }
    
    public NodeGUIimpl(PanelContext hostPanelContext, ColorProfile colorCode, Node node) {
        initComponents();
        
        this.hostPanelContext = hostPanelContext;
        
        hostPanelContext.getPanelGUI().add(this);
        this.colorCode = colorCode;
        //this.setVisible(true);
        
        
        this.setBackground(Color.gray);
        this.setOpaque(false);
        
        this.node = node;
        
        locationContext = new LocationContext(hostPanelContext.getPanelGUI().getWidth(), hostPanelContext.getPanelGUI().getHeight());
        
        
        
        hostG2D = (Graphics2D)hostPanelContext.getPanelGUI().getGraphics();
        hostG2D.setBackground(Color.GRAY);
        
        if (terminal == null)
            terminal = new Terminal();
        
        // Create the default pop-up menus (to view its energy, location)
        menuItemTerminal = new JMenuItem("Connect Terminal to ...");
        menuItemIP       = new JMenuItem("Show/Hide Node ID");
        menuItemLocation = new JMenuItem("Show/Hide Location Coordinates");
        menuItemEnergy   = new JMenuItem("Show/Hide Energy Levels");
        menuItemNeighbors = new JMenuItem("Show/Hide Discovered Neighbors");
        menuItemUdefData1= new JMenuItem("Show/Hide User Defined Data 1");
        menuItemUdefData2= new JMenuItem("Show/Hide User Defined Data 2");
        menuItemUdefData3= new JMenuItem("Show/Hide User Defined Data 3");
        menuItemKill     = new JMenuItem("Kill Node");
        
        nodePopupMenu = new JPopupMenu();
        
        menuItemTerminal.addActionListener( this );
        menuItemIP.addActionListener(this);
        menuItemLocation.addActionListener( this );
        menuItemEnergy.addActionListener( this );
        menuItemNeighbors.addActionListener( this );
        menuItemUdefData1.addActionListener( this );
        menuItemUdefData2.addActionListener( this );
        menuItemUdefData3.addActionListener( this );
        menuItemKill.addActionListener( this );
        
        
        nodePopupMenu.add(menuItemTerminal);
        nodePopupMenu.addSeparator();
        nodePopupMenu.add(menuItemIP);
        nodePopupMenu.add(menuItemLocation);
        nodePopupMenu.add(menuItemEnergy);
        nodePopupMenu.add(menuItemNeighbors);
        nodePopupMenu.add(menuItemUdefData1);
        nodePopupMenu.add(menuItemUdefData2);
        nodePopupMenu.add(menuItemUdefData3);
        nodePopupMenu.add(menuItemKill);
        
        
        addMouseListener( this );
    }
    
   
    
    public PanelContext getPanelContext()
    {
        return hostPanelContext;
    }
   
    public void setPanelLocation2D(Location2D panelLocation)
    {
        // Expects a location expressed in screen coordinates (pixels)
        
        ((JPanel)this).setBounds(panelLocation.getX(),panelLocation.getY(), 13, 13);
        if (panelLocation == null)
        {
            System.out.println("Null panel location reported at node ID: "+ node.getID());
            System.exit(1);
        }
        this.panelLocation = panelLocation;
        this.setVisible(true); 
    }

    
     /* **************** *
     * NodeGUI interface *
     * ***************** */
    public Location2D getPanelLocation2D()
    {
        return panelLocation;
    }
    
    public LocationContext getLocationContext()
    {
        return locationContext;
    }
    
    public Terminal getTerminal()
    {
        return terminal;
    }
    
    /**
     * Returns the ColorProfile associated with this node
     * <p>
     * @returns ColorProfile
     */
    public ColorProfile getColorProfile()
    {
        return colorCode;
    }
    
    public void setGroupSelectionTool(GroupSelectionTool groupSelectionTool)
    {
        this.groupSelectionTool = groupSelectionTool;
    }
    
    public void markSelected(boolean marked)
    {
        this.selectionMarked = marked;
        if (marked)
            colorCode.mark(ColorProfile.SELECTED, ColorProfile.FOREVER);
        else
            colorCode.mark(ColorProfile.SELECTED, ColorProfile.CLEAR);
        repaint();
    }
    
    
    public void dataExchange(TerminalDataSet terminalDataSet)
    {
        localTerminalDataSet = terminalDataSet;
        node.setQueryList(terminalDataSet.getQueryList());
        node.getAppCallback().signalUserRequest();
    }
        
    
    /** 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()
    {
        jPopupMenu = new javax.swing.JPopupMenu();

        addMouseListener(new java.awt.event.MouseAdapter()
        {
            public void mouseClicked(java.awt.event.MouseEvent evt)
            {
                formMouseClicked(evt);
            }
            public void mouseEntered(java.awt.event.MouseEvent evt)
            {
                formMouseEntered(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(0, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(0, 300, Short.MAX_VALUE)
        );
    }// </editor-fold>//GEN-END:initComponents

    private void formMouseEntered(java.awt.event.MouseEvent evt)//GEN-FIRST:event_formMouseEntered
    {//GEN-HEADEREND:event_formMouseEntered
         setToolTipText("<html>NodeID: " + node.getID() + "<br>Enrg [%]: " + (int)node.getEnergyManagement().getBattery().getPercentageEnergyLevel() + "<br>Coverage [ft]: " + (long)node.getEffectiveCoverage_ft() + "</html>");
         
    }//GEN-LAST:event_formMouseEntered

    private void formMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_formMouseClicked
    // TODO add your handling code here:
    }//GEN-LAST:event_formMouseClicked
    
    public void addJMenuItem(JMenuItem jMenuItem)
    {
        jPopupMenu.add(jMenuItem);
    }
    
    // Turn on-off GUI drawing
    public void setVisibility(boolean visibility)
    {
        this.setVisible(visibility);
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPopupMenu jPopupMenu;
    // End of variables declaration//GEN-END:variables

    
    /* GRAPHICS */
      public synchronized void paintComponent(Graphics g) {
          if(node != null && node.getSimControl() != null && node.getSimControl().getSpeed() == SimManager.MAX)
              return;
          
          Graphics2D g2d = (Graphics2D)g;
          long lifetime = 0;
        
        
          
          if (colorCode != null)
            {
                ColorPair colorPair = colorCode.getColorSet();
                lifetime = colorCode.getTimeToColorChange();

                if (colorPair != null)
                {
                    if (colorPair.outerColor != null)
                        {
                            g2d.setColor(colorPair.outerColor);
                            g2d.draw(outerCircle);
                        }
                    
                   if (colorPair.innerColor != null)
                        {
                            g2d.setColor(colorPair.innerColor);
                            g2d.fill(innerCircle);
                        }
                }             
            }
            else
                System.out.println("[WARNING: MyNode.java] - ColorCode not initialized");   
          
          if (panelLocation == null)
              return;
          
          int itemRow = 1;
          
          if (displayIP)
          {
              g2d.setColor(Color.BLACK);
              g2d.drawString(((Integer)node.getID()).toString(), 20, 10 * itemRow);
              itemRow++;
          }
          if (displayEnergy)
          {
              g2d.setColor(Color.BLACK);
              g2d.drawString(((Integer)(int)node.getEnergyManagement().getBattery().getPercentageEnergyLevel()).toString() + " %", 20, 10 * itemRow);
              itemRow++;
          }
          
          if (displayNeighbors)
          {
              if (node.neighboursList != null && node.neighboursList.size() > 0)
              {
                  //LinkedList<NodeEntry> neighList = 
                  for (NodeEntry nodeEntry:node.neighboursList.getAsLinkedList())
                  {
                      ArrowDrawingTool.drawArrow(this.getPanelContext().getPanelGUI().getGraphics(),
                                                 this.getPanelLocation2D(),
                                                 nodeEntry.getNCS_Location2D().fromNCS(this.getLocationContext()));
                  }
                  displayNeighbors = false;
              }
          }
          
          if (displayLocation)
          {
              g2d.setColor(Color.BLACK);
              //g2d.drawString(((Integer)(int)node.getLocation2D().getX()).toString() + " x " + ((Integer)(int)node.getLocation2D().getX()).toString(), 20, 10 * itemRow);
              g2d.drawString(((Integer)(int)getPanelLocation2D().getX()).toString() + " x " + ((Integer)(int)getPanelLocation2D().getY()).toString(), 20, 10 * itemRow);
              itemRow++;
          }
          if (displayUdefData1)
          {
              g2d.setColor(Color.BLACK);
              g2d.drawString("" + userDefinedData1 , 20, 10 * itemRow);
              itemRow++;
          }
          if (displayUdefData2)
          {
              g2d.setColor(Color.BLACK);
              g2d.drawString("" + userDefinedData2 , 20, 10 * itemRow);
              itemRow++;
          }
          if (displayUdefData3)
          {
              g2d.setColor(Color.BLACK);
              g2d.drawString("" + userDefinedData3 , 20, 10 * itemRow);
              itemRow++;
          }
          
          if (lifetime != 0)
              repaint(lifetime);
        }

    protected void clear(Graphics g) {
        //super.paintComponent(g);
    }    
    
    public void addPopupMenus(JPopupMenu extraNodePopupMenus)
    {
        nodePopupMenu.add(extraNodePopupMenus);
    }
    
    public void actionPerformed(ActionEvent e) {
        if (groupSelectionTool != null && groupSelectionTool.groupExists() && groupSelectionTool.isGroupMember(this.node))
            groupSelectionTool.notifyActionPerformed(node, e);
        else
            handleAction(e);
     }
    
    
    public void setUserDefinedData1(int data)
    {
        this.userDefinedData1 = data;
    }
    
    public void setUserDefinedData2(int data)
    {
        this.userDefinedData2 = data;
    }

     public void setUserDefinedData3(int data)
    {
        this.userDefinedData3 = data;
    }

    public void handleAction(ActionEvent e)
    {
        if (e.getActionCommand() == "Connect Terminal to ...")
        {
            terminal.dataExchange(localTerminalDataSet, node, this);
        }
        if (e.getActionCommand() == "Show/Hide Node ID")
        {
            displayIP = !displayIP;  
            if (displayIP)
                displayItemCount++;
            else
                displayItemCount--;
        }
        if (e.getActionCommand() == "Show/Hide Location Coordinates")
        {
            displayLocation = !displayLocation;
            if (displayLocation)
                displayItemCount++;
            else
                displayItemCount--;
        }
        if (e.getActionCommand() == "Show/Hide Energy Levels")
        {
            displayEnergy = !displayEnergy;
            if (displayEnergy)
                displayItemCount++;
            else
                displayItemCount--;
        }
        
       
        if (e.getActionCommand() == "Show/Hide Discovered Neighbors")
        {
            displayNeighbors = !displayNeighbors;
        }
        
        if (e.getActionCommand() == "Show/Hide User Defined Data 1")
        {
            displayUdefData1 = !displayUdefData1;
            displayItemCount++;
            if (displayUdefData1)
                displayItemCount++;
            else
                displayItemCount--;
        }
        
        if (e.getActionCommand() == "Show/Hide User Defined Data 2")
        {
            displayUdefData2 = !displayUdefData2;
            displayItemCount++;
            if (displayUdefData2)
                displayItemCount++;
            else
                displayItemCount--;
        }
        
        if (e.getActionCommand() == "Show/Hide User Defined Data 3")
        {
            displayUdefData3 = !displayUdefData3;
            if (displayUdefData3)
                displayItemCount++;
            else
                displayItemCount--;
        }
        
        if (e.getActionCommand() == "Kill Node")
        {
            ((BatteryControl)node.getEnergyManagement().getBattery()).deplete();
            colorCode.mark(ColorProfile.DEAD, ColorProfile.FOREVER);    
        }
        
        // calculate extraWidth
        int extraWidth = 13;
        if (displayIP)
            extraWidth = extraWidth < 30 ? 30 : extraWidth;
        if (displayLocation)
            extraWidth = extraWidth < 80 ? 80 : extraWidth;
        if (displayEnergy)
            extraWidth = extraWidth < 40 ? 40 : extraWidth;
        if (displayUdefData1 || displayUdefData2 || displayUdefData3)
            extraWidth = extraWidth < 50 ? 50 : extraWidth;

        this.setBounds(panelLocation.getX(), panelLocation.getY(), 13 + extraWidth, 13 * (displayItemCount + 1));
        
        repaint();
    }
    
     public void mouseClicked(MouseEvent e) {   
        /* If right-click, pop-up the menu */
        if (e.getButton() == e.BUTTON3)
           if (e.getX() <= 13)
                nodePopupMenu.show(this, 20,20);
          
        
        /* If left-click, select/deselect the node */
        if (e.getButton() == e.BUTTON1)
            if (groupSelectionTool != null)
                groupSelectionTool.notifySelected(this.node, !selectionMarked);
        
     }
    
    public void mouseEntered(MouseEvent e) {}
    
    public void mouseExited(MouseEvent e) {}
    
    public void mousePressed(MouseEvent e) {}
    
    public void mouseReleased(MouseEvent e) {}
    
}
