package netmatch.qtool;

import netmatch.algorithm.*;
import netmatch.algorithm.Common;
import netmatch.help.netMatchQuickHelp;
import netmatch.piccolox.PScrollPane;
import edu.umd.cs.piccolo.PLayer;
import edu.umd.cs.piccolo.PNode;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.Point2D;
import java.io.*;
import java.util.Hashtable;
import java.util.Iterator;

public class QToolFrame extends JFrame implements ActionListener, WindowListener {
  final static Color EDGE_COLOR = new Color(77, 77, 255);
  private QCanvas canvas;
  public JTextArea infoArea;
  private JTextField statusBar;
  private JButton[] pButtons;
  private JButton[] sButtons;
  private Border originalBorder;
  private EtchedBorder selBorder;
  private IQueryRecipient recipient;
  private String queryName = "";
  boolean isModif;
  private String title;
  public ImageIcon[] icons, structures, menu;
  private String LastDirectory;
  private int counter;
  private boolean isSaved;
  public QPopupMenu popup;
  netMatchQuickHelp h;

  public QToolFrame(String title, IQueryRecipient recipient, ImageIcon[] icons, ImageIcon[] structures, ImageIcon[] menu) {
    this.recipient = recipient;
    this.title = title;
    this.icons = icons;
    this.menu = menu;
    this.structures = structures;
    setIconImage(menu[20].getImage());
    isModif = false;
    getContentPane().setLayout(new BorderLayout());
    setTitle(title + " - new query");
    setSize(800, 600);
    addWindowListener(this);
    JPanel leftPanel = new JPanel();
    leftPanel.setPreferredSize(new Dimension(160, 200));
    leftPanel.setLayout(new BorderLayout());

    // Panel 1
    JPanel palettePanel = new JPanel();
    GridLayout paletteLayout = new GridLayout(4, 2);
    paletteLayout.setHgap(3);
    paletteLayout.setVgap(3);
    palettePanel.setLayout(paletteLayout);
    palettePanel.setBorder(new TitledBorder("Choose one:"));
    palettePanel.setName("Components");
    String[] names = {"Select","Move","Node","Loop","Edge","Path","ZoomIn","ZoomOut"};
    String[] tooltip = {"Select","Move","Add Node","Add Loop","Add Edge","Add Path","Zoom In","Zoom Out"};
    selBorder = new EtchedBorder(EtchedBorder.RAISED, Color.blue, Color.blue);
    BListener bListener = new BListener();
    pButtons = new JButton[tooltip.length];
    for(int i = 0;i < pButtons.length;i++) {
      if(icons[i] != null)
        pButtons[i] = new JButton("", icons[i + 1]);
      else
        pButtons[i] = new JButton("");
      pButtons[i].setName(names[i]);
      pButtons[i].setToolTipText(tooltip[i]);
      pButtons[i].addActionListener(bListener);
      pButtons[i].setFocusable(false);
    }
    if(pButtons.length > 0)
      originalBorder = pButtons[0].getBorder();
    for(int i = 0;i < pButtons.length;i++)
      palettePanel.add(pButtons[i]);
    pButtons[0].setBorder(selBorder);

    // Panel 2
    JPanel structurePanel = new JPanel();
    GridLayout strLayout = new GridLayout(structures.length, 1);
    strLayout.setVgap(4);
    structurePanel.setLayout(strLayout);
    sButtons = new JButton[5];
    sButtons[0] = new JButton(structures[0]);
    sButtons[0].setName("TreeChain");
    sButtons[0].setToolTipText("Three Chain");
    sButtons[0].addActionListener(bListener);
    structurePanel.add(sButtons[0]);
    sButtons[1] = new JButton(structures[1]);
    sButtons[1].setName("FeedForwardLoop");
    sButtons[1].setToolTipText("Feed Forward Loop");
    sButtons[1].addActionListener(bListener);
    structurePanel.add(sButtons[1]);
    sButtons[2] = new JButton(structures[2]);
    sButtons[2].setName("Bi-Parallel");
    sButtons[2].setToolTipText("Bi-Parallel");
    sButtons[2].addActionListener(bListener);
    structurePanel.add(sButtons[2]);
    sButtons[3] = new JButton(structures[3]);
    sButtons[3].setName("Bi-Fan");
    sButtons[3].setToolTipText("Bi-Fan");
    sButtons[3].addActionListener(bListener);
    structurePanel.add(sButtons[3]);
    sButtons[4] = new JButton(structures[4]);
    sButtons[4].setName("MtoN-Fan");
    sButtons[4].setToolTipText("m to n");
    sButtons[4].addActionListener(bListener);
    structurePanel.add(sButtons[4]);
    structurePanel.setBorder(new EmptyBorder(4, 4, 4, 4));
    JScrollPane p = new JScrollPane();
    p.getViewport().add(structurePanel);

    // tabbed pane
    JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
    tabbedPane.addTab("Palette", null, palettePanel, "");
    tabbedPane.addTab("Motifs", null, p, "");

    JPanel m = new JPanel(new GridLayout(2, 1, 3, 3));
    m.add(tabbedPane);

    JPanel infoPanel = new JPanel();
    infoPanel.setLayout(new BorderLayout());
    infoPanel.setBorder(new TitledBorder("Info:"));

    // create info area
    infoArea = new JTextArea();
    infoArea.setEditable(false);
    infoArea.setMinimumSize(new Dimension(160, 130));
    infoArea.setFont(new Font("SansSerif", Font.PLAIN, 12));
    infoArea.setBorder(new EtchedBorder());
    infoPanel.add(infoArea, BorderLayout.CENTER);
    infoPanel.setMinimumSize(new Dimension(160, 160));
    m.add(infoPanel);

    leftPanel.add(m, BorderLayout.CENTER);

    JButton pass = new JButton("<html>Pass Query<br> to NetMatch</html>", menu[4]);
    pass.setToolTipText("<html>Clicking on this button the query<br> will be uploaded to NetMatch main windows.</html>");
    pass.addActionListener(this);
    pass.setActionCommand("Pass query to NetMatch");
    leftPanel.add(pass, BorderLayout.SOUTH);

    // add to frame
    getContentPane().add(leftPanel, BorderLayout.WEST);

    statusBar = new JTextField();
    statusBar.setBackground(SystemColor.control);
    statusBar.setEditable(false);
    //statusBar.setForeground(new Color(212, 208, 200));
    statusBar.setForeground(Color.BLACK);

    statusBar.setBorder(new EtchedBorder());
    getContentPane().add(statusBar, BorderLayout.SOUTH);

    // create main menu
    JPanel menubar = new JPanel(new BorderLayout());
    JMenuBar bar = createMainMenu();
    menubar.add(bar, BorderLayout.NORTH);
    menubar.add(createToolBar(), BorderLayout.SOUTH);
    getContentPane().add(menubar, BorderLayout.NORTH);

    // add piccolo canvas
    canvas = new QCanvas(this);
    getContentPane().add(canvas, BorderLayout.CENTER);
    PScrollPane scrollPane = new PScrollPane(canvas);
    getContentPane().add(scrollPane);

    // create popup menu
    popup = new QPopupMenu(this);

    // pack all and show
    setupMode(0);
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    setLocation(screenSize.width / 2 - getWidth() / 2, screenSize.height / 2 - getHeight() / 2);
    LastDirectory = ".";
    counter = 1;
    isSaved = false;
    updateStatus();
    setVisible(true);
  }


