import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;

/**
*   <code>LoadGraph</code> loada a graph from a file.
*
*   @author Gideon Schwarz (mail@gideon-schwarz.de)
*   @version 24.02.2004 
*/
public class LoadGraph{

    /** Position in 2-dimensional space for every node. */
    private float[][] pos = null;
    /** Similarity (edge weight) for every pair of nodes. */
    private float[][] sim = null;
    /** Similarity (edge weight) for evere node.*/
    private float[][] sim2 = null;
    /** Name of the nodes.*/
    private String[] names = null;
    
    /** 
    *   Finds the name of the file with data of a graph.
    *   Uses a interactive dialog to find the file.
    *   @param fr       frame is used for interactive input
    */
    private static String getFileName(Frame fr){
        String fileName= null;
        FileDialog dlg = new FileDialog(fr, "Datei öffnen", FileDialog.LOAD);
        dlg.setFile("*.rsf");
        dlg.show();
        String dn = dlg.getFile();
        if(dn != null) fileName = dlg.getDirectory() + dn;
        return fileName;
    }
    
    /**
    *   Returns the length for the arrays <code>sim</code> and <code>pos</code>.
    *   @param fileName     name of file, with path, where graph is saved.
    */
    private static int arrayLength(String fileName) {
        int length = 0;
        boolean eof = false;
        try {
            FileReader file = new FileReader(fileName);
            BufferedReader buff = new BufferedReader(file);
            while (!eof){
                String line = buff.readLine();
                if (line == null){
                    eof = true;
                } else {
                    StringTokenizer str = new StringTokenizer(line);
                    String test = str.nextToken();
                    if (test.equals("NODE")) {
                        length++;
                    } else {
                        if (!test.equals("EDGE")){
                            //Error message 1: error in file
                            JOptionPane.showMessageDialog(null,"Error in file! " ,"Error 1", JOptionPane.ERROR_MESSAGE);
                            return 0;
                        }
                    }
                }
            }
            buff.close();
        } catch(IOException e) {
            //Error message 2: file not found
            JOptionPane.showMessageDialog(null,"File not found!","Error 2", JOptionPane.ERROR_MESSAGE);
            return 0;
        }
        return length;
    }


    /** 
    *   Enters a new information in <code>sim</code> with the data read from file.
    *   Gives a Errormessage if start node or end node or both not allready read.
    *   @param i            integer save number of nodes, which allready read
    *   @param startName    name of the start node of the edge, read from file
    *   @param endName      name of the end node of the edge, read from file
    */
    private void createEdge(int i, String startName, String endName){
        int startIndex = i;
        int endIndex = i;
        for(int k = 0;k < i;k++){
            if(names[k].equals(startName) && names[k].equals(endName)){
                startIndex = k;
                endIndex = k;
            } else {
                if(names[k].equals(startName)){
                    startIndex = k;
                } else {
                    if(names[k].equals(endName)){
                        endIndex = k;
                    }
                }
            }
        }
        if (startIndex != i && endIndex != i) {
            //start node and end node exist => enters information in sim.
            if(startIndex != endIndex){
                sim[startIndex][endIndex] = 1.0f;
                sim[endIndex][startIndex] = 1.0f;
            } else {
                sim[startIndex][endIndex] = 0.0f;
            }
            return;
        } else {
            if(startIndex == i && endIndex == i){
                //Error message 1: error in file
                JOptionPane.showMessageDialog(null, "Startnode and Endnode not found line!","Error 1", JOptionPane.ERROR_MESSAGE);
                return;
            } else {
                if (endIndex == i) {
                    //Error message 1: error in file
                    JOptionPane.showMessageDialog(null, "Endnode not found line!","Error 1", JOptionPane.ERROR_MESSAGE);
                    return;
                } else {
                    //Error message 1: error in file
                    JOptionPane.showMessageDialog(null, "Startnode not found line!","Error 1", JOptionPane.ERROR_MESSAGE);
                    return;
                }
            }
        }
    }
    
    /**
    *   Create similitary Matrix (Edge Weight) for every Node.
    *   sim2 is necessary for CalculatLayout.
    */
    private void modifySimilarityMatrix(){
        sim2 = new float[names.length][];
        for(int i = 0; i < names.length; i++){
            Vector temp = new Vector();
            for(int j = 0; j < names.length;j++){
                if(sim[i][j]==1.0f){
                    temp.add(new Integer(j));
                }
            }
            float[] help = new float[temp.size()];
            for(int j = 0; j < help.length; j++){
                Integer in = (Integer)temp.elementAt(j);
                help[j] = (float)in.intValue();
            }
            sim2[i] = help;
        }
    }


    /**
    *   Loads a graph from a file. 
    */
    public Graph load(){
        Frame little = new Frame();
        String fileName = LoadGraph.getFileName(little);
        int i = 0;
        // no file => return to menue
        if (fileName == null) {
            return null;
        }
        int length = LoadGraph.arrayLength(fileName);
        if (length == 0){
            return null;
        }
        pos = new float[length][3];
        sim = new float[length][length];
        names = new String[length];
        boolean eof = false;
        try {
            FileReader file = new FileReader(fileName);
            BufferedReader buff = new BufferedReader(file);
            //read the data of nodes and edges from the graph
            while (!eof){
                String line = buff.readLine();
                if (line == null){
                    eof = true;
                } else {
                    StringTokenizer str = new StringTokenizer(line);
                    String test = str.nextToken();
                    if(test.equals("NODE")){
                        names[i] = str.nextToken();
                        //for 3 dimensinal change for-loop
                        for(int k = 0;k<2;k++){
                            pos[i][k] = Float.parseFloat(str.nextToken().trim());
                        }
                        i++;
                    } else {
                        createEdge(i, str.nextToken(), str.nextToken());
                    }
                }
            }
            buff.close();
        } catch(IOException e) {
            // Error message 2: File not found
            JOptionPane.showMessageDialog(null,"File not found","Error 2", JOptionPane.ERROR_MESSAGE);
            return null;
        }
        modifySimilarityMatrix();
        Graph graph = new Graph(sim, pos, names, fileName, sim2);
        return graph;
    }
}
