/*
 * DataImportPanel.java
 *
 * Created on January 10, 2005, 11:10 AM
 */

package DDMT.core;

import java.io.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.DefaultListModel;
import java.util.Vector;
import java.util.Random;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import DDMT.Nodes.Node;
import DDMT.Nodes.Neighbor;
//import weka.core.Instance;
/**
 *
 * @author  jk3 jButton17
 */
public class DataImportPanel extends DDMT.core.DefaultPanel {
    
    //Model for the attribute - partitioning status model
    DefaultListModel attributeModel;
    
    //Model which types of nodes are partitioned
    DefaultListModel partitionTypesModel;
    
    //Model for the heterogeneous column distribution
    DefaultListModel heteroDistributionModel;
    
    //Pattern for a node definition
    //Node Number, Network Location, Data Location, Node Type, X-value, Y-value, Neighbor1, Neighbor1 delay, Neighbor2, ...
    private Pattern nodePattern = Pattern.compile("\\d+\\s\\S+\\s\\S+\\s\\S+\\s\\d+\\s\\d+\\s[\\d+\\s\\d+\\p{Punct}\\d+\\s]*");
    private Matcher nodeMatcher;
    
    //Define patterns for integers, strings, doubles, first string, and last string
    private Pattern integerP = Pattern.compile("\\d+");
    private Pattern doubleP = Pattern.compile("\\d+\\p{Punct}\\d+");
    private Pattern stringP = Pattern.compile("\\S+\\s");
    private Pattern alphaStringP = Pattern.compile("[a-zA-Z]\\S*");
    private Pattern neighborP = Pattern.compile("\\s\\d+\\s\\d+\\p{Punct}\\d+");
    private Pattern fileP = Pattern.compile("\\S+\\s\\S+");
    private Pattern firstP = Pattern.compile("\\A\\S+");
    private Pattern lastP = Pattern.compile("\\S+\\Z");
    private Pattern middleP = Pattern.compile("\\s\\S+\\s");
    private Pattern relationP = Pattern.compile("\\A@[Rr][Ee][Ll][Aa][Tt][Ii][Oo][Nn]");
    private Pattern attributeTypeP = Pattern.compile("\\A@[Aa][Tt][Tt][Rr][Ii][Bb][Uu][Tt][Ee]\\s+\\S+\\s+\\S+");
    private Pattern attributeP = Pattern.compile("\\[S^,]*");
    private Pattern heteroDistP = Pattern.compile("\\s(\\S+)");
    private Matcher heteroDistM;
    private Matcher attributeM;
    private Matcher attributeTypeM;
    private Matcher relationM;
    private Matcher fileM;
    private Matcher firstM;
    private Matcher lastM;
    private Matcher middleM;
    private Matcher integerM;
    private Matcher doubleM;
    private Matcher stringM;
    private Matcher alphaStringM;
    private Matcher neighborM;
    
    //Data file
    File dataFile = null;
    boolean dataRead = false;
    
    //Prob. vector
    double[] probVector;
    
    //Attribute names
    private Vector attributeNames;
    
    //The number of tuples that are in the data file
    private int numTuples;
    
    //the actual tuples( in list form)
    private String[] tuples;
    
    //The actual tuples (sorted by column)
    private String[][] columnTuples;
    
    //The different types of nodes known
    private Vector types;
    
    //the nodes that are to be included in the distribution.  This is a subset of all the nodes. headerInfo
    private Vector nodeList;
    
    //the node types - class name array
    String[][] nodeTypes;
    
    /** Creates new form DataImportPanel */
    public DataImportPanel(DDMT.core.MainPanel.ControlClass cClass) {
        initComponents();
        
        controlClass = cClass;
        
        //Set the name of this panel for the main window's tab
        this.setName("Data Import");
        
        //Set up the button groups
        buttonGroup1.add(jRadioButton1);
        buttonGroup1.add(jRadioButton2);
        buttonGroup2.add(jRadioButton3);
        buttonGroup2.add(jRadioButton4);
    }
    
    /**
     *Method for distributing all the settings that each node should know
     */
     private void distributeSettings()
     {
         //Load the agent types
         File file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\NodeClassMatching.txt" );
         nodeTypes = this.readFile(file);
         System.out.println("read in the node types");
         
     }
     
    /**
     *Method to load the nodes into the system
     */
    private void loadNodes() throws Exception
    {
        //Open the Nodes.txt file
        File nodesFile = null;

        nodesFile = new File("Files\\Projects\\" + controlClass.getProjectName() + "\\nodes.txt");
        
        try{
            FileReader fileReader = new FileReader(nodesFile);
            BufferedReader bReader = new BufferedReader(fileReader);
            //Read the number of nodes

            String line = bReader.readLine();
            if( line == null )
            {
                controlClass.showError("Agent Types: Error: Could not read file "+nodesFile.getPath()+".");
                throw new IOException();
            }
            controlClass.nodes = new Node[Integer.parseInt(line)];
            line = bReader.readLine();
            
            //Loop for each line read.
            int i = 0;
            while( line != null )
            {
                nodeMatcher = nodePattern.matcher(line);
                if( nodeMatcher.matches() )
                {
                    //Set up the matchers
                    integerM = integerP.matcher(line);
                    doubleM = doubleP.matcher(line);
                    alphaStringM = alphaStringP.matcher(line);
                    neighborM = neighborP.matcher(line);
                    
                    //Read in the node.
                    Node node = new Node();
                    integerM.find();
                    node.setNumber(Integer.parseInt(integerM.group()));
                    alphaStringM.find();
                    node.setNetworkLocation(alphaStringM.group());
                    alphaStringM.find();
                    String dataLocation = new String(alphaStringM.group());
                    //System.out.println()
                    if( dataLocation.equals("None"))
                    {
                        node.setDataLocation("Files\\Projects\\"+controlClass.getProjectName()+"\\Data\\data"+node.getNumber()+".txt");
                    }else{
                        node.setDataLocation(dataLocation);
                    }
                    alphaStringM.find();
                    node.setType(alphaStringM.group());
                    integerM.find();
                    node.setX(Integer.parseInt(integerM.group()));
                    integerM.find();
                    node.setY(Integer.parseInt(integerM.group()));

                    //Load the neighbors
                    while( neighborM.find() )
                    {
                        String neighbor = new String( neighborM.group() );
                        integerM = integerP.matcher(neighbor);
                        doubleM = doubleP.matcher(neighbor);
                        Neighbor nodeNeighbor = new Neighbor();
                        integerM.find();
                        nodeNeighbor.setNumber(Integer.parseInt(integerM.group()));
                        doubleM.find();
                        nodeNeighbor.setDelay(Double.parseDouble(doubleM.group()));
                        node.addNeighbor(nodeNeighbor);       
                    }
                    //Add node to nodes list
                    controlClass.nodes[i] = node;
            
                    i++;
                }
                line = bReader.readLine();
            }
            
            //Close the files
            bReader.close();
            fileReader.close();
        }catch(IOException ex)
        {
            controlClass.showError("Data Import: Error: Could not read file "+nodesFile.getPath());
        }
    }
    
    /**
     *Method takes two arrays of strings and a file and reads the file as a 
     *matched pair of data items, which it puts into the arrays.
     */
    private String[][] readFile( File file )
    {
        String[][] array = null;
         try{   
                //Read from the file
                file.createNewFile();
                FileReader reader = new FileReader(file);
                BufferedReader bReader = new BufferedReader(reader);
                String line = bReader.readLine();
                
                //First line contains the number of pairs
                array = new String[2][Integer.parseInt(line)];
                
                //Read in all the pairs
                line = bReader.readLine();
                int j = 0;
                while(line != null )
                {
                    fileM = fileP.matcher(line);
                    if( fileM.matches() )
                    {
                        //Set up matchers
                        firstM = firstP.matcher(line);
                        lastM = lastP.matcher(line);
                        
                        //Find the pair
                        firstM.find();
                        array[0][j] = firstM.group();
                        lastM.find();
                        array[1][j] = lastM.group();
                    }
                    line = bReader.readLine();
                    j++;
                }
                
                //Close the readers
                reader.close();
                bReader.close();
                
            }catch(Exception ex)
            {
                controlClass.showError("Agent Types: Error: Unable to read file "+file.getPath()+". Delete the file and try again or fix the file.");
            }
        
        return array;
    }
    
