package mucs;

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class mucs implements ActionListener {

  /* This line has to be added to every class that wants to communicate to MuPAD!!! */
  public native static String calcMuPAD(String query);

  boolean _debug = false;

  JFrame basiclayer = null;
  Object returnObject = null;
  Object triggerObject = null;
  Object callbackTriggerObject = null;
  Object callbackSourceObject = null;
  Object callbackTargetObject = null;
  private int width=-1;
  private int  height=-1;
  private boolean resizeFrame = false;
  private boolean canceled;


  public mucs(String title) {
    mupFrame(title);
  }

  public mucs() {
    mupFrame("MuPAD Unit Construction System (MUCS)");
  }

  private void mupFrame(String title) {
    this.basiclayer = new JFrame(title);
    this.basiclayer.getContentPane().setLayout(new BorderLayout());
    this.basiclayer.addWindowListener(new WindowAdapter(){
            public void windowClosing(WindowEvent e) {
                basiclayer.setVisible(false);
                canceled = true;
                setDoWait(false);
                //basiclayer.dispose();
            }
        });
  }

  /**
   * where has to be 0-4 (NORTH, SOUTH, EAST, WEST, CENTER)
   */
  public void addToContainer(Object toContainer, int where) {
    String layout;
    System.out.println("Trying to use "+ toContainer.getClass().toString() + " at " + where);
    if (toContainer instanceof Component) {
      switch (where) {
      	case 0 : layout = BorderLayout.NORTH; break;
        case 1 : layout = BorderLayout.SOUTH; break;
        case 2 : layout = BorderLayout.EAST; break;
        case 3 : layout = BorderLayout.WEST; break;
        case 4 : layout = BorderLayout.CENTER; break;
        default : layout = BorderLayout.CENTER;
      }
      this.basiclayer.getContentPane().add((Component)toContainer, layout);
      System.out.println("Added " + toContainer.getClass().toString() + " at " + layout);
    } else {
      JOptionPane.showMessageDialog(basiclayer, "Wrong object was stated for addToContainer", "Error", JOptionPane.ERROR_MESSAGE);
    }
  }

  public void setFrameSize(int width, int height) {
    this.resizeFrame = true;
    this.width = width;
    this.height = height;
    System.out.println("Changed size to (" + width + ":" + height +")");
  }

  /**
   * only one object is allowed to actually make a return to Windows possible.
   * (Maybe later on it could be a list...)
   */
  public void actionPerformed(ActionEvent e) {
    System.out.println("1." + e.getSource().getClass().toString());
    System.out.println("2." + e.getActionCommand());
    if (e.getSource().equals(triggerObject)) {
        setDoWait(false);
    }

    /*
    if (e.getActionCommand().equals(triggerObject)) {
      setDoWait(false);
    } else if (e.getActionCommand().equals("JButton")) {
      // Usually not neccessary
      if (callbackTargetObject != null) {
        if (returnObject instanceof JTextField) {
          if (callbackSourceObject instanceof JTextField) {
            ((JTextField)callbackTargetObject).setText(calcMuPAD( ((JTextField)callbackSourceObject).getText() ));
          } else if (callbackSourceObject instanceof JTextArea) {
             ((JTextField)callbackTargetObject).setText(calcMuPAD( ((JTextArea)callbackSourceObject).getText() ));
          }
        }
        else if (returnObject instanceof JTextArea) {
          ((JTextArea)callbackTargetObject).setText(calcMuPAD("Haki"));
        } else {
          JOptionPane.showMessageDialog(basiclayer, "Wrong object was stated for callback", "Error", JOptionPane.ERROR_MESSAGE);
        }

      }
    }
    */
  }

  /**
   * Here the object that defines the return is stated.
   * (Maybe later on it could be a list...)
   */
  public void setReturnObject(Object returnObject) {
    if ((returnObject instanceof JTextField) || (returnObject instanceof JTextArea))
    {
      this.returnObject = returnObject;
      System.out.println("Added " + returnObject.getClass().toString() + " as returnObject.");
    }
    else
    {
      System.out.println("Sorry, but so far only JTextField and JTextArea are allowed.");
    }
  }

  /**
   * Here the object that defines the return is stated.
   * (Maybe later on it could be a list...)
   */
  public void setTriggerObject(Object triggerObject) {
    if (triggerObject instanceof JButton) {
      this.triggerObject = triggerObject;
      ((JButton)(this.triggerObject)).addActionListener(this);
      System.out.println("Added " + triggerObject.getClass().toString() + " as triggerObject.");
    }
    else
    {
      System.out.println("Sorry, but so far only JButtons are allowed.");
    }
  }

  /**
   * Here the object that triggers the callback is stated.
   * So far only a JButton is allowed
   * @param callbackObject
   * @param callbackReturnObject
   * (Maybe later on it could be a list...)
   */
  public void addCallbackObject(Object callbackTriggerObject, Object callbackSourceObject, Object callbackReturnObject) {
    if (callbackTriggerObject instanceof JButton) {
      this.callbackTriggerObject = callbackTriggerObject;
      ((JButton)this.callbackTriggerObject).setActionCommand("JButton");
      this.callbackSourceObject = callbackSourceObject;
    } else {
      JOptionPane.showMessageDialog(basiclayer, "Can not create callback mechanism", "Error", JOptionPane.ERROR_MESSAGE);
    }
  }


  public void waitForTermination()
  {
    while (this.doWait) {
      synchronized (this.waitMutex) {
        try {
          this.waitMutex.wait();
        } catch (InterruptedException e) {
            System.out.println("There are some serious errors...");
          }
      }
    }
  }

  public String showMucs() {
    canceled = false;

    Dimension screenSize=Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize=new Dimension((int)(screenSize.width/2),(int)(screenSize.height/2));
    int x=(int)(frameSize.width/2);
    int y=(int)(frameSize.height/3);
    basiclayer.setBounds(x,y,frameSize.width,frameSize.height);

    if (resizeFrame) {
      basiclayer.setSize(this.width, this.height);
    } else {
      basiclayer.pack();
    }
    //this.basiclayer.validate();
    basiclayer.setVisible(true);
    basiclayer.toFront();
    doWait = true;
    waitForTermination();

    // Now everything is okay and we close the window...
    basiclayer.setVisible(false);

    if (!canceled) {
      if (returnObject instanceof JTextField) {
        return ((JTextField)returnObject).getText();
      }
      else if (returnObject instanceof JTextArea) {
        return ((JTextArea)returnObject).getText();
      } else {
        return "No return object defined.";
      }
    }
    return "Canceled by user.";
  }

  public void setDoWait(boolean state) {
    synchronized(this.waitMutex) {
      System.out.println("Change state to " + state);
      this.doWait = state;
      this.waitMutex.notify();
    }
  }

  private boolean doWait;
  private Object waitMutex = new Object();

}