  private JToolBar createToolBar() {
    JToolBar toolbar = new JToolBar();
    JButton b1;
    b1 = new JButton(menu[0]);
    b1.setToolTipText("New query");
    b1.addActionListener(this);
    b1.setActionCommand("New query");
    toolbar.add(b1);
    b1 = new JButton(menu[1]);
    b1.setToolTipText("Load query");
    b1.addActionListener(this);
    b1.setActionCommand("Load query...");
    toolbar.add(b1);
    b1 = new JButton(menu[2]);
    b1.setToolTipText("Save query");
    b1.addActionListener(this);
    b1.setActionCommand("Save query");
    toolbar.add(b1);
    b1 = new JButton(menu[3]);
    b1.setToolTipText("Change query name");
    b1.addActionListener(this);
    b1.setActionCommand("Change query name");
    toolbar.add(b1);
    /*b1 = new JButton(menu[4]);
    b1.setToolTipText("Pass query to NetMatch");
    b1.addActionListener(this);
    b1.setActionCommand("Pass query to NetMatch");
    toolbar.add(b1);*/
    b1 = new JButton(menu[5]);
    b1.setToolTipText("Exit");
    b1.addActionListener(this);
    b1.setActionCommand("Exit");
    toolbar.add(b1);
    toolbar.addSeparator();
    b1 = new JButton(menu[6]);
    b1.setToolTipText("Clear");
    b1.addActionListener(this);
    b1.setActionCommand("Clear");
    toolbar.add(b1);
    toolbar.addSeparator();
    b1 = new JButton(menu[19]);
    b1.setToolTipText("Quick Help");
    b1.addActionListener(this);
    b1.setActionCommand("Quick Help");
    toolbar.add(b1);
    return toolbar;
  }