    /**
     *Method to display which types should have data
     */
    public void displayPartitionTypes()
    {
        //Control boolean
        boolean newList = false;
        
        //make sure that a project has been selected
        if( controlClass.getProjectName() ==  null)
        {
            controlClass.showError("Data Import: Error: No project selected!");
            return;
        }
        
        //Make sure that node data exists
        if( controlClass.nodes == null)
        {
            controlClass.showError("Data Import: Error: No topology information available!");
        }
        
        //See if a partitionTypes.txt file already exists
        File file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\partitionTypes.txt");
        if( file.exists() )
        {
            //Read the file
            String[][] elements = this.readFile(file);

            //Check it against the known node types
            file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\NodeClassMatching.txt");
            String[][] elements2 = this.readFile(file);

            partitionTypesModel = new DefaultListModel();
            for( int i = 0; i< elements[0].length; i++)
            {
                partitionTypesModel.addElement(new String[]{ elements[0][i],elements[1][i] });
            }
            jList2.setCellRenderer(new DoubleCellRenderer());
            jList2.setModel(partitionTypesModel);
        }else{
            
            try{
                //load the types of nodes form the node class matching file
                file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\NodeClassMatching.txt");
                String[][] elements = this.readFile(file);
                this.types = new Vector();
                for( int i = 0; i < elements[0].length; i++)
                {
                    boolean newOne = true;
                    for(int j = 0; j< types.size(); j++)
                    {
                        if(elements[0][i].equals( ((String)types.elementAt(j))))
                        {
                            newOne = false;
                        }
                    }
                    if(newOne)
                    {
                        types.add(elements[0][i]);
                    }
                }
                
                //set up the model
                partitionTypesModel = new DefaultListModel();
                for( int i = 0; i <types.size(); i++)
                {
                    partitionTypesModel.addElement(new String[]{(String)types.elementAt(i), "Partition"});
                }
                jList2.setCellRenderer(new DoubleCellRenderer());
                jList2.setModel(partitionTypesModel);
            }catch (Exception ex)
            {
                controlClass.showError("Data Import: Error: Couldn't load partition data.  Please re-save the Agent Types panel.");
                file.delete();
            }
        }
    }
    
    /**
     *Method to distribute the columns of centralized data to nodes
     *
     *The method used is as follows:
     *1.) The list of columns is randomized
     *2.) The column in the list is associated with a node, starting at the 
     *begining of the lists, in a sequential manner.
     *
     *Each node is guranteed to have ceiling[(number of columns)/(number of nodes)]
     *or floor[(number of columns)/(number of nodes)] columns associated with
     *it.  
     */
    private void distributeHetero()
    {
        //Throw an error if no data file has been selected
        if( dataRead == false)
        {
            controlClass.showError("Data Import: Error: No data file opened!");
            return;
        }
        
        //Load the node class matching
        this.distributeSettings();
        
        //Create a second list that contains only elements that should be randomized
        Vector randTypes = new Vector();
        for( int i = 0; i< attributeModel.size(); i++)
        {
            if( ((String[])attributeModel.elementAt(i))[1].equals( "Normal") )
            {
                randTypes.add(new String( ((String[])attributeModel.elementAt(i))[0]));
            }
        }
        
        //Randomize the list of columns
        int[] attributes = new int[attributeNames.size()];
        int length = 0;
        int columnsLeft = attributes.length;
        
        //Set up the list of items that are only normally partitioned
        for( int i = 0; i< attributeNames.size(); i++)
        {
            if( ((String[])attributeModel.elementAt(i))[1].equals( "Normal") )
            {
                attributes[length] = i;
                length++;
            }
        }
        
        //Randomize the list
        for( int m = 0; m < length; m++)
        {
            int j;
            int k = length;
            for (int i = 0; i < k-1; i++)
            {
                j = ((int)(((double)(k - i))*Math.random())) + i;
                int temp = attributes[i];
                attributes[i] = attributes[j];
                attributes[j] = temp;
            }
        }
        
        //Find the number of nodes that are to recieve data
        Vector temp = new Vector();
        int tempIndex = 0;
        
        //Loop for each node
        for( int i = 0; i< controlClass.nodes.length; i++)
        {
            //Loop for each node type that should be distributed
            for( int k = 0; k<this.partitionTypesModel.size(); k++)
            {
                //If this type should be partitioned...
                if( ((String)((Object[])partitionTypesModel.elementAt(k))[1]).equals( "Partition" ) )
                {
                
                    //loop for each node - class type matching
                    for( int j = 0; j< this.nodeTypes[0].length; j++)
                    {
                        //If this node matches the class type...
                        if( nodeTypes[1][j].equals( controlClass.nodes[i].getType())
                            && ((String)((Object[])partitionTypesModel.elementAt(k))[0]).equals( nodeTypes[0][j] ))
                        {
                            temp.addElement( new Integer( i ));
                            tempIndex++;
                        }
                    }
                }
            }
        }

        //If there are no nodes to partition to, then skip that step
        if( temp.size() == 0 )
        {
            //display the model nodes.txt
            heteroDistributionModel = new DefaultListModel();
            for( int i = 0; i < controlClass.nodes.length; i++)
            {
                String line1 = new String(controlClass.nodes[i].getNumber()+" (");
                for(int j = 0; j< nodeTypes[0].length; j++)
                {
                    if( nodeTypes[1][j].equals( controlClass.nodes[i].getType()) )
                    {
                        line1 = line1 + nodeTypes[0][j]+")";
                    }
                }
                String line2 = new String();
                heteroDistributionModel.addElement(new String[]{line1, line2});
            }
            jList3.setCellRenderer(new DoubleCellRenderer());
            jList3.setModel(heteroDistributionModel);
            
            return;
        }
        
        //Split it up between ONLY the nodes that are to recieve data 
        int numPerNode = length / temp.size() + 1;
        int nodeData[][] = new int[temp.size()][numPerNode];
        int currNode = 0;
        int currNum = -1;
        for( int i = 0; i < length; i++)
        {
            currNode = i % temp.size();
            if( currNode == 0 )
                currNum++;

            nodeData[currNode][currNum] = i;
        }
        
        //display the model nodes.txt
        heteroDistributionModel = new DefaultListModel();
        int tmpIndex = 0;
        for( int i = 0; i < controlClass.nodes.length; i++)
        {
            
            String line1 = new String(controlClass.nodes[i].getNumber()+" (");
            for(int j = 0; j< nodeTypes[0].length; j++)
            {

                if( nodeTypes[1][j].equals( controlClass.nodes[i].getType()) )
                {
                    line1 = line1 + nodeTypes[0][j]+")";
                }
            }
            
            String line2 = new String();
            
            //If this node is supposed to recieve columns...
            if( tmpIndex < temp.size() && ((Integer)temp.elementAt(tmpIndex)).intValue() == i)
            {
                for( int j = 0; j< numPerNode; j++)
                {
                    
                    //if the current attribute was assigned above...
                    if( (temp.size() *j)+tmpIndex < length )
                    {
                        //...then append it to the end
                        line2 = line2 +" "+ attributeNames.elementAt(attributes[nodeData[tmpIndex][j]]);
                    }
                }
                
                //Go to the next value that is supposed to recieve columns
                tmpIndex++;
            }
            //Error condition
            else if( tmpIndex < temp.size() && ((Integer)temp.elementAt(tmpIndex)).intValue() < i )
            {
                System.out.println("Error! "+((Integer)temp.elementAt(tmpIndex)).intValue() +" < "+i);
            }
            
            heteroDistributionModel.addElement(new String[]{line1, line2});
        }
        jList3.setCellRenderer(new DoubleCellRenderer());
        jList3.setModel(heteroDistributionModel);
    }
    
    /**
     *Method to save the columns to a file
     */
    private void saveColumns()
    {
        File file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\columns.txt");
        try{
            //Open the file writers
            FileWriter writer = new FileWriter(file);
            BufferedWriter bWriter = new BufferedWriter(writer);
            
            //output the number of lines
            bWriter.write(new String(""+attributeModel.getSize()));
            bWriter.newLine();
            
            //Write each line
            for( int i = 0; i< attributeModel.getSize(); i++)
            {
                String[] elements = (String[])attributeModel.getElementAt(i);
                bWriter.write(new String(elements[0] +" "+elements[1]));
                bWriter.newLine();
            }
            
            bWriter.close();
            writer.close();
        }catch(Exception ex)
        {
            controlClass.showError("Data Import: Error: Could not save file "+file.getPath());
            ex.printStackTrace();
        }
    }
    
    /**
     *Method to load the columns to the list
     */
    private void loadColumns()
    {
        //Make sure that a project has been selected
        if( controlClass.getProjectName() ==  null)
        {
            controlClass.showError("Data Import: Error: No project selected!");
            return;
        }
        
        //see if the file exists
        File file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\columns.txt");
        
        //If the file doesn't exist but the attributes do, then make a new list
        if( attributeNames != null && !file.exists())
        {
            try{
                //Loop for each attribute
                attributeModel = new DefaultListModel();
                for( int i = 0; i< attributeNames.size(); i++)
                {
                    attributeModel.addElement(new String[]{(String)attributeNames.elementAt(i), "Normal"});
                }
                jList1.setCellRenderer( new DoubleCellRenderer());
                jList1.setModel(attributeModel);
            }catch(Exception ex)
            {
                controlClass.showError("Data Import: Error: ");
                ex.printStackTrace();
            }
        }

        //If the file does exist and the attributes exist, then load it
        else{
            try{
                FileReader reader = new FileReader(file);
                BufferedReader bReader = new BufferedReader(reader);
                
                //Read in the file
                String[][] data  = this.readFile(file);
                
                //Loop for each attribute
                attributeModel = new DefaultListModel();
                for( int i = 0; i < data[0].length; i++)
                {
                    attributeModel.addElement(new String[]{data[0][i], data[1][i]});
                }
                jList1.setCellRenderer(new DoubleCellRenderer());
                jList1.setModel(attributeModel);
                bReader.close();
                reader.close();
            }catch(Exception ex)
            {
                controlClass.showError("Data Import: Error: Could not load file "+file.getPath());
                ex.printStackTrace();
            }
        }
    }
    
