package guiDomain;
import sharedInterfaces.*;
import sharedObjects.*;

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.text.*;


public class GuiFacade extends JFrame implements GuiFacadeInterface
{
    private DataServerFacadeInterface database;
    private String experiment; // experiment name
    private String shortFileAddress; // for retrieving plot data
    private double[] xVals=null,yVals=null; // plot data arrays
    private String xUnits=null,yUnits=null;
    private int xLen=0,yLen=0;
    private boolean isGraphData=false; //Is there data to plot?
    private boolean isDataError=false; //Flags unexpected data from MDSPlus

    // Components for the menu
    private JMenuBar menuBar;

    private JMenu fileMenu;
    private JMenuItem fileConnectItem;
    private JMenuItem fileOpenItem;
    private JMenuItem fileExitItem;

    // Components for the main window
    private AbstractGraphicsFacade graph;
    private JLabel description;

    // Dialogs
    private OpenDialog openD;
    private ConnectDialog connectD;

    // file tree
    private JTree tree;

    public GuiFacade()
    {
        // Construct the menu
        menuBar = new JMenuBar();
        setJMenuBar( menuBar );

        fileMenu = new JMenu( "File" );
        menuBar.add( fileMenu );

        fileConnectItem = new JMenuItem( new ConnectAction() );
        fileMenu.add( fileConnectItem );

        fileOpenItem = new JMenuItem( new OpenAction() );
        fileMenu.add( fileOpenItem );

        fileMenu.addSeparator();

        fileExitItem = new JMenuItem( new ExitAction() );
        fileMenu.add( fileExitItem );

        description = new JLabel();

        connectD = new ConnectDialog(this, "Enter Connection Details", true);
        openD = new OpenDialog(this, "Enter experiment and shot", true);
    }