  public void setTitleModif() {
    if(!queryName.equals(""))
      setTitle(title + " - " + getShortName(queryName) + "*");
    else
      setTitle(title + " - new query*");
  }

  // returns name without path and extention
  private String getNetworkName(String fullName) {
    int lastP = fullName.lastIndexOf('.');
    int lastS = fullName.lastIndexOf('\\');
    return lastP == -1 || lastP < lastS ? fullName.substring(lastS + 1) : fullName.substring(lastS + 1, lastP);
  }

  private String getShortName(String fullName) {
    int lastS = fullName.lastIndexOf('\\');
    return fullName.substring(lastS + 1);
  }

  // returns name without extention
  private String getNameWithoutExt(String fullName) {
    int lastP = fullName.lastIndexOf('.');
    int lastS = fullName.lastIndexOf('\\');
    return lastP == -1 || lastP < lastS ? fullName : fullName.substring(0, lastP);
  }

  private String addSIFExt(String fullName) {
    return getNameWithoutExt(fullName) + ".sif";
  }

  private String addNAExt(String fullName) {
    return getNameWithoutExt(fullName) + ".NA";
  }

  private String addEAExt(String fullName) {
    return getNameWithoutExt(fullName) + ".EA";
  }

  private void SaveAs() {
    JFileChooser c = new JFileChooser();
    qtoolFileFilter filter = new qtoolFileFilter("sif", "SIF network");
    c.addChoosableFileFilter(filter);
    c.setCurrentDirectory(new File(LastDirectory));
    int rVal = c.showSaveDialog(this);
    if(rVal == JFileChooser.APPROVE_OPTION) {
      queryName = c.getSelectedFile().getAbsolutePath();
      queryName = addSIFExt(queryName);
      saveNetwork(queryName);
      setTitle(title + " - " + getShortName(queryName));
      LastDirectory = c.getSelectedFile().getAbsolutePath();
    }
  }