    /**
     *Method to save the current partition types
     */
    private void savePartitionTypes()
    {
        //exit if there is no project selected
        if( controlClass.getProjectName() == null)
        {
            controlClass.showError("Data Import: Error: No project selected!");
            return;
        }
        
        //Exit if no node information is available
        if( controlClass.nodes == null)
        {
            controlClass.showError("Data Import: Error: No topology information available!");
            return;
        }
        
        //Save the partition types
        File file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\partitionTypes.txt");
        try{
            FileWriter writer = new FileWriter(file);
            BufferedWriter bWriter = new BufferedWriter(writer);
            
            //write the number of elements
            bWriter.write(new String(""+this.partitionTypesModel.size()));
            bWriter.newLine();
            
            //Write each line
            for( int i = 0; i< partitionTypesModel.size(); i++)
            {
                bWriter.write( new String( ((String[])partitionTypesModel.elementAt(i))[0] +" "+ ((String[])partitionTypesModel.elementAt(i))[1] ));
                bWriter.newLine();
            }
            bWriter.flush();
            bWriter.close();
            writer.close();
            
        }catch(Exception ex)
        {
            controlClass.showError("Data Import: Error: Could not write file "+file.getPath());
        }
    }
    
    /**
     *Method to refresh the data on the panel
     */
    public void refresh()
    {
        try{
            this.loadNodes();
            
        }catch( Exception ex)
        {
            controlClass.showError("Data Import: Error: Could not read node file!");
            return;
        }

        //Load the hetero file if it exists
        File file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\heteroDist.txt");
        
        //If there is a data file but no heteroFile.txt then load the screen from the data file.
        if( file.exists() )
        {
            jButton8.setEnabled(true);
            jButton9.setEnabled(true);
            jButton17.setEnabled(false);
            if( dataRead )
            {
                this.openHeteroFile(file);
            }
        }else if( dataRead )
        {
            jButton8.setEnabled(true);
            jButton9.setEnabled(true);
            jButton17.setEnabled(true);
            
            //Refresh the display
            this.distributeHetero();
            
        }else{
            jButton8.setEnabled(false);
            jButton9.setEnabled(false);
            jButton17.setEnabled(false);
        }
        
        //Show the partition types matching
        this.displayPartitionTypes();
        
        //Load the file name if it exists
        file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\distribution.txt");
        if( file.exists() )
        {
            try{
                FileReader reader = new FileReader(file);
                BufferedReader bReader = new BufferedReader(reader);
                
                //Read in the type of distribution
                String type = bReader.readLine();
                if( type.equals("Heterogeneous"))
                {
                    jTabbedPane1.setSelectedIndex(1);
                }else if(type.equals("Homogeneous") )
                {
                    jTabbedPane1.setSelectedIndex(0);
                }if( type.equals("None"))
                {
                    throw new Exception("normal");
                }
                
                //Read in the location of the data file
                String data = bReader.readLine();
                this.dataFile = new File(data);
                this.openFile(dataFile);
                this.dataRead = true;
                
                //load the column data
                this.loadColumns();
            }catch(Exception ex)
            {
                //If this isn't really an error, but simply the fact that the file doesn't have a file location...
                if( ex.getMessage() != null && ex.getMessage().equals( "normal") )
                {
                }
                
                //Otherwise it really is an error
                else{
                    controlClass.showError("Data Import: Error: Could not load distribution file!");
                    ex.printStackTrace();
                }
            }
        }
    }
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents
        buttonGroup1 = new javax.swing.ButtonGroup();
        buttonGroup2 = new javax.swing.ButtonGroup();
        jPanel1 = new javax.swing.JPanel();
        jPanel14 = new javax.swing.JPanel();
        jButton15 = new javax.swing.JButton();
        jButton10 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jPanel3 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jPanel4 = new javax.swing.JPanel();
        jRadioButton1 = new javax.swing.JRadioButton();
        jRadioButton2 = new javax.swing.JRadioButton();
        jPanel5 = new javax.swing.JPanel();
        jSeparator1 = new javax.swing.JSeparator();
        jPanel6 = new javax.swing.JPanel();
        jPanel7 = new javax.swing.JPanel();
        jPanel9 = new javax.swing.JPanel();
        jPanel15 = new javax.swing.JPanel();
        jPanel18 = new javax.swing.JPanel();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel20 = new javax.swing.JPanel();
        jPanel21 = new javax.swing.JPanel();
        jLabel4 = new javax.swing.JLabel();
        jRadioButton3 = new javax.swing.JRadioButton();
        jRadioButton4 = new javax.swing.JRadioButton();
        jPanel23 = new javax.swing.JPanel();
        jPanel10 = new javax.swing.JPanel();
        jPanel12 = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        jList3 = new javax.swing.JList();
        jPanel17 = new javax.swing.JPanel();
        jLabel6 = new javax.swing.JLabel();
        jPanel24 = new javax.swing.JPanel();
        jButton9 = new javax.swing.JButton();
        jButton8 = new javax.swing.JButton();
        jButton17 = new javax.swing.JButton();
        jPanel16 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        jList1 = new javax.swing.JList();
        jLabel2 = new javax.swing.JLabel();
        jPanel26 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        jButton12 = new javax.swing.JButton();
        jPanel13 = new javax.swing.JPanel();
        jPanel8 = new javax.swing.JPanel();
        jPanel11 = new javax.swing.JPanel();
        jButton2 = new javax.swing.JButton();
        jButton4 = new javax.swing.JButton();
        jLabel3 = new javax.swing.JLabel();
        jScrollPane2 = new javax.swing.JScrollPane();
        jList2 = new javax.swing.JList();
        jPanel25 = new javax.swing.JPanel();
        jLabel5 = new javax.swing.JLabel();
        jLabel8 = new javax.swing.JLabel();

        jPanel1.setLayout(new java.awt.BorderLayout());

