package netmatch.qtool;

import edu.umd.cs.piccolo.PCanvas;
import edu.umd.cs.piccolo.PLayer;
import edu.umd.cs.piccolo.event.PBasicInputEventHandler;
import edu.umd.cs.piccolo.event.PInputEvent;
import javax.swing.*;
import java.awt.geom.Point2D;
import java.awt.*;
import java.util.ArrayList;

public class QCreateStructure extends PBasicInputEventHandler {
  private QToolFrame frame;
  private int structureType;

  public QCreateStructure(QToolFrame frame) {
    this.frame = frame;
    structureType = Common.THREE_CHAIN;
  }

  private void showPopup(PInputEvent event) {
    Point2D pos = event.getPosition();
    int x = (int) pos.getX();
    int y = (int) pos.getY();

    QElement popupElement;

    if(event.getPickedNode() instanceof QText)
      popupElement = ((QText) event.getPickedNode()).getOwner();
    else if(!(event.getPickedNode() instanceof QElement))
      return;
    else
      popupElement = (QElement) event.getPickedNode();

    frame.popup.show((Component) event.getComponent(), x, y, popupElement);
  }

  private void showInfo(PInputEvent event) {
    QElement elem;
    if(event.getPickedNode() instanceof QText)
      elem = ((QText) event.getPickedNode()).getOwner();
    else if(event.getPickedNode() instanceof QElement)
      elem = (QElement) event.getPickedNode();
    else {
      frame.infoArea.setText("");
      return;
    }
    frame.infoArea.setText(elem.getInfo());
  }

  public void mouseMoved(PInputEvent event) {
    super.mouseMoved(event);
    showInfo(event);
  }

  public void setStructure(int i) {
    structureType = i;
  }