  public void actionPerformed(ActionEvent e) {
    String command = e.getActionCommand();
    if(command.equals("Load query...")) {
      check();
      queryName = "";
      isModif = false;
      setTitle(title + " - new query");
      Network.clean(canvas.getNodeLayerReference(), canvas.getEdgeLayerReference());
      JFileChooser c = new JFileChooser();
      c.setCurrentDirectory(new File(LastDirectory));
      qtoolFileFilter filter = new qtoolFileFilter("sif", "SIF network");
      c.addChoosableFileFilter(filter);
      int rVal = c.showOpenDialog(this);
      if(rVal == JFileChooser.APPROVE_OPTION) {
        queryName = c.getSelectedFile().getAbsolutePath();
        loadNetwork(c.getSelectedFile().getAbsolutePath());
        setTitle(title + " - " + getShortName(queryName));
        LastDirectory = c.getSelectedFile().getAbsolutePath();
        isSaved = true;
      }
    }
    if(command.equals("Load node attributes...")) {
      JFileChooser c = new JFileChooser();
      c.setCurrentDirectory(new File(LastDirectory));
      qtoolFileFilter filter = new qtoolFileFilter("NA", "SIF Node Attributes");
      c.addChoosableFileFilter(filter);
      int rVal = c.showOpenDialog(this);
      if(rVal == JFileChooser.APPROVE_OPTION) {
        loadNodeAttributes(c.getSelectedFile().getAbsolutePath());
        LastDirectory = c.getSelectedFile().getAbsolutePath();
        isModif = true;
        setTitleModif();
      }
    }
    if(command.equals("Load edge attributes...")) {
      JFileChooser c = new JFileChooser();
      c.setCurrentDirectory(new File(LastDirectory));
      qtoolFileFilter filter = new qtoolFileFilter("EA", "SIF Edge Attributes");
      c.addChoosableFileFilter(filter);
      int rVal = c.showOpenDialog(this);
      if(rVal == JFileChooser.APPROVE_OPTION) {
        loadEdgeAttributes(c.getSelectedFile().getAbsolutePath());
        LastDirectory = c.getSelectedFile().getAbsolutePath();
        isModif = true;
        setTitleModif();
      }
    }
    if(command.equals("New query")) {
      check();
      queryName = "";
      setTitle(title + " - new query");
      isModif = false;
      Network.clean(canvas.getNodeLayerReference(), canvas.getEdgeLayerReference());
      isSaved = false;
      updateStatus();
    }
    else if(command.equals("Save query")) {
      //System.out.println("bool:" + canvas.getNodeLayerReference().getAllNodes().size());
      if(canvas.getNodeLayerReference().getAllNodes().size() > 1) {
        if(queryName.equals(""))
          SaveAs();
        else {
          saveNetwork(queryName);
          setTitle(title + " - " + getShortName(queryName));
        }
        isModif = false;
      }
    }
    else if(command.equals("Save query as...")) {
      if(canvas.getNodeLayerReference().getAllNodes().size() > 1)
        SaveAs();
      isModif = false;
    }
    else if(command.equals("Save node attributes as...")) {
      if(canvas.getNodeLayerReference().getAllNodes().size() > 1) {
        JFileChooser c = new JFileChooser();
        qtoolFileFilter filter = new qtoolFileFilter("NA", "SIF Node Attributes");
        c.addChoosableFileFilter(filter);
        c.setCurrentDirectory(new File(LastDirectory));
        int rVal = c.showSaveDialog(this);
        if(rVal == JFileChooser.APPROVE_OPTION) {
          saveNodeAttributes(addNAExt(c.getSelectedFile().getAbsolutePath()));
          LastDirectory = c.getSelectedFile().getAbsolutePath();
        }
      }
    }
    else if(command.equals("Save edge attributes as...")) {
      if(canvas.getNodeLayerReference().getAllNodes().size() > 1) {
        JFileChooser c = new JFileChooser();
        qtoolFileFilter filter = new qtoolFileFilter("EA", "SIF Edge Attributes");
        c.addChoosableFileFilter(filter);
        c.setCurrentDirectory(new File(LastDirectory));
        int rVal = c.showSaveDialog(this);
        if(rVal == JFileChooser.APPROVE_OPTION) {
          saveEdgeAttributes(addEAExt(c.getSelectedFile().getAbsolutePath()));
          LastDirectory = c.getSelectedFile().getAbsolutePath();
        }
      }
    }
    else if(command.equals("Change query name")) {
      String name = JOptionPane.showInputDialog(this, "Enter a name for query:");
      if(name != null) {
        queryName = name;
        setTitle(title + " - " + getShortName(queryName));
        isSaved = false;
      }
    }
    else if(command.equals("Pass query to NetMatch")) {
      if(canvas.getNodeLayerReference().getAllNodes().size() > 1) {
        passOptions();
      }
    }
    else if(command.equals("Clear")) {
      Network.clean(canvas.getNodeLayerReference(), canvas.getEdgeLayerReference());
      updateStatus();
      isModif = false;
    }
    else if(command.equals("Quick Help")) {
      h = new netMatchQuickHelp("NetMatch Quick Help", menu[20]);
      h.setVisible(true);
    }
    else if(command.equals("Exit"))
      exit();
  }

