package textServerDomain;
import sharedInterfaces.*;
import sharedDataInterfaces.*;

import java.io.*;
import javax.swing.*;
import javax.swing.tree.*;
import java.util.*;


//Read data saved in text form. The expected format is formed of two colums:
//The first one contains the X values;
//The second one contains the Y values;
//Method open receives a path: if the path refers to a text file containing data
//Teh experiment contains only that data item. If the path refers to a directory,
//the contained directory subtree is displayed.
public class TextDataServer implements DataServerFacadeInterface
{
    TreeModel directoryTree = null;
    String rootPath;
    String xTitle = "", yTitle = "";
    String separator = System.getProperty("file.separator");

    //No special action required for connection
    public void connect(String serverAddrCPort) throws IOException
    {}

    //No special action required for disconnection
    public void disconnect() throws IOException
    {}

    //open the directory tree starting from the passed path.
    //The shot argument is not used.
    public void open(String path, int shot) throws IOException
    {
        rootPath = path;
        DefaultMutableTreeNode root = new DefaultMutableTreeNode(path);
        directoryTree = new DefaultTreeModel(root);
        try
        {
            File rootFile = new File(path);
            if(!rootFile.exists())
                throw new IOException("Cannot find file " + path);
            if (rootFile.isDirectory())
            {
                traverseDirectory(path, rootFile, root);
            }
        }
        catch (Exception exc)
        {
            //System.err.println("Error traversing trees: " + exc);
            throw new IOException("TextDataServer skipped");
        }
    }

    private void traverseDirectory(String currDirName, File currDirectory,
                                   DefaultMutableTreeNode currRoot) throws
        IOException
    {
        String fileNames[] = currDirectory.list();
        for (int i = 0; i < fileNames.length; i++)
        {
	    if (!fileNames[i].equals(".svn")) // ignore subversion tags
            {   DefaultMutableTreeNode currNode = new DefaultMutableTreeNode(" "+fileNames[i]);
                currRoot.add(currNode);
                File currFile = new File(currDirName + separator + fileNames[i]);
                if (currFile.isDirectory())
                 traverseDirectory(currDirName + separator + fileNames[i], currFile, currNode);
	    }
        }
    }

    //No special action required when closing
    public void close() throws IOException
    {}

    public void constructTree(JTree tree) throws IOException
    {
        tree.setModel(directoryTree);
    }

    public boolean isConnected()
    {
        //Always implicitly connected
        return true;
    }

    public boolean isOpen()
    {
        return directoryTree != null;
    }

    public String getExperiment()
    {
        return rootPath;
    }

//Shot is useless here
    public int getShot()
    {
        return 0;
    }

    //Retrieves data associated with the passed path. It needs to convert path to a
    //relatine file name, appending it to the root path name and reading text data
    //If not numeric, the first element of each row in interpreted as the name of the corresponding data set
    public GraphDataInterface getPlotData(String path)
    {
        //The elements of the path are separated by a blank character
        StringTokenizer st = new StringTokenizer(path, " ");
        String fileName = rootPath;
        GraphData graphData = new GraphData();
        while (st.hasMoreTokens())
        {
            fileName = fileName + separator + st.nextToken();
        }
        try
        {
            BufferedReader br = new BufferedReader(new FileReader(fileName));
            Vector linesV = new Vector();
            String currLine;
//Read lines and store them in a vector
            boolean firstLine = true;

            while (true)
            {
                currLine = br.readLine();
                if (currLine == null)break;
                st = new StringTokenizer(currLine, " \t");
                //Check whether the line contains useful elements (at least contains two strings if the first line, or two numbers )
                if (st.countTokens() < 2)continue; //No useful line without two elements
                if (firstLine && !lineContainsNumbers(currLine)) //If it is the first useful line and dooes not contain numbers
                {
                    getTitles(currLine); //it is assumed to be containing X and Y titles
                    continue;
                }
                if (lineContainsNumbers(currLine))
                    linesV.addElement(currLine);
                firstLine = false;
            }
            br.close();
            //If no useful line found, return empty GraphData
            if (linesV.size() > 0)
            {
                double xArr[] = new double[linesV.size()];
                double yArr[] = new double[linesV.size()];
                for (int i = 0; i < linesV.size(); i++)
                {
                    st = new StringTokenizer( (String) linesV.
                        elementAt(i), " \t");
                    xArr[i] = Double.parseDouble(st.nextToken());
                    yArr[i] = Double.parseDouble(st.nextToken());
                }
                graphData.initialise(xArr, yArr, xTitle, yTitle, "", 0, false);
            }
        }
        catch (Exception exc)
        {
            System.err.println("Error reading text file: " + exc);

        }
        return graphData;
    }

    private boolean lineContainsNumbers(String line)
    {
        try
        {
            StringTokenizer st = new StringTokenizer(line, " \t");
            Double.parseDouble(st.nextToken());
            Double.parseDouble(st.nextToken());
            return true;
        }
        catch (Exception exc)
        {
            return false;
        }
    }

    private void getTitles(String line)
    {
        StringTokenizer st = new StringTokenizer(line, " \t");
        xTitle = st.nextToken();
        yTitle = st.nextToken();
    }
}