        jPanel1.setPreferredSize(new java.awt.Dimension(25, 25));
        jPanel1.setMaximumSize(new java.awt.Dimension(25, 25));
        jPanel1.setMinimumSize(new java.awt.Dimension(25, 25));
        jPanel14.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 5, 0));

        jButton15.setText("Refresh");
        jButton15.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton15ActionPerformed(evt);
            }
        });

        jPanel14.add(jButton15);

        jButton10.setText("Select Data File");
        jButton10.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton10ActionPerformed(evt);
            }
        });

        jPanel14.add(jButton10);

        jButton3.setText("Partition/Save");
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });

        jPanel14.add(jButton3);

        jPanel1.add(jPanel14, java.awt.BorderLayout.CENTER);

        add(jPanel1, java.awt.BorderLayout.SOUTH);

        jPanel2.setLayout(new java.awt.BorderLayout());

        jPanel3.setLayout(new javax.swing.BoxLayout(jPanel3, javax.swing.BoxLayout.X_AXIS));

        jLabel1.setText("Select Option:");
        jPanel3.add(jLabel1);

        jPanel3.add(jPanel4);

        jRadioButton1.setSelected(true);
        jRadioButton1.setText("Partition Data");
        jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButton1ActionPerformed(evt);
            }
        });

        jPanel3.add(jRadioButton1);

        jRadioButton2.setText("Do Not Partition Data");
        jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jRadioButton2ActionPerformed(evt);
            }
        });

        jPanel3.add(jRadioButton2);

        jPanel2.add(jPanel3, java.awt.BorderLayout.WEST);

        add(jPanel2, java.awt.BorderLayout.NORTH);

        jPanel5.setLayout(new java.awt.BorderLayout());

        jPanel5.add(jSeparator1, java.awt.BorderLayout.NORTH);

        jPanel6.setLayout(new java.awt.BorderLayout());

        jPanel7.setLayout(new java.awt.BorderLayout());

        jPanel9.setMaximumSize(new java.awt.Dimension(10, 10));
        jPanel7.add(jPanel9, java.awt.BorderLayout.WEST);

        jPanel15.setMaximumSize(new java.awt.Dimension(10, 10));
        jPanel7.add(jPanel15, java.awt.BorderLayout.NORTH);

        jPanel18.setLayout(new javax.swing.BoxLayout(jPanel18, javax.swing.BoxLayout.Y_AXIS));

        jPanel18.setName("Heterogeneous ");
        jTabbedPane1.setPreferredSize(new java.awt.Dimension(300, 300));
        jTabbedPane1.setMinimumSize(new java.awt.Dimension(310, 326));
        jTabbedPane1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                jTabbedPane1MouseClicked(evt);
            }
        });

        jPanel20.setLayout(new java.awt.BorderLayout());

        jPanel20.setPreferredSize(new java.awt.Dimension(150, 150));
        jPanel20.setName("Homogeneous");
        jPanel20.setMinimumSize(new java.awt.Dimension(0, 0));
        jPanel21.setBorder(new javax.swing.border.EtchedBorder());
        jLabel4.setText("Predefined Vectors:");
        jPanel21.add(jLabel4);

        jRadioButton3.setText("User");
        jPanel21.add(jRadioButton3);

        jRadioButton4.setSelected(true);
        jRadioButton4.setText("Uniform");
        jPanel21.add(jRadioButton4);

        jPanel20.add(jPanel21, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Homogeneous", jPanel20);

        jPanel23.setLayout(new java.awt.BorderLayout());

        jPanel23.setPreferredSize(new java.awt.Dimension(300, 300));
        jPanel23.setName("Heterogeneous");
        jPanel23.setMinimumSize(new java.awt.Dimension(300, 300));
        jPanel10.setLayout(new javax.swing.BoxLayout(jPanel10, javax.swing.BoxLayout.X_AXIS));

        jPanel12.setLayout(new java.awt.BorderLayout());

        jScrollPane3.setViewportView(jList3);

        jPanel12.add(jScrollPane3, java.awt.BorderLayout.CENTER);

        jPanel12.add(jPanel17, java.awt.BorderLayout.EAST);

        jLabel6.setText("Column Partitioning (Heterogeneous)");
        jPanel12.add(jLabel6, java.awt.BorderLayout.NORTH);

        jPanel24.setPreferredSize(new java.awt.Dimension(250, 40));
        jPanel24.setMinimumSize(new java.awt.Dimension(300, 40));
        jButton9.setText("Import");
        jButton9.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton9ActionPerformed(evt);
            }
        });

        jPanel24.add(jButton9);

        jButton8.setText("Export");
        jButton8.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton8ActionPerformed(evt);
            }
        });

        jPanel24.add(jButton8);

        jButton17.setText("Redistribute");
        jButton17.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton17ActionPerformed(evt);
            }
        });

        jPanel24.add(jButton17);

        jPanel12.add(jPanel24, java.awt.BorderLayout.SOUTH);

        jPanel10.add(jPanel12);

        jPanel16.setLayout(new java.awt.BorderLayout());

        jPanel16.setPreferredSize(new java.awt.Dimension(250, 40));
        jPanel16.setMinimumSize(new java.awt.Dimension(250, 40));
        jScrollPane1.setViewportView(jList1);

        jPanel16.add(jScrollPane1, java.awt.BorderLayout.CENTER);

        jLabel2.setText("List of Columns");
        jPanel16.add(jLabel2, java.awt.BorderLayout.NORTH);

        jPanel26.setPreferredSize(new java.awt.Dimension(350, 40));
        jPanel26.setMinimumSize(new java.awt.Dimension(350, 40));
        jButton1.setText("Set Universal");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jPanel26.add(jButton1);

        jButton12.setText("Set Normal");
        jButton12.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton12ActionPerformed(evt);
            }
        });

        jPanel26.add(jButton12);

        jPanel16.add(jPanel26, java.awt.BorderLayout.SOUTH);

        jPanel10.add(jPanel16);

        jPanel23.add(jPanel10, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Heterogeneous", jPanel23);

        jPanel13.setLayout(new java.awt.BorderLayout());

        jPanel13.setName("Partitioning List");
        jPanel8.setLayout(new java.awt.BorderLayout());

        jPanel13.add(jPanel8, java.awt.BorderLayout.CENTER);

        jButton2.setText("Partition");
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jPanel11.add(jButton2);

        jButton4.setText("Do Not Partition");
        jButton4.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton4ActionPerformed(evt);
            }
        });

        jPanel11.add(jButton4);

        jPanel13.add(jPanel11, java.awt.BorderLayout.SOUTH);

        jLabel3.setText("Partitioning List (Homogeneous)");
        jPanel13.add(jLabel3, java.awt.BorderLayout.NORTH);

        jPanel13.add(jScrollPane2, java.awt.BorderLayout.CENTER);

        jPanel13.add(jList2, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab("Partitioning List", jPanel13);

        jPanel18.add(jTabbedPane1);

        jPanel7.add(jPanel18, java.awt.BorderLayout.CENTER);

        jPanel6.add(jPanel7, java.awt.BorderLayout.CENTER);

        jPanel5.add(jPanel6, java.awt.BorderLayout.CENTER);

        jLabel5.setText("Current Data File:");
        jPanel25.add(jLabel5);

        jLabel8.setText("None");
        jPanel25.add(jLabel8);

        jPanel5.add(jPanel25, java.awt.BorderLayout.SOUTH);

        add(jPanel5, java.awt.BorderLayout.CENTER);

    }//GEN-END:initComponents

    /**
     *Method for 'Partition' clicked
     */
    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        //Loop for all the selected items
        int[] indices = jList2.getSelectedIndices();
        for( int i = 0 ; i < indices.length ; i++ )
        {
            partitionTypesModel.setElementAt(new String[]{((String[])partitionTypesModel.getElementAt(indices[i]))[0], "Partition"},indices[i]);
        }
        
        //Save to file
        this.savePartitionTypes();
        
        //Redistribute the hetero model based on these new rules
        if( indices.length >0 )
        {
            this.distributeHetero();
        }
    }//GEN-LAST:event_jButton2ActionPerformed

    /**
     *Method for 'Do Not Partition' clicked
     */
    private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton4ActionPerformed
        //Loop for all the selected items
        int[] indices = jList2.getSelectedIndices();
        for( int i = 0 ; i < indices.length ; i++ )
        {
            partitionTypesModel.setElementAt(new String[]{((String[])partitionTypesModel.getElementAt(indices[i]))[0], "Do_Not_Partition"},indices[i]);
        }
        
        //Save to file
        this.savePartitionTypes();
        
        //Redistribute the hetero model based on these new rules
        if( indices.length >0 )
        {
            this.distributeHetero();
        }
    }//GEN-LAST:event_jButton4ActionPerformed

    /**
     *Method for 'Set Normal' clicked
     */
    private void jButton12ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton12ActionPerformed
        //get the selected items
        int[] index = jList1.getSelectedIndices();
        for( int i = 0; i< index.length; i++)
        {
            //Change each element's value
            attributeModel.setElementAt(
                new String[]{((String[])attributeModel.elementAt(index[i]))[0], "Normal"}
                ,index[i]);
        }
        
        //Save the list
        this.saveColumns();
        
        //Redistribute the hetero list
        this.distributeHetero();
    }//GEN-LAST:event_jButton12ActionPerformed

    /**
     *Method for 'Set Universal' clicked
     */
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        //get the selected items
        int[] index = jList1.getSelectedIndices();
        for( int i = 0; i< index.length; i++)
        {
            //Change each element's value
            attributeModel.setElementAt(
                new String[]{((String[])attributeModel.elementAt(index[i]))[0], "Universal"}
                ,index[i]);
        }
        
        //Save the list
        this.saveColumns();
        
        //Redistribute the hetero list
        this.distributeHetero();
    }//GEN-LAST:event_jButton1ActionPerformed

    /**
     *Method for small tabbed pane clicked
     */
    private void jTabbedPane1MouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_jTabbedPane1MouseClicked
        if( this.dataRead )
        {
            jButton8.setEnabled(true);
            jButton9.setEnabled(true);
            jButton17.setEnabled(true);
        }
    }//GEN-LAST:event_jTabbedPane1MouseClicked

    /**
     *Method for 'Redistribute' on the hetero distribution model clicked
     */
    private void jButton17ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton17ActionPerformed
        this.distributeHetero();
    }//GEN-LAST:event_jButton17ActionPerformed

    /**
     *Method for 'Partition/Save' clicked
     */
    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
        //Save the node - local data matching
        try
        {
            //Clear out the old files if they exist
            if( controlClass.getProjectName() == null )
            {
                throw new Exception();
            }
            File nodesFile = new File("Files\\Projects\\" + controlClass.getProjectName() + "\\nodes.txt");
            if( nodesFile.exists() )
                nodesFile.delete();
            nodesFile.createNewFile();
        
            //Stop if there is no data file selected
            if( dataFile == null)
            {
                controlClass.showError("Data Import: Error: No data file selected!");
                return;
            }
            
            //Save the node data
            FileWriter nodeWriter = new FileWriter(nodesFile);
            BufferedWriter nodeBWriter = new BufferedWriter(nodeWriter);
            
            //Write the number of nodes in the file
            nodeBWriter.write(new String(""+controlClass.nodes.length ));
            nodeBWriter.newLine();
            String line = new String();
            for( int i = 0; i< controlClass.nodes.length; i++)
            {
                //Save format:
                //Node Number, Network Location, Data Location, Node Type, X-value, Y-value, Neighbor1, Neighbor1 delay, Neighbor2, ...
                String temp = new String(controlClass.nodes[i].getNumber()+" " + controlClass.nodes[i].getNetworkLocation() + " " + controlClass.nodes[i].getDataLocation() + " " + controlClass.nodes[i].getType()+" "+controlClass.nodes[i].getX()+" "+controlClass.nodes[i].getY()+" ");
                Vector v = controlClass.nodes[i].getNeighbors();
                for( int j = 0; j< v.size(); j++)
                {
                    temp = temp + (((Neighbor)v.elementAt(j)).getNumber()) +" "+ (((Neighbor)v.elementAt(j)).getDelay())+" ";
                }
                nodeBWriter.write(temp);
                nodeBWriter.newLine();
            }
            nodeBWriter.flush();
            nodeBWriter.close();
            nodeWriter.close();
        }catch( IOException ex)
        {
            controlClass.showError("Agent Types: Error: Couldn't save topology information to file!");
        }catch( NullPointerException ex )
        {
            controlClass.showError("Agent Types: Error: No Project selected!  Could not save file!");
        }catch( Exception x)
        {
            controlClass.showError("Agent Types: Error: Unknown Exception");
        }
        
        //Set up the file for the distribution save
        File file = null;
        FileWriter writer = null;
        BufferedWriter bWriter = null;
        
        try{
            file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\distribution.txt");
            writer = new FileWriter(file);
            bWriter = new BufferedWriter(writer); 
            
        }catch(IOException ex)
        {
            controlClass.showError("Data Import: Error: Could not save distribution vector to "+file.getPath()+"!");
        }
        
        //Case that no data distribution is supposed to take place
        if(jRadioButton2.isSelected() )
        {
            try
            {
                //Save the control file
                bWriter.write(new String("None"));
                bWriter.flush();
                bWriter.close();
                writer.close();
                return;
            }catch(IOException ex)
            {
                controlClass.showError("Data Import: Error: Could not save distribution vector to "+file.getPath()+"!");
            }
        }
        //If the user has 'Homogeneous' selected...
        else if( ((JPanel)jTabbedPane1.getSelectedComponent()).getName().equals( "Homogeneous"))
        {
            //Get a list of the nodes that should recieve data
            //Node[] partitionList = this.fillPartitionList();
            
            try
            {
                //Check for a data file selected
                if(!dataRead )
                {
                    controlClass.showError("Data Import: Error: No data file selected!");
                    return;
                }

                //Save the distribution type and file path
                bWriter.write(new String("Homogeneous"));
                bWriter.newLine();
                bWriter.write(dataFile.getPath());
                bWriter.flush();
                bWriter.close();
                writer.close();
                
                //Define a place for all the header files to be saved
                Vector headerInfo = new Vector();
                String relationLine = new String();

                //Read in the tuples
                {
                    //Initialize the storage area
                    tuples = new String[numTuples];
                    int numRead = 0;
                    int numAttributes = attributeNames.size();
                    attributeNames = new Vector();
                    
                    //Prepare the file writers to input the data
                    file = new File(jLabel8.getText());
                    FileReader reader = new FileReader(file);
                    BufferedReader bReader = new BufferedReader(reader);
                
                    //Read in each tuple and distribute it
                    String line = bReader.readLine();
                    Pattern tupleP = null;
                    Matcher tupleM;
                    boolean allAttributes = false; //Boolean that shows whether or not all the attributes have been read
                    while(line != null)
                    {
                        //Find the attribute names and put them in the list
                        //AND add the attribute and relation lines to the headerInfo vector (for printing later)
                        relationM = relationP.matcher(line);
                        attributeTypeM = attributeTypeP.matcher(line);
                        if( relationM.find() )
                        {
                            headerInfo.add(new String(line));
                        }
                        else if( attributeTypeM.matches() )
                        {
                            headerInfo.add(new String(line));
                            middleM = middleP.matcher(line);
                            middleM.find();
                            Pattern midP = Pattern.compile("\\s+(.+)\\s+");
                            Matcher midM = midP.matcher(middleM.group());
                            midM.find();
                            attributeNames.add(midM.group(1));
                        }
                        
                        //If the line isn't an attribute but there are attributes in the system, then assume that we have all the attributes and generate the pattern.
                        else if( attributeNames.size() > 0 && allAttributes == false )
                        {
                            if( numAttributes != attributeNames.size() )
                            {
                                controlClass.showError("Data Import: Error: File "+file.getPath()+" has changed! Please re-select it and try again.");
                                return;
                            }
                            allAttributes = true;
                        
                            //Define the tuple
                            String output = new String("(\\S+)");
                            for( int i = 1; i< attributeNames.size(); i++)
                            {
                                output = output + "\\s+(\\S+)";
                            }
                            tupleP = Pattern.compile(output);
                        }
                    
                        //If all the attributes have been read in and the line is a tuple, then...  Files\\
                        else if( tupleP != null )
                        {
                            tupleM = tupleP.matcher(line);
                            if( tupleM.find() )
                            {
                                tuples[numRead] = new String(tupleM.group());
                                numRead++;
                            }
                        }
                        
                        line = bReader.readLine();
                    }
                    reader.close();
                    bReader.close();
                }

                //Get the node - class matching
                file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\NodeClassMatching.txt");
                String[][] elements = this.readFile(file);
                
                //Replace the first element in the 'elements' array with true if it should be distributed
                for( int i = 0; i<elements[0].length; i++)
                {
                    for(int j = 0; j< this.partitionTypesModel.size(); j++)
                    {
                        String[] typeTemp = ((String[])partitionTypesModel.elementAt(j));
                        if( typeTemp[0].equals( elements[0][i]) && typeTemp[1].equals( "Partition"))
                        {
                            elements[0][i] = "True";
                        }
                    }
                }
                
                //Copy the nodes that are supposed to have data
                this.nodeList = new Vector();
                for( int i = 0; i< controlClass.nodes.length; i++)
                {
                    for( int j = 0; j<elements[0].length; j++)
                    {
                        if( controlClass.nodes[i].getType().equals( elements[1][j]) && elements[0][j].equals("True"))
                        {
                            nodeList.add(controlClass.nodes[i]);
                            break;
                        }
                    }
                }
                
                //distribute the touples to data files
                int[] nodeNum = new int[tuples.length];
                {
                    //Create the distribution object
                    DistributionTypes dTypes = new DistributionTypes();
                    
                    //If the uniform element is selected, then ...
                    if( jRadioButton4.isSelected() )
                    {
                        //Loop for each element in the data array
                        Random rand = new Random();
                        for( int i = 0; i< tuples.length; i++)
                        {
                            //Get the probability vector for this element
                            double[] pVec = dTypes.distribute(0, tuples[i]);
                            
                            //distribute the element
                            float num = (float)rand.nextDouble();
                            
                            //find which element it falls in
                            float temp = 0;
                            boolean found = false;
                            for( int j = 0; j < pVec.length; j++)
                            {
                                //Add in the current prob value
                                temp += pVec[j];
                                
                                //If the random number is smaller than the sum of all the elements up to this point...
                                if( num > temp )
                                {
                                    //...assign it to that node number.
                                    found = true;
                                    nodeNum[i] = j;
                                }
                            }
                            
                            //If this element doesn't fit into any of the other probabilities, then put it in the last one
                            if( found == false )
                            {
                                nodeNum[i] = pVec.length - 1;
                            }
                        }
                    }

                    
                    //..else if the user button is selected...
                    else if( jRadioButton3.isSelected() )
                    {
                        
                        //Loop for each element in the data array
                        Random rand = new Random();
                        for( int i = 0; i< tuples.length; i++)
                        {
                            //Get the probability vector for this element
                            double[] pVec = dTypes.distribute(1, tuples[i]);
                            
                            //distribute the element
                            double num = rand.nextDouble();
                            
                            //find which element it falls in
                            double temp = 0.0;
                            for( int j = 0; j < pVec.length; j++)
                            {
                                //Add in the current prob value
                                temp += pVec[j];
                                
                                //If the random number is smaller than the sum of all the elements up to this point...
                                if( num > temp )
                                {
                                    //...assign it to that node number.
                                    nodeNum[i] = j;
                                }
                            }
                        }
                    }
                
                    //Output the data to the files - loop for each node
                    for( int i = 0; i < this.nodeList.size(); i++)
                    {

                        //Continue if there is a data location defined for this node
                        if( !((Node)nodeList.elementAt(i)).getDataLocation().equals("None") )
                        {
                            //Define the writers for this node
                            file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\Data\\data"+((Node)nodeList.elementAt(i)).getNumber()+".txt");
                            writer = new FileWriter(file);
                            bWriter = new BufferedWriter(writer);
                            
                            //Write out the header files for the topology
                            bWriter.write(new String("%Filename: "+file.getPath()));
                            bWriter.newLine();
                            bWriter.newLine();
                            for( int j = 0; j < headerInfo.size(); j++)
                            {
                                bWriter.write((String)headerInfo.elementAt(j));
                                bWriter.newLine();
                            }
                            bWriter.newLine();
                            bWriter.write( new String("@DATA"));
                            
                            //loop for each tuple
                            bWriter.newLine();
                            for( int j = 0; j<nodeNum.length; j++)
                            {
                                //if this tuple belongs to this node, then write it out
                                if( nodeNum[j] == i )
                                {
                                    bWriter.write(tuples[j]);
                                    bWriter.newLine();
                                }
                            }
                            
                            bWriter.flush();
                            writer.close();
                            bWriter.close();
                        }
                    }
                }
                
                //Free the memory for that temp array of nodes that recieve data
                this.nodeList = null;
                    
            }catch(IOException ex)
            {
                controlClass.showError("Data Import: Error: Could not save distribution vector to "+file.getPath()+"!");
            }
        }
        //Else if the user has 'Heterogeneous' selected
        else if( ((JPanel)jTabbedPane1.getSelectedComponent()).getName().equals( "Heterogeneous") )
        {
            try{
                
                //Save the distribution type and file path
                bWriter.write(new String("Heterogeneous"));
                bWriter.newLine();
                bWriter.write(dataFile.getPath());
                bWriter.flush();
                bWriter.close();
                writer.close();
                
                //Save number of elements
                file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\heteroDist.txt");
                writer = new FileWriter(file);
                bWriter = new BufferedWriter(writer);
                bWriter.write(new String(""+heteroDistributionModel.getSize()));
                bWriter.newLine();
                
                //Save the heterogeneous panel (jPanel23, jList3) distribution
                String line = new String();
                String output = new String();
                for( int i = 0; i < heteroDistributionModel.getSize(); i++)
                {
                    //Set up the RegEx matches
                    String[] elements = (String[])heteroDistributionModel.elementAt(i);
                    firstM = firstP.matcher(elements[0]);
                    firstM.find();
                    output = new String(firstM.group()+ " "+ elements[1]);
                    bWriter.write(output);
                    bWriter.newLine();
                    
                }
                bWriter.flush();
                bWriter.close();
                writer.close();
                
                //Save the (column - partition or not) matching (jList1)
                this.saveColumns();
                
                //Initialize a place for all the header info for the nodes to go
                Vector headerInfo = new Vector();
                String relationLine = new String();
                
                //Read in the tuples
                {
                    //Initialize the storage area
                    this.columnTuples = new String[attributeNames.size()][numTuples];
                    int numRead = 0;
                    int numAttributes = attributeNames.size();
                    attributeNames = new Vector();
                    
                    //Prepare the file writers to input the data
                    file = new File(jLabel8.getText());
                    FileReader reader = new FileReader(file);
                    BufferedReader bReader = new BufferedReader(reader);
                
                    //Read in each tuple and distribute it
                    line = bReader.readLine();
                    Pattern tupleP = null;
                    Matcher tupleM;
                    boolean allAttributes = false; //Boolean that shows whether or not all the attributes have been read
                    while(line != null)
                    {
                        //Find the attribute names and put them in the list
                        //AND add the attribute and relation lines to the headerInfo vector (for printing later)
                        relationM = relationP.matcher(line);
                        attributeTypeM = attributeTypeP.matcher(line);
                        if( relationM.find() )
                        {
                            relationLine = new String(line);
                        }
                        else if( attributeTypeM.matches() )
                        {
                            headerInfo.add(new String(line));
                            middleM = middleP.matcher(line);
                            middleM.find();
                            Pattern midP = Pattern.compile("\\s+(.+)\\s+");
                            Matcher midM = midP.matcher(middleM.group());
                            midM.find();
                            attributeNames.add(midM.group(1));
                            
                        }
                        
                        //If the line isn't an attribute but there are attributes in the system, then assume that we have all the attributes and generate the pattern.
                        else if( attributeNames.size() > 0 && allAttributes == false )
                        {
                            if( numAttributes != attributeNames.size() )
                            {
                                controlClass.showError("Data Import: Error: File "+file.getPath()+" has changed! Please re-select it and try again.");
                                return;
                            }
                            allAttributes = true;
                            
                            //Define the tuple
                            output = new String("(\\S+)");
                            for( int i = 1; i< attributeNames.size(); i++)
                            {
                                output = output + "\\s+(\\S+)";
                            }
                            tupleP = Pattern.compile(output);
                        }
                    
                        //If all the attributes have been read in and the line is a tuple, then...
                        else if( tupleP != null )
                        {
                            
                            tupleM = tupleP.matcher(line);
                            if( tupleM.find() )
                            {
                                //Split the tuple up into columns
                                for( int j = 0; j< this.attributeNames.size(); j++)
                                {
                                    columnTuples[j][numRead] = tupleM.group(j+1);
                                }
                                numRead++;
                            }
                        }
                        
                        line = bReader.readLine();
                    }
                    reader.close();
                    bReader.close();
                }
                
                //Get the node - class matching
                file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\NodeClassMatching.txt");
                String[][] elements = this.readFile(file);
                
                //Replace the first element in the 'elements' array with true if it should be distributed
                for( int i = 0; i<elements[0].length; i++)
                {
                    for(int j = 0; j< this.partitionTypesModel.size(); j++)
                    {
                        String[] typeTemp = ((String[])partitionTypesModel.elementAt(j));
                        if( typeTemp[0].equals( elements[0][i]) && typeTemp[1].equals( "Partition"))
                        {
                            elements[0][i] = "True";
                        }
                    }
                }
                
                //Copy the nodes that are supposed to have data
                boolean[] partitionList = new boolean[controlClass.nodes.length];
                for( int i = 0; i< controlClass.nodes.length; i++)
                {
                    boolean found = false;
                    for( int j = 0; j<elements[0].length; j++)
                    {
                        if( controlClass.nodes[i].getType().equals( elements[1][j]) && elements[0][j].equals("True"))
                        {
                            found = true;
                            break;
                        }
                    }
                    partitionList[i] = found;
                }
                elements = null;
                
                //Load the node types
                this.distributeSettings();
                
                //Make a matrix whos columns are nodes and rows are attributes - true = this column is distributed to this node.
                boolean[][] attributesMatrix = new boolean[controlClass.nodes.length][attributeModel.size()];
                
                //Set the universal/Normal attributes 
                String oneAttribute = new String();
                for( int i = 0; i< controlClass.nodes.length; i++)
                {
                    //Get the list of attributes for this node
                    String temp = ((String[])heteroDistributionModel.elementAt(i))[1];
                    
                    //add the universal elements if they apply
                    if( partitionList[i] == true )
                    {
                        for( int j = 0; j< attributeModel.size(); j++)
                        {
                            if( ((String)((Object[])attributeModel.getElementAt(j))[1]).equals("Universal") )
                            {
                              temp = temp + " "+ ((String)((Object[])attributeModel.getElementAt(j))[0]);
                            }
                            //System.out.println((String)((Object[])attributeModel.getElementAt(j))[1]);
                        }
                    }
                    
                    //Get one element
                    heteroDistM = heteroDistP.matcher(temp);
                    while(heteroDistM.find())
                    {
                        oneAttribute = heteroDistM.group(1) ;
                        
                        //Check which number this element is
                        for( int k = 0; k< attributeNames.size();k++)
                        {
                            if( oneAttribute.equals( ((String)attributeNames.elementAt(k))))
                            {
                                attributesMatrix[i][k] = true;
                            }
                        }
                    }
                }
                
                //Write each file
                //Loop for each node
                for( int i = 0; i< heteroDistributionModel.size(); i++)
                {
                    //open the file
                    file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\Data\\data"+controlClass.nodes[i].getNumber()+".txt");
                    if( !file.exists())
                    {
                        file.createNewFile();
                    }
                    writer = new FileWriter(file);
                    bWriter = new BufferedWriter(writer);
                    
                    //Output the header for the attribute definition part
                    bWriter.write(relationLine);
                    bWriter.newLine();
                    
                    //Loop for each of the attributes
                    for( int j = 0; j< attributesMatrix[0].length; j++)
                    {
                        //If this attribute belongs to this node, then output it
                        if( attributesMatrix[i][j] == true )
                        {
                            bWriter.write((String)headerInfo.elementAt(j));
                            bWriter.newLine();
                        }
                    }
                    
                    //output the header for the data
                    bWriter.newLine();
                    bWriter.write("@DATA");
                    bWriter.newLine();
                    
                    //Loop for each tuple in the system
                    output = new String();
                    for(int j = 0; j< columnTuples[0].length; j++)
                    {
                        //loop for each attribute
                        for( int k = 0; k< attributesMatrix[0].length; k++)
                        {
                            //If this attribute is supposed to belong to this node, then add it.
                            if( attributesMatrix[i][k] == true)
                            {
                                output = output + " "+ columnTuples[k][j];
                            }
                        }
                        
                        //Write this line
                        if(output.length() > 0)
                        {
                            bWriter.write(output);
                            bWriter.newLine();
                            output = new String();
                        }
                    }
                    
                    //close the streams
                    bWriter.flush();
                    writer.close();
                    bWriter.close();
                }
                
                //free the memory
                this.columnTuples = null;
            }catch(IOException ex)
            {
                controlClass.showError("Data Import: Error: Could not save distribution vector to "+file.getPath()+"!");
            }
        } else 
        {
            controlClass.showError("Data Import: Error: No distribution type selected! (Panel must be selected to distribute)");
        }
        
        //Save the local locations
        try{
            file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\locations.txt");
            writer = new FileWriter(file);
            bWriter = new BufferedWriter(writer);
            
            //write the number of lines
            bWriter.write(new String(""+controlClass.nodes.length));
            bWriter.newLine();
            
            //Write each line
            for( int i = 0; i< controlClass.nodes.length; i++)
            {
                bWriter.write(new String(""+i+" "+controlClass.nodes[i].getDataLocation()));
                bWriter.newLine();
            }
            bWriter.close();
            writer.close();
        }catch( Exception ex)
        {
            controlClass.showError("Data Import: Error: Could not save file distribution!");
        }
        
        //Save the column vector
        this.saveColumns();
    }//GEN-LAST:event_jButton3ActionPerformed

    /**
     *Method that returns a boolean array the length of the node list that contains true 
     *if this node is partitioned data.
     */
    private Node[] fillPartitionList()
    {
        Node[] partitionList = new Node[controlClass.nodes.length];
        
        //loop for each of the nodes
        //for( int i = 0; i< controlClass.nodes.length; i++)
        //{
            //loop for each of the node - node type matchings
            for( int j = 0; j< nodeTypes[0].length; j++)
            {
                 System.out.println(nodeTypes[0][j]+", "+nodeTypes[1][j] );       
            }
        //}
        
        return partitionList;
    }
    
    /**
     *Method for 'Import' on the heterogeneous tab clicked
     */
    private void jButton9ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton9ActionPerformed
        //Show a file chooser 
        JFileChooser fc = new JFileChooser();
        int returnVal = fc.showOpenDialog(this.getParent());
        
        //Get the return file, if applicable
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            this.openHeteroFile(fc.getSelectedFile());

        }
    }//GEN-LAST:event_jButton9ActionPerformed

    /*
     *Method to open the hetero distribution file that is passed in
     */
    private void openHeteroFile(File f)
    {
        File file = null;
        try{
            file = f;
            file.createNewFile();
            FileReader reader = new FileReader(file);
            BufferedReader bReader = new BufferedReader(reader);
                
            //The vector that holds the number of columns
            attributeNames = new Vector();
            
            //Read in the number of pairs
            String line = bReader.readLine();
            int numLines = Integer.parseInt(line);
                
            //load the file
            heteroDistributionModel = new DefaultListModel();
            line = bReader.readLine();
            while( line != null )
            {
                //Set up the RegEx matches
                heteroDistM = heteroDistP.matcher(line);
                firstM = firstP.matcher(line);
                firstM.find();
                String output1 = new String(firstM.group()+" (");
                for( int j = 0; j< nodeTypes[0].length; j++)
                {
                    if( controlClass.nodes[Integer.parseInt(firstM.group())].getType().equals( nodeTypes[1][j]) )
                    {
                        output1 = output1+nodeTypes[0][j]+")";
                    }
                }
                String output2 = new String();
                while( heteroDistM.find() )
                {
                    attributeNames.add(heteroDistM.group(1));
                    output2 = output2 + " "+heteroDistM.group(1);
                }
                heteroDistributionModel.addElement(new String[]{output1, output2});
                line = bReader.readLine();
            }
            jList3.setModel(heteroDistributionModel);
            jList3.setCellRenderer(new DoubleCellRenderer());
            bReader.close();
            reader.close();
        }catch(IOException ex)
        {
            controlClass.showError("Data Import: Error: File "+file.getPath()+" is not a valid Heterogeneous data file!");
        }catch(Exception ex)
        {
            controlClass.showError("Data Import: Error: Unknown problem reading file "+file.getPath()+"!");
        }
    }
    
    /**
     *Method for 'Export' on the heterogeneous tab clicked
     */
    private void jButton8ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton8ActionPerformed
        //Show a file chooser 
        JFileChooser fc = new JFileChooser();
        int returnVal = fc.showSaveDialog(this.getParent());
        
        try{
            //Get the return file, if applicable
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                //Save the distribution type and file path
                File file = fc.getSelectedFile();
                FileWriter writer = new FileWriter(file);
                BufferedWriter bWriter = new BufferedWriter(writer);
                
                //Save number of elements
                writer = new FileWriter(file);
                bWriter = new BufferedWriter(writer);
                bWriter.write(new String(""+heteroDistributionModel.getSize()));
                bWriter.newLine();
                
                //Save the heterogeneous panel (jPanel23, jList3) distribution
                String line = new String();
                String output = new String();
                for( int i = 0; i < heteroDistributionModel.getSize(); i++)
                {
                    //Set up the RegEx matches
                    String[] elements = (String[])heteroDistributionModel.elementAt(i);
                    firstM = firstP.matcher(elements[0]);
                    firstM.find();
                    output = new String(firstM.group()+ " "+ elements[1]);
                    bWriter.write(output);
                    bWriter.newLine();
                    
                }
                bWriter.flush();
                bWriter.close();
                writer.close();
            }
        }catch(IOException ex)
        {
            controlClass.showError("Data Import: Error: Could not write to data file!");
            ex.printStackTrace();
        }catch(Exception ex)
        {
            controlClass.showError("Data Import: Error: Unknown error saving data file!");
            ex.printStackTrace();
        }
    }//GEN-LAST:event_jButton8ActionPerformed

    /**
     *Method for 'Select Data File' pressed
     */
    private void jButton10ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton10ActionPerformed
        //Open a file chooser
        JFileChooser fc = new JFileChooser();
        int returnVal = fc.showOpenDialog(this.getParent());
        
        //Initialize the attribute names varaible
        attributeNames = new Vector();
        
        //Get the return file, if applicable
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            dataFile = fc.getSelectedFile();
            
            this.openFile(dataFile);
        }
        
        //Make sure that the buttons that are useless without a data file aren't
        //enabled until this is done
        if( this.dataRead )
        {
            jButton8.setEnabled(true);
            jButton9.setEnabled(true);
            jButton17.setEnabled(true);
        }
        
        //Now do the random distribution
        if( attributeNames.size() > 0)
        {
            dataRead = true;
            
            //Load the attributes into the model
            try{
                //Loop for each attribute
                attributeModel = new DefaultListModel();
                for( int i = 0; i< attributeNames.size(); i++)
                {
                    attributeModel.addElement(new String[]{(String)attributeNames.elementAt(i), "Normal"});
                }
                jList1.setCellRenderer( new DoubleCellRenderer());
                jList1.setModel(attributeModel);
            }catch(Exception ex)
            {
                controlClass.showError("Data Import: Error: ");
                ex.printStackTrace();
            }
            
            this.distributeHetero();
        }else{
            controlClass.showError("Data Import: Error: Not a valid WEKA file format!");
        }
    }//GEN-LAST:event_jButton10ActionPerformed

    /**
     *Method to open a data file
     */
    private void openFile( File file )
    {
        
        //Delete the old file
        File oldFile = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\heteroDist.txt");
        if( oldFile.exists() )
            oldFile.delete();
        
        //Update display
        attributeNames = new Vector();
        jLabel8.setText(dataFile.getPath());
        numTuples = 0;
        try{
            
            //Pattern that will be defined for a tuple
            Pattern tupleP = null;
            Matcher tupleM;
            
            //Read the data types
            FileReader reader = new FileReader(dataFile);
            BufferedReader bReader = new BufferedReader(reader);
            String line = bReader.readLine();
            boolean allAttributes = false; //Boolean that shows whether or not all the attributes have been read
            while(line != null)
            {
                //Find the attribute names and put them in the list
                attributeTypeM = attributeTypeP.matcher(line);
                if( attributeTypeM.matches() )
                {
                    middleM = middleP.matcher(line);
                    middleM.find();
                    Pattern midP = Pattern.compile("\\s+(.+)\\s+");
                    Matcher midM = midP.matcher(middleM.group());
                    midM.find();
                    attributeNames.add(midM.group(1));
                        
                }
                
                //If the line isn't an attribute but there are attributes in the system, then assume that we have all the attributes and generate the pattern.
                else if( attributeNames.size() > 0 && allAttributes == false )
                {
                    allAttributes = true;
                    
                    //Define the tuple
                    String output = new String("(\\s+)?\\S+");
                    for( int i = 1; i< attributeNames.size(); i++)
                    {
                        output = output + "\\s+\\S+";
                    }
                    tupleP = Pattern.compile(output);
                }
                
                //If all the attributes have been read in and the line is a tuple, then...
                else if( tupleP != null )
                {
                    tupleM = tupleP.matcher(line);
                    if( tupleM.find() )
                    {
                        numTuples++;
                    }
                }
                
                line = bReader.readLine();
            }
            reader.close();
            bReader.close();
                
        }catch(IOException ex)
        {
            controlClass.showError("Data Import: Error: Unable to read data file!");
            file.delete();
        }
        
        //Display these new attribute names
        attributeModel = new DefaultListModel();
        for( int i = 0; i< attributeNames.size();i++)
        {
            attributeModel.addElement(new String[]{ ((String)attributeNames.elementAt(i)), new String("Normal")});
        }
        jList1.setCellRenderer(new DoubleCellRenderer());
        jList1.setModel(attributeModel);
    }
    
    /**
     *Method for 'Refresh' pressed
     */
    private void jButton15ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton15ActionPerformed
        try{
            this.loadNodes();
        }catch(Exception ex)
        {
            controlClass.showError("Data Import: Error: Could not read node file!");
        }
    }//GEN-LAST:event_jButton15ActionPerformed

    /**
     *Method for 'Distribute Data and Specify Locations' clicked
     */
    private void jRadioButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButton1ActionPerformed
        //Enable all the buttons
        jTabbedPane1.setEnabled(true);
        jScrollPane1.getHorizontalScrollBar().setEnabled(true);
        jScrollPane1.getVerticalScrollBar().setEnabled(true);
        jScrollPane2.getHorizontalScrollBar().setEnabled(true);
        jScrollPane2.getVerticalScrollBar().setEnabled(true);
        jScrollPane3.getHorizontalScrollBar().setEnabled(true);
        jScrollPane3.getVerticalScrollBar().setEnabled(true);
        jList1.setEnabled(true);
        jList2.setEnabled(true);
        jList3.setEnabled(true);
        jLabel2.setEnabled(true);
        jLabel3.setEnabled(true);
        jLabel4.setEnabled(true);
        jLabel5.setEnabled(true);
        jLabel6.setEnabled(true);
        jLabel8.setEnabled(true);
        jButton1.setEnabled(true);
        jButton2.setEnabled(true);
        jButton4.setEnabled(true);
        jButton10.setEnabled(true);
        jButton12.setEnabled(true);
        jRadioButton3.setEnabled(true);
        jRadioButton4.setEnabled(true);
        //Load the hetero file if it exists
        File file = new File("Files\\Projects\\"+controlClass.getProjectName()+"\\heteroDist.txt");
        
        //If there is a data file but no heteroFile.txt then load the screen from the data file.
        if( file.exists() )
        {
            jButton8.setEnabled(true);
            jButton9.setEnabled(true);
            jButton17.setEnabled(false);
            if( dataRead )
            {
                this.openHeteroFile(file);
            }
        }else if( dataRead )
        {
            jButton8.setEnabled(true);
            jButton9.setEnabled(true);
            jButton17.setEnabled(true);
            
            //Refresh the display
            this.distributeHetero();
            
        }else{
            jButton8.setEnabled(false);
            jButton9.setEnabled(false);
            jButton17.setEnabled(false);
        }
        
        //Show the partition types matching
        this.displayPartitionTypes();
    }//GEN-LAST:event_jRadioButton1ActionPerformed

    /**
     *Method for 'Specify Locations Only' clicked
     */
    private void jRadioButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jRadioButton2ActionPerformed
        //disable the distribute data panel
        jTabbedPane1.setEnabled(false);
        jScrollPane1.setEnabled(false);
        jScrollPane1.getHorizontalScrollBar().setEnabled(false);
        jScrollPane1.getVerticalScrollBar().setEnabled(false);
        jScrollPane2.getHorizontalScrollBar().setEnabled(false);
        jScrollPane2.getVerticalScrollBar().setEnabled(false);
        jScrollPane3.getHorizontalScrollBar().setEnabled(false);
        jScrollPane3.getVerticalScrollBar().setEnabled(false);
        jScrollPane2.setEnabled(false);
        jScrollPane3.setEnabled(false);
        jList1.setEnabled(false);
        jList2.setEnabled(false);
        jList3.setEnabled(false);
        jLabel2.setEnabled(false);
        jLabel3.setEnabled(false);
        jLabel4.setEnabled(false);
        jLabel5.setEnabled(false);
        jLabel6.setEnabled(false);
        jLabel8.setEnabled(false);
        jButton1.setEnabled(false);
        jButton2.setEnabled(false);
        jButton4.setEnabled(false);
        jButton8.setEnabled(false);
        jButton9.setEnabled(false);
        jButton10.setEnabled(false);
        jButton12.setEnabled(false);
        jButton17.setEnabled(false);
        jRadioButton3.setEnabled(false);
        jRadioButton4.setEnabled(false);
    }//GEN-LAST:event_jRadioButton2ActionPerformed
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.ButtonGroup buttonGroup1;
    private javax.swing.ButtonGroup buttonGroup2;
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton10;
    private javax.swing.JButton jButton12;
    private javax.swing.JButton jButton15;
    private javax.swing.JButton jButton17;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JButton jButton4;
    private javax.swing.JButton jButton8;
    private javax.swing.JButton jButton9;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JList jList1;
    private javax.swing.JList jList2;
    private javax.swing.JList jList3;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel10;
    private javax.swing.JPanel jPanel11;
    private javax.swing.JPanel jPanel12;
    private javax.swing.JPanel jPanel13;
    private javax.swing.JPanel jPanel14;
    private javax.swing.JPanel jPanel15;
    private javax.swing.JPanel jPanel16;
    private javax.swing.JPanel jPanel17;
    private javax.swing.JPanel jPanel18;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel20;
    private javax.swing.JPanel jPanel21;
    private javax.swing.JPanel jPanel23;
    private javax.swing.JPanel jPanel24;
    private javax.swing.JPanel jPanel25;
    private javax.swing.JPanel jPanel26;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JPanel jPanel7;
    private javax.swing.JPanel jPanel8;
    private javax.swing.JPanel jPanel9;
    private javax.swing.JRadioButton jRadioButton1;
    private javax.swing.JRadioButton jRadioButton2;
    private javax.swing.JRadioButton jRadioButton3;
    private javax.swing.JRadioButton jRadioButton4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JTabbedPane jTabbedPane1;
    // End of variables declaration//GEN-END:variables
    
    /**
     *Distribution type class.  Controls which type of distribution is used
     */
    class DistributionTypes
    {
        //Array of strings that are the names of the types of distributions
        String[] names = new String[]{"Uniform", "User"};
        
        /**
         *Constructor
         */
        public DistributionTypes()
        {
            
        }
        
        /**
         *Method that will return the node number that this tuple belongs to.
         */
        public double[] distribute(int type, String tuple)
        {
            switch(type)
            {
                case 0:
                    return this.uniform(tuple);
                case 1:
                    return this.user(tuple);
            }
            return new double[]{-1.0};
        }
        
        /**
         *Method to do uniform distribution
         */
        private double[] uniform(String tuple)
        {
            double prob = 1.0 / nodeList.size();
            double[] num = new double[nodeList.size()];
            
            for( int i = 0; i< nodeList.size(); i++)
            {
                num[i] = prob;
            }
            return num;
        }
        
        /**
         *Method to do user distribution.  Not defined yet.
         */
        private double[] user(String tuple)
        {
            return new double[]{0.0, 0.0};
        }
    }
    
    /**
     *Cell renderer for the list.  Shows two strings seperated by a two-way arrow.
     */
    public class DoubleCellRenderer extends JPanel implements ListCellRenderer {
            
        //The left label
        JLabel left;
        
        //The right label
        JLabel right;
        
        //the center label
        JLabel center;
        
        /**
         *Method to create a new cell renderer
         */
        DoubleCellRenderer() 
        {
            setLayout( new GridLayout());
            left = new JLabel();
            right = new JLabel();
            center = new JLabel();
            left.setOpaque(true);
            right.setOpaque(true);
            center.setOpaque(true);
            add(left);
            add(center);
            add(right);
        }
      
        /**
         *Method to get one component of the cell renderer
         */
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) 
        {
            //The first string
            String leftS = ((String[])value)[0];
            String rightS = ((String[])value)[1];
            left.setText(leftS);
            right.setText(rightS);
            center.setIcon(new ImageIcon("Files\\Core\\Icons\\arrow.gif"));
            
            if (isSelected) 
            {
                right.setBackground( list.getSelectionBackground());
                right.setForeground( list.getSelectionForeground());
                left.setBackground( list.getSelectionBackground());
                left.setForeground( list.getSelectionForeground());
                center.setBackground( list.getSelectionBackground());
                center.setForeground( list.getSelectionForeground());
                right.setEnabled(true);
                left.setEnabled(true);
                center.setEnabled(true);
            } else {
                right.setBackground(list.getBackground());
                right.setForeground(list.getForeground());
                left.setBackground(list.getBackground());
                left.setForeground(list.getForeground());
                center.setBackground(list.getBackground());
                center.setForeground(list.getForeground());
                right.setEnabled(true);
                left.setEnabled(true);
                center.setEnabled(true);
            }
            
            if( !list.isEnabled() )
            {
                right.setBackground(list.getBackground());
                right.setEnabled(false);
                left.setBackground(list.getBackground());
                left.setEnabled(false);
                center.setBackground(list.getBackground());
                center.setEnabled(false);
            }
            
            setEnabled(list.isEnabled());
            setFont(list.getFont());
            return this;
        }
    }
}