  private void check() {
    //System.out.println("modf:"+isModif+" issave:"+isSaved);
    if(isModif) {
      String nn = queryName.equals("") ? "new query" : getShortName(queryName);
      int r = JOptionPane.showConfirmDialog(this, "Do you want to save " + nn, "Graph Editor", JOptionPane.YES_NO_OPTION);
      if(r == JOptionPane.YES_OPTION) {
        if(!isSaved)
          SaveAs();
        else
          saveNetwork(queryName);
      }
    }
  }

  private void saveNetwork(String fullName) {
    FileWriter writer;
    try {
      writer = new FileWriter(fullName);
      Network.saveStructure(writer, canvas);
      String name = getNameWithoutExt(fullName);
      writer = new FileWriter(name + ".NA");
      Network.saveNodeAttr(writer, canvas.getNodeLayerReference());
      writer = new FileWriter(name + ".EA");
      Network.saveEdgeAttr(writer, canvas.getEdgeLayerReference());
      isSaved = true;
    }
    catch(IOException e) {
      System.err.println("Can't open the file: " + fullName);
    }
  }

  private void saveNodeAttributes(String fullName) {
    FileWriter writer;
    try {
      writer = new FileWriter(fullName);
      Network.saveNodeAttr(writer, canvas.getNodeLayerReference());
    }
    catch(IOException e) {
      System.err.println("Can't open the file: " + fullName);
    }
  }

  private void saveEdgeAttributes(String fullName) {
    FileWriter writer;
    try {
      writer = new FileWriter(fullName);
      Network.saveEdgeAttr(writer, canvas.getEdgeLayerReference());
    }
    catch(IOException e) {
      System.err.println("Can't open the file: " + fullName);
    }
  }


  private boolean loadNetwork(String fullName) {
    Network.clean(canvas.getNodeLayerReference(), canvas.getEdgeLayerReference());
    //System.out.println(name);
    FileReader reader;
    try {
      reader = new FileReader(fullName);
      Network.loadStructure(reader, canvas);
      updateStatus();
    }
    catch(FileNotFoundException e) {
      System.err.println("Can't open the file: " + fullName);
    }
    catch(InvalidSIFException e) {
      System.err.println("Network structure file: " + fullName + "\n" + e.getMessage());
    }
    String name = getNameWithoutExt(fullName);
    try {
      reader = new FileReader(name + ".NA");
      Network.loadNodeAttr(reader, canvas.getNodeLayerReference());
    }
    catch(FileNotFoundException e) {
      //System.err.println("Node attributes aren't found: " + name);
    }
    catch(InvalidSIFException e) {
      System.err.println("Node labels file: " + name + "\n" + e.getMessage());
    }
    try {
      reader = new FileReader(name + ".EA");
      Network.loadEdgeLoopAttr(reader, canvas.getEdgeLayerReference());
    }
    catch(FileNotFoundException e) {
      //System.err.println("Edge attributes aren't found: " + name);
    }
    catch(InvalidSIFException e) {
      System.err.println("Edge labels file: " + name + "\n" + e.getMessage());
    }
    return true;
  }