    public void initialise(DataServerFacadeInterface _source,
			   AbstractGraphicsFacade _graph)
    {
        database = _source;
	graph = _graph;

        tree=new JTree(new DefaultTreeModel(new DefaultMutableTreeNode("No experiment open")));
        tree.addTreeSelectionListener( new DataTreeSelectionListener() );
        JScrollPane treeScroll = new JScrollPane( tree );
        treeScroll.setMinimumSize( new Dimension( 150, 10 ) );

        JSplitPane rightPane = new JSplitPane( JSplitPane.VERTICAL_SPLIT,
                        new JScrollPane( description ),graph);
        JSplitPane mainPane = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT,
                        treeScroll, rightPane );
        getContentPane().add( mainPane, "Center" );
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle( "No experiment opened" );
        this.setBounds( 200, 200, 800, 400 );
        this.setVisible(true);
    }

    public void graphPointUpdated(double x, double y, boolean inRange)
    {
	if (inRange)
	{
	    DecimalFormat decForm = new DecimalFormat("0.##E0");
            String xString = decForm.format(x);
            String yString = decForm.format(y);
            description.setText(" x= " + xString + "  y= " + yString);
        }
	else description.setText(" ");
    }


    public void getPlotData()
    {
        MDSDescriptor result1=null,result2=null,result3=null,result4=null;
        String expression1="",expression2="",expression3="",expression4="";

        try
        {
            expression1="units_of(" + shortFileAddress + ")"; // Y title
            result1 = database.evaluate( expression1 );

            expression2= shortFileAddress; //Y values
            result2 = database.evaluate( expression2 );

            expression3="units_of(dim_of(" + shortFileAddress +"))"; // X title
            result3 = database.evaluate( expression3 );

            expression4="dim_of(" + shortFileAddress + ")"; // X values
            result4 = database.evaluate( expression4 );
        }
        catch ( IOException e )
        {
            System.out.println( "Failed to communicate with server: "
              + e.getMessage() );
            System.exit(-1);
        }

        // check x and y axis label types
        if ( (result1.getDtype() != result1.DTYPE_CSTRING) ||
            (result3.getDtype() != result3.DTYPE_CSTRING))
        {
            System.out.println(
                "Error: String descriptor not returned for one of:");
            System.out.println("        " + expression1 + " and " + expression3);
            System.out.println(
                "(should never happen if MDSPlus database is correct)");
            isDataError = true;
        }

        // get x and y labels
        yUnits = result1.getCstringData();
        xUnits = result3.getCstringData();

        // check xVals and yVals types
        // - double => legal data
        // - strings => some data does not exist; No y data => no data
        if ( (result2.getDtype() != result2.DTYPE_DOUBLE))
        {
            System.out.println("Error: Double descriptor not returned for:");
            System.out.println(" yVals:       " + expression2);
            isDataError = true;
        }
        if ( (result4.getDtype() != result4.DTYPE_CSTRING) &&
            (result4.getDtype() != result4.DTYPE_DOUBLE))
        {
            System.out.println(
                "Error: Double or String descriptor not returned for:");
            System.out.println(" xVals:       " + expression4);
            isDataError = true;
        }

        if ( (!isDataError) && (result2.getDtype() == result2.DTYPE_DOUBLE))
        { // legal y data exists
            yLen = result2.getDoubleData().length;
            if (yLen < 2)
            {
                System.out.println(
                    "Error: " + expression2 + " is not an array");
                isDataError = true;
            }
            else
            {

                boolean isXData = false;
                if (result4.getDtype() == result4.DTYPE_DOUBLE)
                {
                    isXData = true;
                    xLen = result4.getDoubleData().length;
                }
                else
                {
                    xLen = yLen;
                }

                if (xLen != yLen)
                {
                    System.out.println("Warning: xLen not yLen in data");
                    System.out.println("xLen = " + xLen + " yLen= " + yLen);
                    System.out.println("(xData will be ignored for plot)");
                    xLen = yLen;
                    isXData = false;
                }

                yVals = new double[yLen];
                xVals = new double[yLen];

                for (int i = 0; i < yLen; i++)
                {
                    yVals[i] = result2.getDoubleDataElement(i);
                }

                for (int i = 0; i < yLen; i++)
                {
                    if (isXData)
                    {
                        xVals[i] = result4.getDoubleDataElement(i);
                    }
                    else
                    {
                        xVals[i] = i;
                    }
                }
                isGraphData = true;
            }
	}
    }


    // Private Inner Classes
    private class ExitAction extends AbstractAction
    {
        public ExitAction() {   super( "Exit" );}

        public void actionPerformed( ActionEvent event )
        {    System.exit( 0 );
        }
    }

    private class ConnectAction extends AbstractAction
    {
        public ConnectAction(){    super( "Connect ..." );}

        public void actionPerformed( ActionEvent event )
        {
            if (connectD.showDialog())
            {
                String server = connectD.getServer();
                try
                {
                    if ( database.isConnected() )
                     {
                         if(database.isOpen())
                         {
                             tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("No experiment open")));
                             GuiFacade.this.graph.resetGraphData();
                             description.setText(" ");
                             database.close();
                         }
                         database.disconnect();
                    }
                    database.connect( server );
                    String newTitle = "Connection made. No experiment opened";
                    GuiFacade.this.setTitle(newTitle);
                    }
                    catch (IOException e)
                    {
                        JOptionPane.showMessageDialog(GuiFacade.this,
                                 "Failed to connect to server",
                                 "Error", JOptionPane.ERROR_MESSAGE );
                      }
                 }
          }
    }

    private class OpenAction extends AbstractAction
    {
        public OpenAction(){ super( "Open ..." );}

        public void actionPerformed( ActionEvent event )
        {    if (openD.showDialog())
             {
                 experiment = openD.getExperiment();
                 int shot = openD.getShot();
                 try
                 {
                     if ( database.isOpen() )
                     {
                        tree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode("No experiment open")));
                        GuiFacade.this.graph.resetGraphData();
                        description.setText(" ");
                        database.close();
                     }
                      database.open( experiment, shot );
                      database.constructTree(tree);
                      String newTitle = " Opened experiment: "
                                   + experiment + " shot: " + shot;
                      GuiFacade.this.setTitle(newTitle);
                 }
                 catch (IOException e)
                 {
                     JOptionPane.showMessageDialog(GuiFacade.this,
                                                   "Failed to open " +
                                                   "experiment " + experiment +", shot " +shot + ": " +
                                                   e.getMessage(), "Error",
                                                   JOptionPane.ERROR_MESSAGE);
                 }
             }
         }
    }

    /**    Plots the graph and displays the path of the selected tree node */
    private class DataTreeSelectionListener implements TreeSelectionListener
    {
        public void valueChanged( TreeSelectionEvent e )
        {   // Get new data and plot it
            Object path[];
            String stringPath="";
            path = e.getPath().getPath();
	    shortFileAddress="";
            for ( int i = 1; i < path.length; i ++ )
            {
	        shortFileAddress = shortFileAddress + path[i].toString();
            }
	    stringPath = stringPath + shortFileAddress;
	    if (!shortFileAddress.equals("")) // (Do not plot or display the "TOP" node)
	    {
		isGraphData = false;
		isDataError = false;
                GuiFacade.this.getPlotData();
	        GuiFacade.this.graph.setGraphData
                   (xVals,yVals,xUnits,yUnits,shortFileAddress,isGraphData,isDataError);
                GuiFacade.this.graph.repaint(); //(prints a message if no data)
	    }
        }
    }


}