  public void mouseClicked(PInputEvent event) {
    if(event.isRightMouseButton()) {
      showPopup(event);
      return;
    }
    //System.out.println("click:" + structureType);
    if(!event.isLeftMouseButton())
      return;
    // create new node as composition of ellipse and text
    PLayer edgeLayer = ((PCanvas) (event.getComponent())).getCamera().getLayer(0);
    PLayer nodeLayer = ((PCanvas) (event.getComponent())).getCamera().getLayer(1);
    Point2D pressPoint = event.getPosition();
    switch(structureType) {
      case Common.THREE_CHAIN: {
        QNode node1 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY(), "n" + Network.nodeCount++);
        QNode node2 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY() + 60, "n" + Network.nodeCount++);
        QNode node3 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY() + 120, "n" + Network.nodeCount++);
        QEdge edge1 = new QEdge("e" + Network.edgeCount++);
        edge1.setSource(node1);
        edge1.setTarget(node2);
        node1.addEdge(edge1);
        node2.addEdge(edge1);
        QEdge edge2 = new QEdge("e" + Network.edgeCount++);
        edge2.setSource(node2);
        edge2.setTarget(node3);
        node2.addEdge(edge2);
        node3.addEdge(edge2);
        node1.addToLayer(nodeLayer);
        node2.addToLayer(nodeLayer);
        node3.addToLayer(nodeLayer);
        edgeLayer.addChild(edge1);
        edgeLayer.addChild(edge2);
        edge1.update();
        edge2.update();
        Network.nCount += 3;
        Network.eCount += 2;
        frame.updateStatus();
        break;
      }
      case Common.FEED_FORWARD_LOOP: {
        QNode node1 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY(), "n" + Network.nodeCount++);
        QNode node2 = new QNode((float) pressPoint.getX() + 50, (float) pressPoint.getY() + 50, "n" + Network.nodeCount++);
        QNode node3 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY() + 100, "n" + Network.nodeCount++);
        QEdge edge1 = new QEdge("e" + Network.edgeCount++);
        edge1.setSource(node1);
        edge1.setTarget(node2);
        node1.addEdge(edge1);
        node2.addEdge(edge1);
        QEdge edge2 = new QEdge("e" + Network.edgeCount++);
        edge2.setSource(node2);
        edge2.setTarget(node3);
        node2.addEdge(edge2);
        node3.addEdge(edge2);
        QEdge edge3 = new QEdge("e" + Network.edgeCount++);
        edge3.setSource(node1);
        edge3.setTarget(node3);
        node1.addEdge(edge3);
        node3.addEdge(edge3);
        node1.addToLayer(nodeLayer);
        node2.addToLayer(nodeLayer);
        node3.addToLayer(nodeLayer);
        edgeLayer.addChild(edge1);
        edgeLayer.addChild(edge2);
        edgeLayer.addChild(edge3);
        edge1.update();
        edge2.update();
        edge3.update();
        Network.nCount += 3;
        Network.eCount += 3;
        frame.updateStatus();
        break;
      }
      case Common.BI_FAN: {
        QNode node1 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY(), "n" + Network.nodeCount++);
        QNode node2 = new QNode((float) pressPoint.getX() + 70, (float) pressPoint.getY(), "n" + Network.nodeCount++);
        QNode node3 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY() + 70, "n" + Network.nodeCount++);
        QNode node4 = new QNode((float) pressPoint.getX() + 70, (float) pressPoint.getY() + 70, "n" + Network.nodeCount++);
        QEdge edge1 = new QEdge("e" + Network.edgeCount++);
        edge1.setSource(node1);
        edge1.setTarget(node3);
        node1.addEdge(edge1);
        node3.addEdge(edge1);
        QEdge edge2 = new QEdge("e" + Network.edgeCount++);
        edge2.setSource(node1);
        edge2.setTarget(node4);
        node1.addEdge(edge2);
        node4.addEdge(edge2);
        QEdge edge3 = new QEdge("e" + Network.edgeCount++);
        edge3.setSource(node2);
        edge3.setTarget(node3);
        node2.addEdge(edge3);
        node3.addEdge(edge3);
        QEdge edge4 = new QEdge("e" + Network.edgeCount++);
        edge4.setSource(node2);
        edge4.setTarget(node4);
        node2.addEdge(edge4);
        node4.addEdge(edge4);
        node1.addToLayer(nodeLayer);
        node2.addToLayer(nodeLayer);
        node3.addToLayer(nodeLayer);
        node4.addToLayer(nodeLayer);
        edgeLayer.addChild(edge1);
        edgeLayer.addChild(edge2);
        edgeLayer.addChild(edge3);
        edgeLayer.addChild(edge4);
        edge1.update();
        edge2.update();
        edge3.update();
        edge4.update();
        Network.nCount += 4;
        Network.eCount += 4;
        frame.updateStatus();
        break;
      }
      case Common.MTON_FAN: {
        ArrayList mn = mToN();
        if(mn == null)
          break;
        int m = ((Integer) mn.get(0)).intValue();
        int n = ((Integer) mn.get(1)).intValue();
        ArrayList mNodes = new ArrayList(m);
        ArrayList nNodes = new ArrayList(n);
        // the first layer (m nodes)
        int shift = 0;
        if(m < n)
          shift = 35 * (n - m);
        for(int i = 0;i < m;i++) {
          QNode node = new QNode((float) pressPoint.getX() + 70 * i + shift, (float) pressPoint.getY(), "n" + Network.nodeCount++);
          node.addToLayer(nodeLayer);
          mNodes.add(node);
        }
        if(m > n)
          shift = 35 * (m - n);
        else
          shift = 0;
        // the second layer (n nodes)
        for(int i = 0;i < n;i++) {
          QNode node = new QNode((float) pressPoint.getX() + 70 * i + shift, (float) pressPoint.getY() + 70, "n" + Network.nodeCount++);
          node.addToLayer(nodeLayer);
          nNodes.add(node);
        }
        // connect m to n
        for(int s = 0;s < m;s++)
          for(int t = 0;t < n;t++) {
            QEdge edge = new QEdge("e" + Network.edgeCount++);
            QNode snode = (QNode) mNodes.get(s);
            QNode tnode = (QNode) nNodes.get(t);
            edge.setSource(snode);
            edge.setTarget(tnode);
            snode.addEdge(edge);
            tnode.addEdge(edge);
            edgeLayer.addChild(edge);
            edge.update();
          }

        Network.nCount += (m + n);
        Network.eCount += m * n;
        frame.updateStatus();
        break;
      }
      case Common.BI_PARALLEL: {
        QNode node1 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY(), "n" + Network.nodeCount++);
        QNode node2 = new QNode((float) pressPoint.getX() - 50, (float) pressPoint.getY() + 50, "n" + Network.nodeCount++);
        QNode node3 = new QNode((float) pressPoint.getX() + 50, (float) pressPoint.getY() + 50, "n" + Network.nodeCount++);
        QNode node4 = new QNode((float) pressPoint.getX(), (float) pressPoint.getY() + 100, "n" + Network.nodeCount++);
        QEdge edge1 = new QEdge("e" + Network.edgeCount++);
        edge1.setSource(node1);
        edge1.setTarget(node2);
        node1.addEdge(edge1);
        node2.addEdge(edge1);
        QEdge edge2 = new QEdge("e" + Network.edgeCount++);
        edge2.setSource(node1);
        edge2.setTarget(node3);
        node1.addEdge(edge2);
        node3.addEdge(edge2);
        QEdge edge3 = new QEdge("e" + Network.edgeCount++);
        edge3.setSource(node2);
        edge3.setTarget(node4);
        node2.addEdge(edge3);
        node4.addEdge(edge3);
        QEdge edge4 = new QEdge("e" + Network.edgeCount++);
        edge4.setSource(node3);
        edge4.setTarget(node4);
        node3.addEdge(edge4);
        node4.addEdge(edge4);
        node1.addToLayer(nodeLayer);
        node2.addToLayer(nodeLayer);
        node3.addToLayer(nodeLayer);
        node4.addToLayer(nodeLayer);
        edgeLayer.addChild(edge1);
        edgeLayer.addChild(edge2);
        edgeLayer.addChild(edge3);
        edgeLayer.addChild(edge4);
        edge1.update();
        edge2.update();
        edge3.update();
        edge4.update();
        Network.nCount += 4;
        Network.eCount += 4;
        frame.updateStatus();
        break;
      }
    }
    frame.isModif = true;
    frame.setTitleModif();
  }


  private ArrayList mToN() {
    Object[] message = new Object[3];

    JSpinner mSpinner = new JSpinner(new SpinnerNumberModel(4, 0, Integer.MAX_VALUE, 1));
    //mSpinner.setValue(new Integer(4));
    JSpinner nSpinner = new JSpinner(new SpinnerNumberModel(4, 0, Integer.MAX_VALUE, 1));
    //nSpinner.setValue(new Integer(4));
    JTextField nTextField = new JTextField(25);
    JLabel mLabel = new JLabel("m:");
    mLabel.setAlignmentX(Component.LEFT_ALIGNMENT);

    JLabel nLabel = new JLabel("n: ");
    nLabel.setAlignmentX(Component.LEFT_ALIGNMENT);


    JPanel pm = new JPanel(new BorderLayout(5, 5));
    pm.add(mLabel, BorderLayout.WEST);
    pm.add(mSpinner, BorderLayout.CENTER);
    JPanel pn = new JPanel(new BorderLayout(5, 5));
    pn.add(nLabel, BorderLayout.WEST);
    pn.add(nSpinner, BorderLayout.CENTER);
    message[0] = "<html>Please select <em>m</em> and <em>n</em>:</html>";
    message[1] = pm;
    message[2] = pn;
    String[] options = {"Ok","Cancel"};
    int result = JOptionPane.showOptionDialog(
        frame, // the parent that the dialog blocks
        message, // the dialog message array
        "Please configure m to n pattern", // the title of the dialog window
        JOptionPane.DEFAULT_OPTION, // option type
        JOptionPane.INFORMATION_MESSAGE, // message type
        null, // optional icon, use null to use the default icon
        options, // options string array, will be made into buttons
        options[0]// option that should be made into a default button
    );
    switch(result) {
      case 0:// Ok
        ArrayList mn = new ArrayList();
        mn.add(mSpinner.getValue());
        mn.add(nSpinner.getValue());
        return mn;
    }
    return null;
  }

}