  private void loadNodeAttributes(String fullName) {
    FileReader reader;
    try {
      reader = new FileReader(fullName);
      Network.loadNodeAttr(reader, canvas.getNodeLayerReference());
    }
    catch(FileNotFoundException e) {
      //System.err.println("Node attributes aren't found: " + name);
    }
    catch(InvalidSIFException e) {
      System.err.println("Node labels file: " + fullName + "\n" + e.getMessage());
    }
  }

  private void loadEdgeAttributes(String fullName) {
    FileReader reader;
    try {
      reader = new FileReader(fullName);
      Network.loadEdgeLoopAttr(reader, canvas.getEdgeLayerReference());
    }
    catch(FileNotFoundException e) {
      //System.err.println("Node attributes aren't found: " + name);
    }
    catch(InvalidSIFException e) {
      System.err.println("Node labels file: " + fullName + "\n" + e.getMessage());
    }
  }

  /*public void updateLookAndFeel(String lookAndFeel) {
    try {
      UIManager.setLookAndFeel(lookAndFeel);
      SwingUtilities.updateComponentTreeUI(this);
    }
    catch(Exception ex) {
      JOptionPane.showMessageDialog(this, "QTool: Failed loading L&F: " + lookAndFeel, "QTool Error", JOptionPane.ERROR_MESSAGE);
      System.err.println();
    }
  }*/

  /*private boolean isApproximate(PLayer edgeLayer) throws Exception {
    Iterator it = edgeLayer.getAllNodes().iterator();
    while(it.hasNext()) {
      PNode candNode = (PNode)it.next();
      if(candNode instanceof QPath)
        return true;
    }
    return false;
  }*/

  private GraphLoader loadGraphFromQTool(PLayer nodeLayer, PLayer edgeLayer) throws Exception {
    GraphLoader loader;
    Hashtable names = new Hashtable();
    int i, id;

    i = 0;
    id = 0;
    recipient.clearPaths();
    recipient.setQueryApproximate(false);
    loader = new GraphLoader(null);
    Iterator it = nodeLayer.getAllNodes().iterator();
    while(it.hasNext()) {
      PNode candNode = (PNode) it.next();
      if(!(candNode instanceof QNode))
        continue;
      QNode node = (QNode) candNode;
      String name1 = node.getId();
      String name1Attr = node.getAttr();
      if(!names.containsKey(name1)) {
        names.put(name1, new Integer(i++));
        loader.InsertNode(name1Attr, id++, false);
      }
    }
    it = edgeLayer.getAllNodes().iterator();
    while(it.hasNext()) {
      PNode candNode = (PNode) it.next();
      if(candNode instanceof QEdge) {
        QEdge edge = (QEdge) candNode;
        String type = edge.getAttr();
        QNode source = edge.getSource();
        QNode dest = edge.getTarget();
        String name1 = source.getId();
        String name2 = dest.getId();
        //String name1Attr = source.getAttr();
        //String name2Attr = dest.getAttr();
        loader.InsertEdge(((Integer) names.get(name1)).intValue(), ((Integer) names.get(name2)).intValue(), type, false);
        if(!netmatch.algorithm.Common.DIRECTED) {
          loader.InsertEdge(((Integer) names.get(name2)).intValue(), ((Integer) names.get(name1)).intValue(), type, false);
        }
      }
      else if(candNode instanceof QLoop) {
        QLoop edge = (QLoop) candNode;
        String type = edge.getAttr();
        QNode node = edge.getOwner();
        String name1 = node.getId();
        String name2 = name1 + Common.SELF_EDGE;
        String name1Attr = node.getAttr();
        String name2Attr = name1Attr + Common.SELF_EDGE;
        if(!names.containsKey(name2)) {
          names.put(name2, new Integer(i++));
          loader.InsertNode(name2Attr, id++, true);
        }
        loader.InsertEdge(((Integer) names.get(name1)).intValue(), ((Integer) names.get(name2)).intValue(), type, true);
        if(!Common.DIRECTED) {
          loader.InsertEdge(((Integer) names.get(name2)).intValue(), ((Integer) names.get(name1)).intValue(), type, true);
        }
      }
      else if(candNode instanceof QPath) {
        recipient.setQueryApproximate(true);
        QPath p = (QPath) candNode;
        String type = p.getAttr();
        QNode source = p.getSource();
        QNode dest = p.getTarget();
        String name1 = source.getId();
        String name2 = dest.getId();
        //String name1Attr = source.getAttr();
        //String name2Attr = dest.getAttr();
        Integer index1 = (Integer) names.get(name1);
        Integer index2 = (Integer) names.get(name2);
        recipient.addQPath(index1 + "," + index2 + "," + type);
      }
    }
    /*}
    catch(Exception e) {
        System.err.println("NetMatch Error. UNable to create Network!");
    }*/
    //System.out.println("names:\n"+names);
    return loader;
  }

  private JMenuBar createMainMenu() {
    JMenu[] menus = {new JMenu("Query"),new JMenu("Edit")};
    JMenuItem[] editItems = {new JMenuItem("Clear", menu[13])};
    JMenuBar jm = new JMenuBar();
    JMenuItem item = new JMenuItem("New query", menu[7]);
    item.addActionListener(this);
    menus[0].add(item);
    JMenu loadMenu = new JMenu("Load");
    loadMenu.setIcon(menu[8]);
    item = new JMenuItem("Load query...");
    item.addActionListener(this);
    loadMenu.add(item);
    item = new JMenuItem("Load node attributes...");
    item.addActionListener(this);
    loadMenu.add(item);
    item = new JMenuItem("Load edge attributes...");
    item.addActionListener(this);
    loadMenu.add(item);
    menus[0].add(loadMenu);
    JMenu saveAsMenu = new JMenu("Save As...");
    saveAsMenu.setIcon(menu[9]);
    item = new JMenuItem("Save query as...");
    item.addActionListener(this);
    saveAsMenu.add(item);
    item = new JMenuItem("Save node attributes as...");
    item.addActionListener(this);
    saveAsMenu.add(item);
    item = new JMenuItem("Save edge attributes as...");
    item.addActionListener(this);
    saveAsMenu.add(item);
    menus[0].add(saveAsMenu);
    item = new JMenuItem("Save query", menu[9]);
    item.addActionListener(this);
    menus[0].add(item);
    item = new JMenuItem("Change query name", menu[10]);
    item.addActionListener(this);
    menus[0].add(item);
    item = new JMenuItem("Pass query to NetMatch", menu[11]);
    item.addActionListener(this);
    menus[0].add(item);
    menus[0].addSeparator();
    item = new JMenuItem("Exit", menu[12]);
    item.addActionListener(this);
    menus[0].add(item);
    addItemsToMenu(menus[1], editItems);
    for(int i = 0;i < menus.length;i++)
      jm.add(menus[i]);
    return jm;
  }

  private void addItemsToMenu(JMenu menu, JMenuItem[] items) {
    for(int i = 0;i < items.length;i++) {
      items[i].addActionListener(this);
      menu.add(items[i]);
    }
  }

  private void setupMode(int i) {
    switch(i) {
      case 0:// Select
        canvas.setupSelectorMode();
        break;
      case 1:// Move
        canvas.setupMoveMode();
        break;
      case 2:// Node
        canvas.setupNodeCreatorMode();
        break;
      case 3:// Loop
        canvas.setupLoopCreatorMode();
        break;
      case 4:// Edge
        canvas.setupEdgeCreatorMode();
        break;
      case 5:// Path
        canvas.setupPathCreatorMode();
        break;
    }
  }

  public void exit() {
    if(isModif) {
      String nn = queryName.equals("") ? "new query" : getShortName(queryName);
      int r = JOptionPane.showConfirmDialog(this, "Do you want to save " + nn, "Graph Editor", JOptionPane.YES_NO_OPTION);
      if(r == JOptionPane.YES_OPTION) {
        if(!isSaved)
          SaveAs();
        else
          saveNetwork(queryName);
      }
    }
    isModif = false;
    recipient.deattachRecipient();

    setVisible(false);
    if(h != null) {
       h.setVisible(false);
      h.dispose();
    }
    dispose();
  }

  public void windowClosing(WindowEvent e) {
    exit();
  }

  void updateStatus() {
    statusBar.setText("Nodes: " + Network.nCount + " Edges: " + Network.eCount + " Paths: " + Network.pCount + " Loops: " + Network.lCount + "\n");
  }

  public void windowOpened(WindowEvent e) {
  }

  public void windowClosed(WindowEvent e) {
  }

  public void windowIconified(WindowEvent e) {
  }

  public void windowDeiconified(WindowEvent e) {
  }

  public void windowActivated(WindowEvent e) {
  }

  public void windowDeactivated(WindowEvent e) {
  }

  private void passOptions() {
    if(queryName.equals(""))
      queryName = "unnamed_" + (counter++) + ".sif";
    Object[] message = new Object[7];
    message[0] = "Your query, named \"" + getShortName(queryName) + "\", is now available in the main NetMatch window. Please choose one of the following options:";
    ButtonGroup g = new ButtonGroup();
    JRadioButton c1 = new JRadioButton("Close editor and go back to NetMatch.", true);
    JRadioButton c2 = new JRadioButton("Draw another query.", false);
    JRadioButton c3 = new JRadioButton("Leave editor open for later query editing.", false);
    g.add(c1);
    g.add(c2);
    g.add(c3);
    JCheckBox s = new JCheckBox("Save query in a file.");
    s.setSelected(true);
    message[1] = c1;
    message[2] = c2;
    message[3] = c3;
    message[4] = new JLabel(" ");
    message[5] = new JLabel(" ");
    message[6] = s;
    String[] options = {"Ok","Cancel"};

    int val = JOptionPane.showOptionDialog(
        this, // the parent that the dialog blocks
        message, // the dialog message array
        "NetMatch", // 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
    );
    if(val != 1) {
      if(s.isSelected()) {
        if(!isSaved)
          SaveAs();
        else
          saveNetwork(queryName);
        isModif = false;
        setTitle(title + " - " + getShortName(queryName));
      }
      if(recipient != null) {
        try {
          GraphLoader gg = loadGraphFromQTool(canvas.getNodeLayerReference(), canvas.getEdgeLayerReference());
          recipient.addQueryStructure(getNetworkName(queryName), gg);
        }
        catch(Exception ex) {
          System.err.println("Unable to create NetMatch network!");
        }
      }
      if(c1.isSelected()) {
        recipient.deattachRecipient();
        setVisible(false);
        dispose();
      }
      else if(c2.isSelected()) {
        queryName = "";
        setTitle(title + " - new query");
        isModif = false;
        Network.clean(canvas.getNodeLayerReference(), canvas.getEdgeLayerReference());
        updateStatus();
      }
    }
  }

  // inner class for palette button's actions
  class BListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JButton bt = (JButton) e.getSource();
      if(bt.getName().equals("ZoomIn")) {
        Point2D center = canvas.getCamera().getViewBounds().getCenter2D();
        canvas.getCamera().scaleViewAboutPoint(2.0, center.getX(), center.getY());
        return;
      }
      if(bt.getName().equals("ZoomOut")) {
        Point2D center = canvas.getCamera().getViewBounds().getCenter2D();
        canvas.getCamera().scaleViewAboutPoint(0.5, center.getX(), center.getY());
        return;
      }
      for(int i = 0;i < pButtons.length;i++) {
        pButtons[i].setBorder(originalBorder);
        if(pButtons[i] == bt) {
          bt.setBorder(selBorder);
          setupMode(i);
        }
      }
      for(int i = 0;i < sButtons.length;i++) {
        sButtons[i].setBorder(originalBorder);
        if(sButtons[i] == bt) {
          bt.setBorder(selBorder);
          canvas.setupStructure(i);
        }
      }
    }
  }// BListener
}
