/*
  GAClust.java
  
  (P)2002 Dana Cristofor
*/

/*

GAClust - Clustering categorical databases using genetic algorithms
Copyright (C) 2002  Dana Cristofor


This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA

GAClust was written by Dana Cristofor (dana@cs.umb.edu).

*/

import laur.tools.*;
import laur.tools.Timer;

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import javax.swing.table.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.text.*;

/**
 * The GAClust GUI
 *
 * @version 	1.0
 * @author	Dana Cristofor
 */
public class GAClust extends JFrame 
implements ActionListener, ItemListener, ThreadMonitor
{
  // variables for database selection
  private String DBName;
  private int nRows;
  private int nCols;
  private Partition[] db;
  private Partition[] db_copy;

  // variables for genetic algorithm
  private int popSize;
  private int K;
  private int useTarget; 
  private int targetId;
  private int useWeights; 
  private double sampleDBPct;
  private int excludeAttr;
  private int noRemAttr;
  private double crossoverRate; 
  private double mutationRate; 
  private int classFitnessType; 
  private int crossoverType; 
  private int mutationType;
  private int distributionType;
  private int entropyMeasure; 
  private int fitnessMeasure; 
  private int minimization; 
  private double fitnessThreshold;
  private int consecItrs; 
  private int randseed;
  private Timer timer;
  private Partition refPart; // reference partition
  private GA  ga; // genetic algorithm
  private GenSynDB genSynDB;
  // attribute weights
  private double[] wTargetCondOnDB;
  private double[] wDBCondOnTarget;
  private double[] weight;
  private double targetEntr;
  private int nColsClust;
  private int nColsClust_copy;
  private Random rand;
  private Chromosome finalChrom;
  private Integer noIterations;
  private boolean flipTarget;

  // variables for generate database tab
  private boolean isGenerating;
  private int nDBClasses;
  private int DBSeed;
  private int generateLarge;

  // miscellaneous
  private int status;
  // rembers the last fitness measure used
  private int lastFitnessMeasureUsed;

  // a ThreadMonitor reference used to refer to the monitor of a
  // thread that is executing at some point
  private ThreadMonitor monitor;
  private NumberFormat nf;
  private StringBuffer output;
  private ResultsTableModel resModel;

  private final int IDLE = 0;
  private final int GA_RUNNING = 1;
  private final int GENDB_RUNNING = 2;

  /** Creates new form GAClust */
  public GAClust() 
  {
    super("GAClust");
    timer = new Timer();
    nf = NumberFormat.getInstance();
    nf.setMaximumFractionDigits(3);
    status = IDLE;
    resModel = null;
    initComponents();
  }

  /** This method is called from within the constructor to
   * initialize the form.
   */
  private void initComponents() 
  {
    // initComponents
    MainMenuBar = new JMenuBar();
    ProgramMenu = new JMenu();
    ForceGCMenuItem = new JMenuItem();
    ExitMenuItem = new JMenuItem();

    HelpMenu = new JMenu();
    TopicsMenuItem = new JMenuItem();
    AboutMenuItem = new JMenuItem();

    // Database Tab
    MainTabbedPane = new JTabbedPane();
    DatabaseSplitPane = new JSplitPane();
    DatabasePanel = new JPanel();
    DatabaseCenterPanel = new JPanel();
    DatabaseSouthPanel = new JPanel();
    DBNameLabelPanel = new JPanel();
    DBNameLabel = new JLabel();
    DBNamePanel = new JPanel();
    DBNameTextField = new JTextField();
    BrowsePanel = new JPanel();
    BrowseButton = new JButton();
    NRowsLabelPanel = new JPanel();
    NRowsLabel = new JLabel();
    NRowsPanel = new JPanel();
    NRowsTextField = new JTextField();
    BogusLabel1 = new JLabel();
    BogusLabel2 = new JLabel();
    NAttrLabelPanel = new JPanel();
    NAttrLabel = new JLabel();
    NAttrPanel = new JPanel();
    NAttrTextField = new JTextField();
    OpenButton = new JButton();
    Results = new JPanel();
    ResultsNorth = new JPanel();
    ResultsSouth = new JPanel();
    DatabaseScrollPane = new JScrollPane();
    DBLogTextArea = new JTextArea();
    DBTableScrollPane = new JScrollPane();
    DBTable = new JTable();

    // Generate Tab
    GenerateSplitPane = new JSplitPane();
    GenerateDBPanel = new JPanel();
    GenerateDBNorthPanel = new JPanel();
    GenerateDBSouthPanel = new JPanel();
    GenDBNameLabelPanel = new JPanel();
    GenDBNameLabel = new JLabel();
    GenDBNamePanel = new JPanel();
    GenDBNameTextField = new JTextField();
    UseDefaultNamingCheckBox = new JCheckBox();
    UseDefaultNamingPanel = new JPanel();
    GenNRowsLabelPanel = new JPanel();
    GenNRowsLabel = new JLabel();
    GenNRowsPanel = new JPanel();
    GenNRowsTextField = new JTextField();
    GenBogusLabel1 = new JLabel();
    GenNAttrLabelPanel = new JPanel();
    GenNAttrLabel = new JLabel();
    GenNAttrPanel = new JPanel();
    GenNAttrTextField = new JTextField();
    GenBogusLabel2 = new JLabel();
    GenNClassesLabelPanel = new JPanel();
    GenNClassesLabel = new JLabel();
    GenNClassesPanel = new JPanel();
    GenNClassesTextField = new JTextField();
    GenBogusLabel3 = new JLabel();
    GenRandomSeedLabelPanel = new JPanel();
    GenRandomSeedLabel = new JLabel();
    GenRandomSeedPanel = new JPanel();
    GenRandomSeedTextField = new JTextField();
    GenBogusLabel4 = new JLabel();
    GenerateLargePanel = new JPanel();
    GenerateLargeCheckBox = new JCheckBox();
    GenBogusLabel5 = new JLabel();
    GenBogusLabel6 = new JLabel();
    GenerateButton = new JButton();
    GenAbortButton = new JButton();
    GenProgressBar = new JProgressBar();
    GenProgressBarPanel = new JPanel();
    GenResultsPanel = new JPanel();
    GenResultsNorthPanel = new JPanel();
    GenResultsSouthPanel = new JPanel();
    GenDBTableScrollPane = new JScrollPane();
    GenDBTable = new JTable();
    GenLogScrollPane = new JScrollPane();
    GenLogTextArea = new JTextArea();

    // GA Tab
    GAHorizontalSplitPane = new JSplitPane();
    GASplitPane = new JSplitPane();
    GAPanel = new JPanel();
    GACenterPanel = new JPanel();
    GASouthPanel = new JPanel();
    PopSizeLabelPanel = new JPanel();
    PopSizeLabel = new JLabel();
    PopSizePanel = new JPanel();
    PopSizeTextField = new JTextField();
    NClassesClustLabelPanel = new JPanel();
    NClassesClustLabel = new JLabel();
    NClassesClustPanel = new JPanel();
    NClassesClustTextField = new JTextField();
    CrossRateLabelPanel = new JPanel();
    CrossRateLabel = new JLabel();
    CrossRatePanel = new JPanel();
    CrossRateTextField = new JTextField();
    MutRateLabelPanel = new JPanel();
    MutRateLabel = new JLabel();
    MutRatePanel = new JPanel();
    MutRateTextField = new JTextField();
    ClassFitnessLabelPanel = new JPanel();
    ClassFitnessLabel = new JLabel();
    ClassFitnessPanel = new JPanel();
    ClassFitnessComboBox = new JComboBox();
    CrossTypeLabelPanel = new JPanel();
    CrossTypeLabel = new JLabel();
    CrossTypePanel = new JPanel();
    CrossTypeComboBox = new JComboBox();
    MutTypeLabelPanel = new JPanel();
    MutTypeLabel = new JLabel();
    MutTypePanel = new JPanel();
    MutTypeComboBox = new JComboBox();
    DistrTypeLabelPanel = new JPanel();
    DistrTypeLabel = new JLabel();
    DistrTypePanel = new JPanel();
    DistrTypeComboBox = new JComboBox();
    EntropyMeasureLabelPanel = new JPanel();
    EntropyMeasureLabel = new JLabel();
    EntropyMeasurePanel = new JPanel();
    EntropyMeasureComboBox = new JComboBox();
    FitnessMeasureLabelPanel = new JPanel();
    FitnessMeasureLabel = new JLabel();
    FitnessMeasurePanel = new JPanel();
    FitnessMeasureComboBox = new JComboBox();
    FitnessThresholdLabelPanel = new JPanel();
    FitnessThresholdLabel = new JLabel();
    FitnessThresholdPanel = new JPanel();
    FitnessThresholdTextField = new JTextField();
    ConsecItrsLabelPanel = new JPanel();
    ConsecItrsLabel = new JLabel();
    ConsecItrsPanel = new JPanel();
    ConsecItrsTextField = new JTextField();
    RandomSeedGALabelPanel = new JPanel();
    RandomSeedGALabel = new JLabel();
    RandomSeedGAPanel = new JPanel();
    RandomSeedGATextField = new JTextField();
    UseTargetPanel = new JPanel();
    UseTargetCheckBox = new JCheckBox();
    TargetIDLabelPanel = new JPanel();
    TargetIDLabel = new JLabel();
    TargetIDPanel = new JPanel();
    TargetIDTextField = new JTextField();
    UseWeightsPanel = new JPanel();
    UseWeightsCheckBox = new JCheckBox();
    SampleDBPctLabelPanel = new JPanel();
    SampleDBPctLabel = new JLabel();
    SampleDBPctPanel = new JPanel();
    SampleDBPctTextField = new JTextField();
    ExcludeAttrPanel = new JPanel();
    ExcludeAttrCheckBox = new JCheckBox();
    NRemAttrLabelPanel = new JPanel();
    NRemAttrLabel = new JLabel();
    NRemAttrPanel = new JPanel();
    NRemAttrTextField = new JTextField();
    MinimizationLabelPanel = new JPanel();
    MinimizationLabel = new JLabel();
    MinimizationPanel = new JPanel();
    MinimizationComboBox = new JComboBox();
    ClusterPanel = new JPanel();
    ClusterButton = new JButton();
    ClusterAbortButton = new JButton();
    BogusLabel3 = new JLabel();
    BogusLabel4 = new JLabel();
    BogusLabel5 = new JLabel();
    GAResultsPanel = new JPanel();
    GAResultsNorthPanel = new JPanel();
    GAResultsScrollPane = new JScrollPane();
    GAResultsTable = new JTable();
    GALogPanel = new JPanel();
    GAScrollPane = new JScrollPane();
    GALogTextArea = new JTextArea();

    jfc = new JFileChooser();
    jfc.setCurrentDirectory(new File("."));

    ProgramMenu.setText(Strings.PROGRAM);
    ProgramMenu.setMnemonic(KeyEvent.VK_P);
    ProgramMenu.addActionListener(this);
    ForceGCMenuItem.setText(Strings.FORCEGC + Strings.dots);
    ForceGCMenuItem.addActionListener(this);
    ForceGCMenuItem.setMnemonic(KeyEvent.VK_F);
    ProgramMenu.add(ForceGCMenuItem);

    ProgramMenu.addSeparator();

    ExitMenuItem.setText(Strings.EXIT);
    ExitMenuItem.addActionListener(this);
    ExitMenuItem.setMnemonic(KeyEvent.VK_X);
    ProgramMenu.add(ExitMenuItem);

    MainMenuBar.add(ProgramMenu);

    HelpMenu.setText(Strings.HELP);
    HelpMenu.setMnemonic(KeyEvent.VK_H);
    TopicsMenuItem.setText(Strings.TOPICS + Strings.dots);
    TopicsMenuItem.addActionListener(this);
    TopicsMenuItem.setMnemonic(KeyEvent.VK_T);
    HelpMenu.add(TopicsMenuItem);

    HelpMenu.addSeparator();

    AboutMenuItem.setText(Strings.ABOUT + Strings.dots);
    AboutMenuItem.addActionListener(this);
    AboutMenuItem.setMnemonic(KeyEvent.VK_A);
    HelpMenu.add(AboutMenuItem);
    MainMenuBar.add(HelpMenu);

    getContentPane().add(MainMenuBar, BorderLayout.NORTH);

    setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
    addWindowListener(new WindowAdapter() {
	public void windowClosing(WindowEvent evt)
	{
	  exitForm(evt);
	}
      });

    Dimension prefDim = new Dimension(150, 25);

    DatabaseSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
  
    DatabasePanel.setLayout(new BorderLayout());
    DatabasePanel.setBorder(new TitledBorder(Strings.DBBORDERTITLE));

    DatabaseCenterPanel.setLayout(new GridLayout(3, 3));
    
    DBNameLabel.setPreferredSize(prefDim);
    DBNameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    DBNameLabel.setText("Database name :");
    DBNameLabelPanel.add(DBNameLabel);
    DatabaseCenterPanel.add(DBNameLabelPanel);

    DBNameTextField.setPreferredSize(prefDim);
    DBNameTextField.setText("zoo.data");
    DBNameTextField.setToolTipText(Strings.DBNAME_TIP);
    DBNamePanel.add(DBNameTextField);
    DatabaseCenterPanel.add(DBNamePanel);

    BrowseButton.setText("Browse");
    BrowseButton.addActionListener(this);
    BrowseButton.setMnemonic(KeyEvent.VK_B);
    BrowseButton.setToolTipText(Strings.BROWSE_TIP);
    BrowsePanel.add(BrowseButton);
    DatabaseCenterPanel.add(BrowsePanel);
    
    NRowsLabel.setPreferredSize(prefDim);
    NRowsLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    NRowsLabel.setText("Number of rows:");
    NRowsLabelPanel.add(NRowsLabel);
    DatabaseCenterPanel.add(NRowsLabelPanel);

    NRowsTextField.setPreferredSize(prefDim);
    NRowsTextField.setText("101");
    NRowsTextField.setToolTipText(Strings.NROWS_TIP);
    NRowsPanel.add(NRowsTextField);
    DatabaseCenterPanel.add(NRowsPanel);
    
    DatabaseCenterPanel.add(BogusLabel1);

    NAttrLabel.setPreferredSize(prefDim);
    NAttrLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    NAttrLabel.setText("Number of attributes :");
    NAttrLabelPanel.add(NAttrLabel);
    DatabaseCenterPanel.add(NAttrLabelPanel);

    NAttrTextField.setPreferredSize(prefDim);
    NAttrTextField.setText("17");
    NAttrTextField.setToolTipText(Strings.NATTR_TIP);
    NAttrPanel.add(NAttrTextField);
    DatabaseCenterPanel.add(NAttrPanel);

    DatabaseCenterPanel.add(BogusLabel2);

    DatabasePanel.add(DatabaseCenterPanel, BorderLayout.CENTER);

    OpenButton.setText("Open");
    OpenButton.addActionListener(this);
    OpenButton.setMnemonic(KeyEvent.VK_O);
    OpenButton.setToolTipText(Strings.OPENDB_TIP);
    DatabaseSouthPanel.add(OpenButton);

    DatabasePanel.add(DatabaseSouthPanel, BorderLayout.SOUTH);

    DatabaseSplitPane.setLeftComponent(DatabasePanel);
      
    Results.setLayout(new BorderLayout());

    // display cardinalities in the database text area by
    // double-clicking a row
    DBTable.addMouseListener(new MouseAdapter() 
      {
	public void mouseClicked(MouseEvent event)
	{
	  if (event.getClickCount() < 2)
	    return;

	  int rowNo = DBTable.rowAtPoint(event.getPoint());
	  DBTableModel dbModel = (DBTableModel)DBTable.getModel();
	  DBLogTextArea.append(dbModel.getValueAt(rowNo, 0) + Strings.endl);
	  DBLogTextArea.append(dbModel.getValueAt(rowNo, 1) + Strings.endl);
	}
      });

    DBTableScrollPane.setViewportView(DBTable);
    ResultsNorth.setLayout(new GridLayout(0, 1));
    ResultsNorth.setPreferredSize(new Dimension(900, 350));
    ResultsNorth.add(DBTableScrollPane);
    Results.add(ResultsNorth, BorderLayout.NORTH);
    
    DBLogTextArea.setLineWrap(true);
    DBLogTextArea.setText(Strings.DBINTRO);
    DBLogTextArea.setEditable(false);
    DatabaseScrollPane.setViewportView(DBLogTextArea);
    ResultsSouth.setPreferredSize(new Dimension(900, 100));
    ResultsSouth.setLayout(new GridLayout(0, 1));
    ResultsSouth.add(DatabaseScrollPane);
    Results.add(ResultsSouth, BorderLayout.SOUTH);

    DatabaseSplitPane.setRightComponent(Results);
      
    MainTabbedPane.addTab("Database", DatabaseSplitPane);
    MainTabbedPane.setEnabledAt(0, true);

    //////////// Generate /////////////////////
    GenerateSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
  
    GenerateDBPanel.setLayout(new BorderLayout());
    GenerateDBPanel.setBorder(new TitledBorder(Strings.GENDBBORDERTITLE));
  
    GenerateDBNorthPanel.setLayout(new GridLayout(6,3));
  
    GenDBNameLabel.setPreferredSize(prefDim);
    GenDBNameLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    GenDBNameLabel.setText("Database name :");
    GenDBNameLabelPanel.add(GenDBNameLabel);
    GenerateDBNorthPanel.add(GenDBNameLabelPanel);
  
    GenDBNameTextField.setPreferredSize(prefDim);
    GenDBNameTextField.setToolTipText(Strings.GENDBNAME_TIP);
    GenDBNamePanel.add(GenDBNameTextField);
    GenerateDBNorthPanel.add(GenDBNamePanel);
  
    UseDefaultNamingCheckBox.setText("Use default naming");
    UseDefaultNamingCheckBox.setPreferredSize(prefDim);
    UseDefaultNamingCheckBox.setToolTipText(Strings.USEDEFNAME_TIP);
    UseDefaultNamingPanel.add(UseDefaultNamingCheckBox);
    GenerateDBNorthPanel.add(UseDefaultNamingPanel);
  
    GenNRowsLabel.setPreferredSize(prefDim);
    GenNRowsLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    GenNRowsLabel.setText("Number of rows:");
    GenNRowsLabelPanel.add(GenNRowsLabel);
    GenerateDBNorthPanel.add(GenNRowsLabelPanel);
  
    GenNRowsTextField.setPreferredSize(prefDim);
    GenNRowsTextField.setToolTipText(Strings.NROWS_TIP);
    GenNRowsPanel.add(GenNRowsTextField);
    GenerateDBNorthPanel.add(GenNRowsPanel);
  
    GenerateDBNorthPanel.add(GenBogusLabel1);
  
    GenNAttrLabel.setPreferredSize(prefDim);
    GenNAttrLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    GenNAttrLabel.setText("Number of attributes :");
    GenNAttrLabelPanel.add(GenNAttrLabel);
    GenerateDBNorthPanel.add(GenNAttrLabelPanel);
  
    GenNAttrTextField.setPreferredSize(prefDim);
    GenNAttrTextField.setToolTipText(Strings.NATTR_TIP);
    GenNAttrPanel.add(GenNAttrTextField);
    GenerateDBNorthPanel.add(GenNAttrPanel);
  
    GenerateDBNorthPanel.add(GenBogusLabel2);
  
    GenNClassesLabel.setPreferredSize(prefDim);
    GenNClassesLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    GenNClassesLabel.setText("Number of classes :");
    GenNClassesLabelPanel.add(GenNClassesLabel);
    GenerateDBNorthPanel.add(GenNClassesLabelPanel);
  
    GenNClassesTextField.setPreferredSize(prefDim);
    GenNClassesTextField.setToolTipText(Strings.NCLASSES_TIP);
    GenNClassesPanel.add(GenNClassesTextField);
    GenerateDBNorthPanel.add(GenNClassesPanel);
  
    GenerateDBNorthPanel.add(GenBogusLabel3);
  
    GenRandomSeedLabel.setPreferredSize(prefDim);
    GenRandomSeedLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    GenRandomSeedLabel.setText("Random generator seed :");
    GenRandomSeedLabelPanel.add(GenRandomSeedLabel);
    GenerateDBNorthPanel.add(GenRandomSeedLabelPanel);

    GenRandomSeedTextField.setPreferredSize(prefDim);
    GenRandomSeedTextField.setToolTipText(Strings.RANDSEED_TIP);
    GenRandomSeedPanel.add(GenRandomSeedTextField);
    GenerateDBNorthPanel.add(GenRandomSeedPanel);
  
    GenerateDBNorthPanel.add(GenBogusLabel4);
  
    GenerateLargeCheckBox.setHorizontalAlignment(SwingConstants.RIGHT);
    GenerateLargeCheckBox.setPreferredSize(prefDim);
    GenerateLargeCheckBox.setText("Generate one large class");
    GenerateLargeCheckBox.setToolTipText(Strings.GENLARGE_TIP);
    GenerateLargePanel.add(GenerateLargeCheckBox);
    GenerateDBNorthPanel.add(GenerateLargeCheckBox);

    GenerateDBNorthPanel.add(GenBogusLabel5);
  
    GenerateDBNorthPanel.add(GenBogusLabel6);
  
    GenerateDBPanel.add(GenerateDBNorthPanel, BorderLayout.NORTH);
  
    GenerateButton.setText("Generate");
    GenerateButton.addActionListener(this);
    GenerateButton.setMnemonic(KeyEvent.VK_G);
    GenerateButton.setToolTipText(Strings.GEN_TIP);
    GenerateDBSouthPanel.add(GenerateButton);

    GenAbortButton.setText("Abort");
    GenAbortButton.setEnabled(false);
    GenAbortButton.addActionListener(this);
    GenAbortButton.setMnemonic(KeyEvent.VK_A);
    GenAbortButton.setToolTipText(Strings.GENABORT_TIP);
    GenerateDBSouthPanel.add(GenAbortButton);
  
    GenProgressBar.setStringPainted(true);
    GenProgressBarPanel.add(GenProgressBar);
    GenerateDBSouthPanel.add(GenProgressBarPanel);

    GenerateDBPanel.add(GenerateDBSouthPanel, BorderLayout.SOUTH);
  
    GenerateSplitPane.setLeftComponent(GenerateDBPanel);

    GenResultsPanel.setLayout(new BorderLayout());

    // display cardinalities in the generated database text area by
    // double-clicking a row
    GenDBTable.addMouseListener(new MouseAdapter() 
      {
	public void mouseClicked(MouseEvent event)
	{
	  if (event.getClickCount() < 2)
	    return;

	  int rowNo = GenDBTable.rowAtPoint(event.getPoint());
	  DBTableModel dbModel = (DBTableModel)GenDBTable.getModel();
	  GenLogTextArea.append(dbModel.getValueAt(rowNo, 0) + Strings.endl);
	  GenLogTextArea.append(dbModel.getValueAt(rowNo, 1) + Strings.endl);
	}
      });

    GenDBTableScrollPane.setViewportView(GenDBTable);
    GenResultsNorthPanel.setLayout(new GridLayout(0, 1));
    GenResultsNorthPanel.setPreferredSize(new Dimension(800, 200));
    GenResultsNorthPanel.add(GenDBTableScrollPane);
    GenResultsPanel.add(GenResultsNorthPanel, BorderLayout.NORTH);

    GenLogTextArea.setLineWrap(true);
    GenLogTextArea.setText("Generate a synthetic database" + Strings.endl);
    GenLogTextArea.setEditable(false);
    GenLogScrollPane.setViewportView(GenLogTextArea);
    GenResultsSouthPanel.setLayout(new GridLayout(0, 1));
    GenResultsSouthPanel.setPreferredSize(new Dimension(900, 150));
    GenResultsSouthPanel.add(GenLogScrollPane);
    GenResultsPanel.add(GenResultsSouthPanel, BorderLayout.SOUTH);
  
    GenerateSplitPane.setRightComponent(GenResultsPanel);

    MainTabbedPane.addTab("Generate", GenerateSplitPane);
    MainTabbedPane.setEnabledAt(1, true);

    ////////// GA /////////////////////////////
    GAHorizontalSplitPane.setOrientation(JSplitPane.HORIZONTAL_SPLIT);

    GASplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
      
    GAPanel.setLayout(new BorderLayout());
    GAPanel.setBorder(new TitledBorder(Strings.GABORDERTITLE));

    GACenterPanel.setPreferredSize(new Dimension(600, 300));
    GACenterPanel.setLayout(new java.awt.GridLayout(10, 4));

    PopSizeLabel.setPreferredSize(prefDim);
    PopSizeLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    PopSizeLabel.setText("Population size :");
    PopSizeLabelPanel.add(PopSizeLabel);
    GACenterPanel.add(PopSizeLabelPanel);

    PopSizeTextField.setPreferredSize(prefDim);
    PopSizeTextField.setText("100");
    PopSizeTextField.setToolTipText(Strings.POPSIZE_TIP);
    PopSizePanel.add(PopSizeTextField);
    GACenterPanel.add(PopSizePanel);

    CrossTypeLabel.setPreferredSize(prefDim);
    CrossTypeLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    CrossTypeLabel.setText("Crossover type :");
    CrossTypeLabelPanel.add(CrossTypeLabel);
    GACenterPanel.add(CrossTypeLabelPanel);

    CrossTypeComboBox.setPreferredSize(prefDim);
    CrossTypeComboBox.addItem(Strings.CROSS_RAND);
    CrossTypeComboBox.addItem(Strings.CROSS_X_2RAND_CLASS);
    CrossTypeComboBox.addItem(Strings.CROSS_AM_X_BEST_CLASS);
    CrossTypeComboBox.addItem(Strings.CROSS_AM_X_BEST_WORST);
    CrossTypeComboBox.addItem(Strings.CROSS_AM_X_2RAND_CLASS);
    CrossTypeComboBox.addItemListener(this);
    CrossTypeComboBox.setToolTipText(Strings.CROSSTYPE_TIP);
    CrossTypePanel.add(CrossTypeComboBox);
    GACenterPanel.add(CrossTypePanel);

    NClassesClustLabel.setPreferredSize(prefDim);
    NClassesClustLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    NClassesClustLabel.setText("Number of classes :");
    NClassesClustLabelPanel.add(NClassesClustLabel);
    GACenterPanel.add(NClassesClustLabelPanel);

    NClassesClustTextField.setPreferredSize(prefDim);
    NClassesClustTextField.setText("7");
    NClassesClustTextField.setToolTipText(Strings.NCLASSES_TIP);
    NClassesClustPanel.add(NClassesClustTextField);
    GACenterPanel.add(NClassesClustPanel);

    DistrTypeLabel.setPreferredSize(prefDim);
    DistrTypeLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    DistrTypeLabel.setText("Distribution type :");
    DistrTypeLabelPanel.add(DistrTypeLabel);
    GACenterPanel.add(DistrTypeLabelPanel);

    DistrTypeComboBox.setPreferredSize(prefDim);
    DistrTypeComboBox.addItem(Strings.DISTRIB_NONE);
    DistrTypeComboBox.addItem(Strings.DISTRIB_RAND);
    DistrTypeComboBox.addItem(Strings.DISTRIB_TO_EVEN);
    DistrTypeComboBox.setToolTipText(Strings.DISTRTYPE_TIP);
    DistrTypePanel.add(DistrTypeComboBox);
    GACenterPanel.add(DistrTypePanel);

    CrossRateLabel.setPreferredSize(prefDim);
    CrossRateLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    CrossRateLabel.setText("Crossover rate :");
    CrossRateLabelPanel.add(CrossRateLabel);
    GACenterPanel.add(CrossRateLabelPanel);

    CrossRateTextField.setPreferredSize(prefDim);
    CrossRateTextField.setText("0.8");
    CrossRateTextField.setToolTipText(Strings.CROSSRATE_TIP);
    CrossRatePanel.add(CrossRateTextField);
    GACenterPanel.add(CrossRatePanel);

    MutTypeLabel.setPreferredSize(prefDim);
    MutTypeLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    MutTypeLabel.setText("Mutation type :");
    MutTypeLabelPanel.add(MutTypeLabel);
    GACenterPanel.add(MutTypeLabelPanel);

    MutTypeComboBox.setPreferredSize(prefDim);
    MutTypeComboBox.addItem(Strings.MUT_RAND);
    MutTypeComboBox.addItem(Strings.MUT_MOVE_ELEM);
    MutTypeComboBox.addItem(Strings.MUT_SWAP_ELEM);
    MutTypeComboBox.setToolTipText(Strings.MUTTYPE_TIP);
    MutTypePanel.add(MutTypeComboBox);
    GACenterPanel.add(MutTypePanel);

    MutRateLabel.setPreferredSize(prefDim);
    MutRateLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    MutRateLabel.setText("Mutation rate :");
    MutRateLabelPanel.add(MutRateLabel);
    GACenterPanel.add(MutRateLabelPanel);

    MutRateTextField.setPreferredSize(prefDim);
    MutRateTextField.setText("0.1");
    MutRateTextField.setToolTipText(Strings.MUTRATE_TIP);
    MutRatePanel.add(MutRateTextField);
    GACenterPanel.add(MutRatePanel);

    ClassFitnessLabel.setPreferredSize(prefDim);
    ClassFitnessLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    ClassFitnessLabel.setText("Class fitness type :");
    ClassFitnessLabelPanel.add(ClassFitnessLabel);
    GACenterPanel.add(ClassFitnessLabelPanel);

    ClassFitnessComboBox.setPreferredSize(prefDim);
    ClassFitnessComboBox.addItem(Strings.CF_SYM_DIFF);
    ClassFitnessComboBox.addItem(Strings.CF_PROD);
    ClassFitnessComboBox.addItem(Strings.CF_DIV);
    ClassFitnessComboBox.addItem(Strings.CF_POW);
    ClassFitnessComboBox.setToolTipText(Strings.CLASSFITNESSTYPE_TIP);
    ClassFitnessPanel.add(ClassFitnessComboBox);
    GACenterPanel.add(ClassFitnessPanel);

    FitnessThresholdLabel.setPreferredSize(prefDim);
    FitnessThresholdLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    FitnessThresholdLabel.setText("Fitness threshold :");
    FitnessThresholdLabelPanel.add(FitnessThresholdLabel);
    GACenterPanel.add(FitnessThresholdLabelPanel);

    FitnessThresholdTextField.setPreferredSize(prefDim);
    FitnessThresholdTextField.setText("0.0001");
    FitnessThresholdTextField.setToolTipText(Strings.FTHRES_TIP);
    FitnessThresholdPanel.add(FitnessThresholdTextField);
    GACenterPanel.add(FitnessThresholdPanel);
    
    EntropyMeasureLabel.setPreferredSize(prefDim);
    EntropyMeasureLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    EntropyMeasureLabel.setText("Entropy measure :");
    EntropyMeasureLabelPanel.add(EntropyMeasureLabel);
    GACenterPanel.add(EntropyMeasureLabelPanel);

    EntropyMeasureComboBox.setPreferredSize(prefDim);
    EntropyMeasureComboBox.addItem(Strings.GINI);
    EntropyMeasureComboBox.addItem(Strings.ENTROPY);
    EntropyMeasureComboBox.addItem(Strings.PEAK);
    //EntropyMeasureComboBox.addItem(Strings.CIRCLE);
    //EntropyMeasureComboBox.addItem(Strings.SINE);
    //EntropyMeasureComboBox.addItem(Strings.SQ);
    EntropyMeasureComboBox.addItem(Strings.GE);
    EntropyMeasureComboBox.setToolTipText(Strings.ENTROPY_TIP);
    EntropyMeasurePanel.add(EntropyMeasureComboBox);
    GACenterPanel.add(EntropyMeasurePanel);
    
    ConsecItrsLabel.setPreferredSize(prefDim);
    ConsecItrsLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    ConsecItrsLabel.setText("Consecutive iterations :");
    ConsecItrsLabelPanel.add(ConsecItrsLabel);
    GACenterPanel.add(ConsecItrsLabelPanel);

    ConsecItrsTextField.setPreferredSize(prefDim);
    ConsecItrsTextField.setText("100");
    ConsecItrsTextField.setToolTipText(Strings.CITRS_TIP);
    ConsecItrsPanel.add(ConsecItrsTextField);
    GACenterPanel.add(ConsecItrsPanel);
    
    FitnessMeasureLabel.setPreferredSize(prefDim);
    FitnessMeasureLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    FitnessMeasureLabel.setText("Fitness measure :");
    FitnessMeasureLabelPanel.add(FitnessMeasureLabel);
    GACenterPanel.add(FitnessMeasureLabelPanel);

    FitnessMeasureComboBox.setPreferredSize(prefDim);
    FitnessMeasureComboBox.addItem(Strings.FM_PA_P);
    FitnessMeasureComboBox.addItem(Strings.FM_P_PA);
    FitnessMeasureComboBox.addItem(Strings.FM_BOTH);
    FitnessMeasureComboBox.addItem(Strings.FM_BOTH_SCALED);
    FitnessMeasureComboBox.addItem(Strings.FM_NORM_W);
    FitnessMeasureComboBox.addItem(Strings.FM_WE);
    FitnessMeasureComboBox.addItem(Strings.FM_ALTERNATE_HAVG);
    FitnessMeasureComboBox.addItem(Strings.FM_ALTERNATE);
    FitnessMeasureComboBox.addItem(Strings.FM_MOD);
    FitnessMeasureComboBox.addItem(Strings.FM_Q);
    FitnessMeasureComboBox.addItem(Strings.FM_L);
    FitnessMeasureComboBox.addItem(Strings.FM_QR);
    FitnessMeasureComboBox.addItem(Strings.FM_LR);
    FitnessMeasureComboBox.addItem(Strings.FM_Q_QR);
    FitnessMeasureComboBox.addItemListener(this);
    FitnessMeasureComboBox.setToolTipText(Strings.FM_TIP);
    FitnessMeasurePanel.add(FitnessMeasureComboBox);
    GACenterPanel.add(FitnessMeasurePanel);
    
    RandomSeedGALabel.setPreferredSize(prefDim);
    RandomSeedGALabel.setHorizontalAlignment(SwingConstants.RIGHT);
    RandomSeedGALabel.setText("Random seed :");
    RandomSeedGALabelPanel.add(RandomSeedGALabel);
    GACenterPanel.add(RandomSeedGALabelPanel);

    RandomSeedGATextField.setPreferredSize(prefDim);
    RandomSeedGATextField.setText("1");
    RandomSeedGATextField.setToolTipText(Strings.RANDSEED_TIP);
    RandomSeedGAPanel.add(RandomSeedGATextField);
    GACenterPanel.add(RandomSeedGAPanel);
    
    MinimizationLabel.setPreferredSize(prefDim);
    MinimizationLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    MinimizationLabel.setText("Optimization type :");
    MinimizationLabelPanel.add(MinimizationLabel);
    GACenterPanel.add(MinimizationLabelPanel);

    MinimizationComboBox.setPreferredSize(prefDim);
    MinimizationComboBox.addItem(Strings.FO_MIN);
    MinimizationComboBox.addItem(Strings.FO_MAX);
    MinimizationComboBox.setToolTipText(Strings.OPT_TIP);
    MinimizationPanel.add(MinimizationComboBox);
    GACenterPanel.add(MinimizationPanel);

    UseTargetCheckBox.setHorizontalAlignment(SwingConstants.RIGHT);
    UseTargetCheckBox.setPreferredSize(prefDim);
    UseTargetCheckBox.setText("Use target");
    UseTargetCheckBox.addItemListener(this);
    UseTargetCheckBox.setToolTipText(Strings.USETARGET_TIP);
    UseTargetPanel.add(UseTargetCheckBox);
    GACenterPanel.add(UseTargetPanel);

    TargetIDLabel.setPreferredSize(prefDim);
    TargetIDLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    TargetIDLabel.setText("Target id :");
    TargetIDLabel.setEnabled(false);
    TargetIDLabelPanel.add(TargetIDLabel);
    GACenterPanel.add(TargetIDLabelPanel);

    TargetIDTextField.setPreferredSize(prefDim);
    TargetIDTextField.setEnabled(false);
    TargetIDTextField.setToolTipText(Strings.TARGETID_TIP);
    TargetIDPanel.add(TargetIDTextField);
    GACenterPanel.add(TargetIDPanel);

    GACenterPanel.add(BogusLabel3);

    UseWeightsCheckBox.setHorizontalAlignment(SwingConstants.RIGHT);
    UseWeightsCheckBox.setPreferredSize(prefDim);
    UseWeightsCheckBox.setText("Use weights");
    UseWeightsCheckBox.setEnabled(false);
    UseWeightsCheckBox.addItemListener(this);
    UseWeightsCheckBox.setToolTipText(Strings.USEWEIGHTS_TIP);
    UseWeightsPanel.add(UseWeightsCheckBox);
    GACenterPanel.add(UseWeightsPanel);

    SampleDBPctLabel.setPreferredSize(prefDim);
    SampleDBPctLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    SampleDBPctLabel.setText("Sampling percent:");
    SampleDBPctLabel.setEnabled(false);
    SampleDBPctLabelPanel.add(SampleDBPctLabel);
    GACenterPanel.add(SampleDBPctLabelPanel);

    SampleDBPctTextField.setPreferredSize(prefDim);
    SampleDBPctTextField.setEnabled(false);
    SampleDBPctTextField.setToolTipText(Strings.SAMPLEDBPCT_TIP);
    SampleDBPctPanel.add(SampleDBPctTextField);
    GACenterPanel.add(SampleDBPctPanel);
      
    GACenterPanel.add(BogusLabel4);

    ExcludeAttrCheckBox.setHorizontalAlignment(SwingConstants.RIGHT);
    ExcludeAttrCheckBox.setPreferredSize(prefDim);
    ExcludeAttrCheckBox.setText("Exclude attributes");
    ExcludeAttrCheckBox.setEnabled(false);
    ExcludeAttrCheckBox.addItemListener(this);
    ExcludeAttrCheckBox.setToolTipText(Strings.EXCLUDEATTR_TIP);
    ExcludeAttrPanel.add(ExcludeAttrCheckBox);
    GACenterPanel.add(ExcludeAttrPanel);

    NRemAttrLabel.setPreferredSize(prefDim);
    NRemAttrLabel.setHorizontalAlignment(SwingConstants.RIGHT);
    NRemAttrLabel.setText("No. remaining attributes :");
    NRemAttrLabel.setEnabled(false);
    NRemAttrLabelPanel.add(NRemAttrLabel);
    GACenterPanel.add(NRemAttrLabelPanel);

    NRemAttrTextField.setPreferredSize(prefDim);
    NRemAttrTextField.setEnabled(false);
    NRemAttrTextField.setToolTipText(Strings.NREMATTR_TIP);
    NRemAttrPanel.add(NRemAttrTextField);
    GACenterPanel.add(NRemAttrPanel);
      
    GACenterPanel.add(BogusLabel5);

    GAPanel.add(GACenterPanel, BorderLayout.CENTER);

    ClusterButton.setText("Cluster !");
    ClusterButton.addActionListener(this);
    ClusterButton.setMnemonic(KeyEvent.VK_C);
    ClusterButton.setToolTipText(Strings.CLUSTER_TIP);
    ClusterPanel.add(ClusterButton);

    ClusterAbortButton.setText("Abort");
    ClusterAbortButton.setEnabled(false);
    ClusterAbortButton.addActionListener(this);
    ClusterAbortButton.setMnemonic(KeyEvent.VK_A);
    ClusterAbortButton.setToolTipText(Strings.CLUSTERABORT_TIP);
    ClusterPanel.add(ClusterAbortButton);
    GASouthPanel.add(ClusterPanel);
    
    GAPanel.add(GASouthPanel, BorderLayout.SOUTH);

    GASplitPane.setLeftComponent(GAPanel);

    GAResultsPanel.setLayout(new BorderLayout());

    // display cardinalities in the database text area by
    // double-clicking a row
    GAResultsTable.addMouseListener(new MouseAdapter() 
      {
	public void mouseClicked(MouseEvent event)
	{
	  if (event.getClickCount() < 2)
	    return;

	  int rowNo = GAResultsTable.rowAtPoint(event.getPoint());
	  ResultsTableModel tableModel = 
	    (ResultsTableModel)GAResultsTable.getModel();

	  if (tableModel instanceof GAResultsModel)
	    {
	      if (rowNo == 4)
		{
		  GALogTextArea.append(Strings.CLUSTCLASSCARD + Strings.endl);
		  String classInfo = (String)tableModel.getValueAt(rowNo, 0);
		  GALogTextArea.append(classInfo + Strings.endl);
		}
	    }
	  else if (tableModel instanceof GAResultsReferenceModel)
	    {
	      if (rowNo == 3)
		{
		  GALogTextArea.append(Strings.REFCLASSCARD + Strings.endl);
		  String classInfo = (String)tableModel.getValueAt(rowNo, 0);
		  GALogTextArea.append(classInfo + Strings.endl);
		  GALogTextArea.append(Strings.CLUSTCLASSCARD + Strings.endl);
		  classInfo = (String)tableModel.getValueAt(rowNo, 1);
		  GALogTextArea.append(classInfo + Strings.endl);
		}
	      else if (rowNo >= 8 && rowNo < 8 + refPart.getNoClasses())
		{
		  // get the target class from this row
		  String refClassInfo = 
		    (String)tableModel.getValueAt(rowNo, 0);
		  String intersections = 
		    (String)tableModel.getValueAt(rowNo, 1);
		  GALogTextArea.append("Reference class (cardinality): " 
				       + refClassInfo + Strings.endl);
		  GALogTextArea.append("Intersections with clustering"
				       + " classes:" + Strings.endl);
		  GALogTextArea.append(intersections + Strings.endl);
		}
	    }
	}
      });
    
    GAResultsScrollPane.setViewportView(GAResultsTable);
    GAResultsNorthPanel.setLayout(new GridLayout(0, 1));
    GAResultsNorthPanel.add(GAResultsScrollPane);
    GAResultsNorthPanel.setPreferredSize(new Dimension(600, 200));
    GAResultsPanel.add(GAResultsNorthPanel, BorderLayout.NORTH);

    GASplitPane.setRightComponent(GAResultsPanel);

    GASplitPane.setPreferredSize(new Dimension(600, 500));
    GAHorizontalSplitPane.setLeftComponent(GASplitPane);

    GALogTextArea.setLineWrap(true); 
    GALogTextArea.setText("Select clustering parameters" + Strings.endl);
    GALogTextArea.setEditable(false);
    GAScrollPane.setViewportView(GALogTextArea);
    GAScrollPane.setPreferredSize(new Dimension(350, 500));
    GALogPanel.setLayout(new GridLayout(0, 1));
    GALogPanel.add(GAScrollPane);
    GAHorizontalSplitPane.setRightComponent(GALogPanel);
      
    MainTabbedPane.addTab("GA", GAHorizontalSplitPane);
    MainTabbedPane.setEnabledAt(2, false);
  
    getContentPane().add(MainTabbedPane);
      
    pack();
  }

  // listeners
  public void itemStateChanged(ItemEvent event) 
  {
    if (event.getSource() == UseTargetCheckBox) 
      {
	boolean state = UseTargetCheckBox.isSelected();
	TargetIDLabel.setEnabled(state);
	TargetIDTextField.setEnabled(state);
      }
    else if (event.getSource() == UseWeightsCheckBox) 
      {
	boolean state = UseWeightsCheckBox.isSelected();
	SampleDBPctLabel.setEnabled(state);
	SampleDBPctTextField.setEnabled(state);
      }
    else if (event.getSource() == ExcludeAttrCheckBox) 
      {
	boolean state = ExcludeAttrCheckBox.isSelected();
	NRemAttrLabel.setEnabled(state);
	NRemAttrTextField.setEnabled(state);
      }
    else if (event.getSource() == FitnessMeasureComboBox)
      {
	String selection = (String)FitnessMeasureComboBox.getSelectedItem();
	if (selection.equals(Strings.FM_NORM_W))
	  {
	    UseWeightsCheckBox.setEnabled(true);
	    UseWeightsCheckBox.setSelected(false);
	    ExcludeAttrCheckBox.setEnabled(false);
	    ExcludeAttrCheckBox.setSelected(false);
	  }
	else if (selection.equals(Strings.FM_WE))
	  {
	    UseWeightsCheckBox.setEnabled(true);
	    UseWeightsCheckBox.setSelected(false);
	    ExcludeAttrCheckBox.setEnabled(true);
	    ExcludeAttrCheckBox.setSelected(false);
	  }
	else
	  {
	    UseWeightsCheckBox.setEnabled(false);
	    UseWeightsCheckBox.setSelected(false);
	    SampleDBPctLabel.setEnabled(false);
	    SampleDBPctTextField.setEnabled(false);
	    
	    ExcludeAttrCheckBox.setEnabled(false);
	    ExcludeAttrCheckBox.setSelected(false);
	    NRemAttrLabel.setEnabled(false);
	    NRemAttrTextField.setEnabled(false);
	  }
      }
    else if (event.getSource() == CrossTypeComboBox)
      {
	// ignore the DESELECTED event
	if (event.getStateChange() == ItemEvent.SELECTED)
	  {
	    String selection = (String)CrossTypeComboBox.getSelectedItem();
	    if (selection.equals(Strings.CROSS_RAND) == false
		&& selection.equals(Strings.CROSS_X_2RAND_CLASS) == false)
	      {
		GALogTextArea.append(Strings.DISTRNEEDED + Strings.endl);
		DistrTypeComboBox.setSelectedIndex(1);
	      }
	  }
      }
  }
  
  public void actionPerformed(ActionEvent event)
  {
    if (event.getSource() == OpenButton)
      {
	DBName = DBNameTextField.getText();
	try
	  {
	    FileReader f = new FileReader(DBName);   
	  }
	catch(FileNotFoundException e)
	  {
	    DBLogTextArea.append(Strings.ERROR + e + Strings.endl);
	    DBNameTextField.setText("");
	    DBNameTextField.requestFocus();
	    return;
	  }

	try
	  {
	    // get parameters
	    nRows = JTextTools.getInt(NRowsTextField, DBLogTextArea, 
				      Strings.NROWSERRMSG);
	    if (nRows <= 0)
	      {
		DBLogTextArea.append(Strings.NROWSPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(NRowsTextField);
	      }
            
	    nCols = JTextTools.getInt(NAttrTextField, DBLogTextArea,
				      Strings.NATTRERRMSG);
	    if (nCols <= 0)
	      {
		DBLogTextArea.append(Strings.NATTRPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(NAttrTextField);
	      }
	  }
	catch (IllegalArgumentException invalid_input)
	  {
	    // wait for user to input something reasonable
	    return;
	  }

	output = new StringBuffer();
	Vector v;
	try
	  {
	    v = DBTransform.transform(DBName, nRows, nCols, output);
	  }
	catch(IOException e)
	  {
	    DBLogTextArea.append(Strings.ERROR + e + Strings.endl);
	    return;
	  }
	// database transformation was successful
	if (output.length() > 0)
	  DBLogTextArea.append(output.toString());
	nRows = ((Integer)v.elementAt(0)).intValue();
	nCols = ((Integer)v.elementAt(1)).intValue();
	db = new Partition[nCols];
	db_copy = new Partition[nCols];

	for (int i = 0; i < nCols; i++)
	  {
	    db[i] = (Partition)v.elementAt(i+2);
	    db_copy[i] = db[i];
	  }

	DBLogTextArea.append("Currently selected database: " + DBName);
	DBLogTextArea.append("(" + nRows + " rows " + nCols 
			     + " attributes)" + Strings.endl);
	
	DBTable.setModel(new DBTableModel());
	MainTabbedPane.setEnabledAt(2, true);
	flipTarget = true; // we get a new database we can flip the
	// target if required
      }
    else if (event.getSource() == BrowseButton)
      {
	DBNameTextField.setText("");
	NRowsTextField.setText("");
	NAttrTextField.setText("");
	
	int returnVal = jfc.showOpenDialog(this);	
	if (returnVal == JFileChooser.APPROVE_OPTION)
	  {
	    File file = jfc.getSelectedFile();
	    DBName = file.getPath();
	    DBNameTextField.setText(file.getName());
	  }
      }
    else if (event.getSource() == ClusterButton)
      {
	// get parameters
	try
	  {
	    popSize = JTextTools.getInt(PopSizeTextField, GALogTextArea,
					Strings.POPSIZEERRMSG);
	    if (popSize <= 0)
	      {
		GALogTextArea.append(Strings.POPSIZEPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(PopSizeTextField);
	      }
            
	    K = JTextTools.getInt(NClassesClustTextField, GALogTextArea,
				  Strings.KERRMSG);
	    if (K < 2)
	      {
		GALogTextArea.append(Strings.KMORETHAN2 + Strings.endl);
		JTextTools.dealWithInvalidValue(NClassesClustTextField);
	      }
	    
	    crossoverRate = JTextTools.getDouble(CrossRateTextField, 
						 GALogTextArea, 
						 Strings.CROSSRATEERRMSG);
	    if (crossoverRate < 0 || crossoverRate > 1)
	      {
		GALogTextArea.append(Strings.CROSSRATEINTERVAL + Strings.endl);
		JTextTools.dealWithInvalidValue(CrossRateTextField);
	      }

	    mutationRate = JTextTools.getDouble(MutRateTextField, GALogTextArea, 
						Strings.MUTRATEERRMSG);
	    if (mutationRate < 0 || mutationRate > 1)
	      {
		GALogTextArea.append(Strings.MUTRATEINTERVAL + Strings.endl);
		JTextTools.dealWithInvalidValue(MutRateTextField);
	      }

	    if (mutationRate + crossoverRate == 1)
	      {
		GALogTextArea.append(Strings.CROSSMUTSUM + Strings.endl);
		if (crossoverRate > mutationRate)
		  {
		    GALogTextArea.append(Strings.ADJUSTCROSS + Strings.endl);
		    JTextTools.dealWithInvalidValue(CrossRateTextField);
		  }
		else
		  {
		    GALogTextArea.append(Strings.ADJUSTMUT + Strings.endl);
		    JTextTools.dealWithInvalidValue(MutRateTextField);
		  }
	      }

	    String selection = (String)ClassFitnessComboBox.getSelectedItem();
	    if (selection.equals(Strings.CF_SYM_DIFF))
	      classFitnessType = Partition.CF_SYM_DIFF;
	    else if (selection.equals(Strings.CF_PROD))
	      classFitnessType = Partition.CF_PROD;
	    else if (selection.equals(Strings.CF_DIV))
	      classFitnessType = Partition.CF_DIV;
	    else
	      classFitnessType = Partition.CF_POW;

	    selection = (String)CrossTypeComboBox.getSelectedItem();
	    if (selection.equals(Strings.CROSS_RAND))
	      crossoverType = Chromosome.CROSS_RAND;
	    else if (selection.equals(Strings.CROSS_X_2RAND_CLASS))
	      crossoverType = Chromosome.CROSS_X_2RAND_CLASS;
	    else if (selection.equals(Strings.CROSS_AM_X_BEST_CLASS))
	      crossoverType = Chromosome.CROSS_AM_X_BEST_CLASS;
	    else if (selection.equals(Strings.CROSS_AM_X_BEST_WORST))
	      crossoverType = Chromosome.CROSS_AM_X_BEST_WORST;
	    else // if (selection.equals(Strings.CROSS_AM_X_2RAND_CLASS))
	      crossoverType = Chromosome.CROSS_AM_X_2RAND_CLASS;

	    selection = (String)MutTypeComboBox.getSelectedItem();
	    if (selection.equals(Strings.MUT_RAND))
	      mutationType = Chromosome.MUT_RAND;
	    else if (selection.equals(Strings.MUT_MOVE_ELEM))
	      mutationType = Chromosome.MUT_MOVE_ELEM;
	    else // if (selection.equals(Strings.MUT_SWAP_ELEM))
	      mutationType = Chromosome.MUT_SWAP_ELEM;

	    selection = (String)DistrTypeComboBox.getSelectedItem();
	    if (selection.equals(Strings.DISTRIB_NONE))
	      distributionType = Chromosome.DISTRIB_NONE;
	    else if (selection.equals(Strings.DISTRIB_RAND))
	      distributionType = Chromosome.DISTRIB_RAND;
	    else //if (selection.equals(Strings.DISTRIB_TO_EVEN))
	      distributionType = Chromosome.DISTRIB_TO_EVEN;

	    selection = (String)EntropyMeasureComboBox.getSelectedItem();
	    if (selection.equals(Strings.GINI))
	      entropyMeasure = ImpurityMeasure.GINI;
	    else if (selection.equals(Strings.ENTROPY))
	      entropyMeasure = ImpurityMeasure.ENTROPY;
	    else if (selection.equals(Strings.PEAK))
	      entropyMeasure = ImpurityMeasure.PEAK;
	    else if (selection.equals(Strings.CIRCLE))
	      entropyMeasure = ImpurityMeasure.CIRCLE;
	    else if (selection.equals(Strings.SINE))
	      entropyMeasure = ImpurityMeasure.SINE;
	    else if (selection.equals(Strings.SQ))
	      entropyMeasure = ImpurityMeasure.SQ;
	    else // if (selection.equals(Strings.GE))
	      entropyMeasure = ImpurityMeasure.GE;

	    selection = (String)FitnessMeasureComboBox.getSelectedItem();
	    if (selection.equals(Strings.FM_PA_P))
	      fitnessMeasure = Global.FM_PA_P;
	    else if (selection.equals(Strings.FM_P_PA))
	      fitnessMeasure = Global.FM_P_PA;
	    else if (selection.equals(Strings.FM_BOTH))
	      fitnessMeasure = Global.FM_BOTH;
	    else if (selection.equals(Strings.FM_BOTH_SCALED))
	      fitnessMeasure = Global.FM_BOTH_SCALED;
	    else if (selection.equals(Strings.FM_Q))
	      fitnessMeasure = Global.FM_Q;
	    else if (selection.equals(Strings.FM_L))
	      fitnessMeasure = Global.FM_L;
	    else if (selection.equals(Strings.FM_QR))
	      fitnessMeasure = Global.FM_QR;
	    else if (selection.equals(Strings.FM_LR))
	      fitnessMeasure = Global.FM_LR;
	    else if (selection.equals(Strings.FM_Q_QR))
	      fitnessMeasure = Global.FM_Q_QR;
	    else if (selection.equals(Strings.FM_ALTERNATE_HAVG))
	      fitnessMeasure = Global.FM_ALTERNATE_HAVG;
	    else if (selection.equals(Strings.FM_ALTERNATE))
	      fitnessMeasure = Global.FM_ALTERNATE;
	    else if (selection.equals(Strings.FM_MOD))
	      fitnessMeasure = Global.FM_MOD;
	    else if (selection.equals(Strings.FM_NORM_W))
	      fitnessMeasure = Global.FM_NORM_W;
	    else // if (selection.equals(Strings.FM_WE))
	      fitnessMeasure = Global.FM_WE;
	    
	    fitnessThreshold = JTextTools.getDouble(FitnessThresholdTextField,
						    GALogTextArea, 
						    Strings.FTHRESERRMSG);
	    if (fitnessThreshold < 0)
	      {
		GALogTextArea.append(Strings.FTHRESPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(FitnessThresholdTextField);
	      }

	    consecItrs = JTextTools.getInt(ConsecItrsTextField, GALogTextArea,
					   Strings.CITRSERRMSG);
	    if (consecItrs <= 0)
	      {
		GALogTextArea.append(Strings.CITRSPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(ConsecItrsTextField);
	      }
	    
	    randseed = JTextTools.getInt(RandomSeedGATextField, GALogTextArea,
					   Strings.RANDSEEDERRMSG);
	    if (randseed < 0)
	      {
		GALogTextArea.append(Strings.RANDSEEDPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(RandomSeedGATextField);
	      }

	    useTarget = 0;
	    targetId = 0;
	    if (UseTargetCheckBox.isSelected() == true)
	      {
		useTarget = 1;
		targetId = JTextTools.getInt(TargetIDTextField, GALogTextArea,
					     Strings.TIDERRMSG);
		if (targetId < 0)
		  {
		    GALogTextArea.append(Strings.TIDPOSITIVE + Strings.endl);
		    JTextTools.dealWithInvalidValue(TargetIDTextField);
		  }
	      }

	    useWeights = 0;
	    sampleDBPct = 0;
	    if (UseWeightsCheckBox.isSelected() == true)
	      {
		useWeights = 1;
		sampleDBPct = JTextTools.getDouble(SampleDBPctTextField, 
						   GALogTextArea,
						   Strings.SPCTERRMSG);
		if (sampleDBPct <= 0)
		  {
		    GALogTextArea.append(Strings.SPCTINTERVAL + Strings.endl);
		    JTextTools.dealWithInvalidValue(SampleDBPctTextField);
		  }
	      }

	    excludeAttr = 0;
	    noRemAttr = 0;
	    if (ExcludeAttrCheckBox.isSelected() == true)
	      {
		excludeAttr = 1;
		noRemAttr = JTextTools.getInt(NRemAttrTextField, GALogTextArea,
					      Strings.NRATTRERRMSG);
		if (noRemAttr <= 0)
		  {
		    GALogTextArea.append(Strings.NRATTRPOSITIVE 
					 + Strings.endl);
		    JTextTools.dealWithInvalidValue(NRemAttrTextField);
		  }
	      }	    
	    
	    selection = (String)MinimizationComboBox.getSelectedItem();
	    if (selection.equals(Strings.FO_MIN))
	      minimization = 1;
	    else // if (selection.equals(Strings.FO_MAX))
	      minimization = 0;

	    if (fitnessMeasure == Global.FM_Q 
		|| fitnessMeasure == Global.FM_L
		|| fitnessMeasure == Global.FM_QR
		|| fitnessMeasure == Global.FM_LR
		|| fitnessMeasure == Global.FM_Q_QR)
	      {
		// we need maximization for this type of fitness
		// measure
		if (minimization == 1)
		  {
		    GALogTextArea.append(Strings.MAXNEEDED + Strings.endl);
		    MinimizationComboBox.setSelectedIndex(1);
		    minimization = 0;
		  }
	      }
	    else
	      // we need minimization for this type of fitness measure
	      if (minimization == 0)
		{
		  GALogTextArea.append(Strings.MINNEEDED + Strings.endl);
		  MinimizationComboBox.setSelectedIndex(0);
		  minimization = 1;
		}
	    
	    if ((fitnessMeasure == Global.FM_NORM_W 
		|| fitnessMeasure == Global.FM_WE)
		&& useWeights == 0)
	      {
		GALogTextArea.append(Strings.WSPCTNEEDED + Strings.endl);
		UseWeightsCheckBox.setSelected(true);
		JTextTools.dealWithInvalidValue(SampleDBPctTextField);
	      }
	    if ((fitnessMeasure == Global.FM_NORM_W 
		|| fitnessMeasure == Global.FM_WE)
		&& useTarget == 0)
	      {
		GALogTextArea.append(Strings.TARGETNEEDED + Strings.endl);
		UseTargetCheckBox.setSelected(true);
		JTextTools.dealWithInvalidValue(TargetIDTextField);
	      }
	    if (fitnessMeasure == Global.FM_WE && excludeAttr == 0)
	      {
		GALogTextArea.append(Strings.EXCLATTRNEEDED + Strings.endl);
		ExcludeAttrCheckBox.setSelected(true);
		JTextTools.dealWithInvalidValue(NRemAttrTextField);
	      }

	  }
	catch (IllegalArgumentException invalid_input)
	  {
	    // wait for user to input something reasonable
	    return;
	  }

	ClusterButton.setEnabled(false);
	ClusterAbortButton.setEnabled(true);
	// start the clustering algorithm	    
	cluster();
      }
    else if (event.getSource() == ClusterAbortButton)
      {
	ClusterButton.setEnabled(true);
	ClusterAbortButton.setEnabled(false);
	ga.abort();
      }
    else if (event.getSource() == GenerateButton)
      {
	try
	  {
	    // get parameters	    
	    if (UseDefaultNamingCheckBox.isSelected() == false)
	      {
		DBName = GenDBNameTextField.getText();
		if (DBName.compareTo("") == 0)
		  {
		    GenLogTextArea.append(Strings.DBINVALID + Strings.endl);
		    GenDBNameTextField.requestFocus();
		    return;
		  }
	      }
	    
	    nRows = JTextTools.getInt(GenNRowsTextField, GenLogTextArea, 
				      Strings.NROWSERRMSG);
	    if (nRows <= 0)
	      {
		GenLogTextArea.append(Strings.NROWSPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(GenNRowsTextField);
	      }
            
	    nCols = JTextTools.getInt(GenNAttrTextField, GenLogTextArea,
				      Strings.NATTRERRMSG);
	    if (nCols <= 1)
	      {
		GenLogTextArea.append(Strings.NROWSMORETHAN2 + Strings.endl);
		JTextTools.dealWithInvalidValue(GenNAttrTextField);
	      }
	    
	    nDBClasses = JTextTools.getInt(GenNClassesTextField, 
					   GenLogTextArea,
					   Strings.KERRMSG);
	    if (nDBClasses < 2)
	      {
		GenLogTextArea.append(Strings.KDBMORETHAN2 + Strings.endl);
		JTextTools.dealWithInvalidValue(GenNClassesTextField);
	      }
            
	    DBSeed = JTextTools.getInt(GenRandomSeedTextField, GenLogTextArea,
				       Strings.RANDSEEDERRMSG);
	    if (DBSeed < 0)
	      {
		GenLogTextArea.append(Strings.RANDSEEDPOSITIVE + Strings.endl);
		JTextTools.dealWithInvalidValue(GenRandomSeedTextField);
	      }
	  }
	catch (IllegalArgumentException invalid_input)
	  {
	    // wait for user to input something reasonable
	    return;
	  }
	
	generateLarge = 0;
	if (GenerateLargeCheckBox.isSelected() == true)
	  generateLarge = 1;
	
	if (UseDefaultNamingCheckBox.isSelected() == true)
	  {
	    DBName = "DBr" + nRows + "a" + nCols + "k" + nDBClasses 
	      + "s" + DBSeed + (generateLarge == 1 ? "L" : "");
	    GenDBNameTextField.setText(DBName);
	  }
	
	db = new Partition[nCols];  
	for (int i = 0; i < nCols; i++)
	  db[i] = new Partition(nRows, nDBClasses);

	isGenerating = true;
	GenProgressBar.setMaximum(nRows);
	GenLogTextArea.append(Strings.DBGENERATING + Strings.endl);
	genSynDB = new GenSynDB(this, GenProgressBar,
				db, nRows, nCols, nDBClasses, 
				DBName, DBSeed, generateLarge,
				GenLogTextArea);
	GenAbortButton.setEnabled(true);
	status = GENDB_RUNNING;
	genSynDB.start();
      }
    else if (event.getSource() == GenAbortButton)
      {
	GenerateButton.setEnabled(true);
	GenAbortButton.setEnabled(false);
	genSynDB.abort();
      }
    else if (event.getSource() == ForceGCMenuItem)
      {
	gcThreaded();
      }
    else if (event.getSource() == ExitMenuItem)
      {
	exitFrame();
      }
    else if (event.getSource() == TopicsMenuItem)
      {
	new HelpDialog(this, true).show();
      }
    else if (event.getSource() == AboutMenuItem)
      {
	new AboutDialog(this, true).show();
      }
  }

  /** clusters the currently selected database */
  private void cluster()
  {
    rand = new Random(randseed);
    
    // number of columns as far as clustering is concern      
    nColsClust = nCols; 
    nColsClust_copy = nCols; 
    if (useTarget == 1)
      {
	// flipping the target should be done once per database
	// openning
	if (flipTarget == true)
	  {
	    // rearrange the database such that the target attribute is
	    // the last attribute
	    Partition temp = db[nCols-1];
	    db[nCols-1] = db[targetId];
	    db_copy[nCols-1] = db_copy[targetId];
	    db[targetId] = temp;
	    db_copy[targetId] = temp;
	    flipTarget = false;  
	  }
	// reference partition is the last attribute
	refPart = db[nCols-1];
	// do not use this attribute in clustering
	nColsClust--;
	nColsClust_copy--;
      }

    GALogTextArea.append("\n***\nClustering database:" + Strings.endl + DBName 
		      + "(" + nRows + " rows " 
		      + nColsClust + " attributes)" + Strings.endl);
    
    if (useWeights == 1)
      {
	GALogTextArea.append("Computing weights" + Strings.endl);
	    
	wTargetCondOnDB = new double[nCols - 1];
	wDBCondOnTarget = new double[nCols - 1];
	weight = new double[nCols - 1];
	    
	targetEntr = Partition.estimateWeights(db, nCols, sampleDBPct,
					       entropyMeasure, 
					       wTargetCondOnDB, 
					       wDBCondOnTarget, 
					       weight, rand);
	    
	if (excludeAttr == 1)
	  {
	    // keep at least one attribute
	    if (noRemAttr < 1)
	      noRemAttr++;
		
	    int[] remAttr = new int[noRemAttr];
	    double[] sortingValues = new double[nColsClust];
	    for (int i = 0; i < nColsClust; i++)
	      sortingValues[i] = Math.abs(targetEntr 
					  - wTargetCondOnDB[i]);
		
	    // sort the indices of the attributes in descending order
	    SelectionMethods.selectBest(sortingValues, nColsClust, 0, 
					remAttr, noRemAttr);
		
	    GALogTextArea.append("attributes that are considered: ");
	    for (int i = 0; i < noRemAttr; i++)
	      GALogTextArea.append(remAttr[i] + " ");
	    GALogTextArea.append(Strings.endl);
	
	
	    // change the order of the references in the database such
	    // that the first noRemAttr be the remaining attributes
	    // followed by the target attribute
	    for (int i = 0; i < noRemAttr; i++)
	      {
		Partition temp = db[i];
		db[i] = db[remAttr[i]];
		db[remAttr[i]] = temp;
		    
		// change also the corresponding weights
		double tempWeight = wTargetCondOnDB[i];
		wTargetCondOnDB[i] = wTargetCondOnDB[remAttr[i]];
		wTargetCondOnDB[remAttr[i]] = tempWeight;
		    
		tempWeight = wDBCondOnTarget[i];
		wDBCondOnTarget[i] = wDBCondOnTarget[remAttr[i]];
		weight[remAttr[i]] = tempWeight;
		    
		tempWeight = weight[i];
		weight[i] = weight[remAttr[i]];
		weight[remAttr[i]] = tempWeight;
	      }
		
	    // one last swap to put target attribute on position
	    // noRemAttr
	    Partition temp = db[noRemAttr];
	    db[noRemAttr] = db[nCols-1];
	    db[nCols-1] = temp;
	    nColsClust = noRemAttr;
		
	    GALogTextArea.append("Working with " + nColsClust 
			      + " attributes" + Strings.endl);
	  } // end of excludeAttr test
	    
	if (fitnessMeasure == Global.FM_NORM_W)
	  {
	    // normilize the weights  
	    double allWeights = 0.0;
	    for (int i = 0; i < nColsClust; i++)
	      allWeights += weight[i];
		
	    for (int i = 0; i < nColsClust ; i++)
	      weight[i] /= allWeights;
		
	    allWeights = 0.0;
	    for (int i = 0; i < nColsClust; i++)
	      allWeights += wDBCondOnTarget[i];
		
	    for (int i = 0; i < nColsClust ; i++)
	      wDBCondOnTarget[i] /= allWeights;
		
	    allWeights = 0.0;
	    for (int i = 0; i < nColsClust; i++)
	      allWeights += wTargetCondOnDB[i];
		
	    for (int i = 0; i < nColsClust ; i++)
	      wTargetCondOnDB[i] /= allWeights;
		
	    GALogTextArea.append("normalized total weights" + Strings.endl);
	    GALogTextArea.append("(attrNo)  wTCondOnDB  wDBCondOnT  sum" + Strings.endl);
	    for (int i = 0; i < nColsClust; i++)
	      GALogTextArea.append("(" + i + ")  "
				   + nf.format(wTargetCondOnDB[i])
				   + "  " + nf.format(wDBCondOnTarget[i])
				   + "  " + nf.format(weight[i]) 
				   + Strings.endl);
	  } // end fitness Global.FM_NORM_W loop
      } // end useWeights test
    else
      {
	// no attribute weights
	wTargetCondOnDB = null;
	wDBCondOnTarget = null;
	weight = null;
      }
	
    // for this fitness measure print statistics about
    // entropy of intersection and average entropy
    if (fitnessMeasure == Global.FM_ALTERNATE_HAVG)
      {
	double entropyIntersect;
	int noClassesIntersect;
	Vector info = new Vector(2);
	// compute informations about the attribute partitions
	Partition.computeInfoIntersections(db, nColsClust, 
					   entropyMeasure, info);
	entropyIntersect = ((Double)info.elementAt(0)).doubleValue(); 
	noClassesIntersect = ((Integer)info.elementAt(1)).intValue();
	    
	GALogTextArea.append("Intersection of attribute partitions"
			     + " has entropy " 
			     + nf.format(entropyIntersect) 
			     + " and " + noClassesIntersect 
			     + " blocks" + Strings.endl); 
	    
	// compute average entropy of attribute partitions
	double avgEntr = 0.0;
	for (int i = 0; i < nColsClust; i++)
	  {
	    double attrPartEntropy = db[i].entropy(entropyMeasure);
		
	    if (Global.VERBOSE == 1)
	      {
		GALogTextArea.append(attrPartEntropy + Strings.endl);
		output = new StringBuffer();
		db[i].printClassCardinalities(output);
		GALogTextArea.append(output.toString());
	      }
		
	    avgEntr += attrPartEntropy;
	  }
	    
	GALogTextArea.append("Average entropy of attribute partitions "
			  + nf.format(avgEntr/(double)nColsClust) + Strings.endl);
      }
	
    GALogTextArea.append("Initializing the GA" + Strings.endl);

    ga = new GA(popSize, nRows, K, crossoverRate, mutationRate, 
		classFitnessType, crossoverType, mutationType, 
		distributionType, entropyMeasure, fitnessMeasure, 
		minimization, fitnessThreshold, consecItrs, rand, 
		db, nColsClust, wTargetCondOnDB, wDBCondOnTarget, 
		weight, this);
	
    status = GA_RUNNING;
    lastFitnessMeasureUsed = fitnessMeasure;
    GALogTextArea.append("Starting the evolution" + Strings.endl);
    
    //delete the old table with results if there is one
    if (resModel != null)
      resModel.reset();

    // while the ga is running desable the Tab for database
    // selection/generation
    MainTabbedPane.setEnabledAt(0, false);
    MainTabbedPane.setEnabledAt(1, false);

    timer.reset();
    timer.start();
    
    try
      {
	ga.start();
      }
    catch(Throwable e)
      {
	GALogTextArea.append(Strings.ERROR + e + Strings.endl);
      }
  }

  /** this function is called at the thread termination */
  public void threadTermination(Thread t)
  {
    if (t == genSynDB)
      {
	isGenerating = false;
	GenProgressBar.setValue(0);
	if (nRows != genSynDB.getRealRowNo())
	  GenLogTextArea.append("Generation of database was aborted!" + Strings.endl);
	// get real row number
	nRows = genSynDB.getRealRowNo();
	// set size of the partition to be this number
	for (int i = 0; i < nCols; i++)
	  db[i].setSize(nRows);

	GenLogTextArea.append("Generated database: " + DBName);
	GenLogTextArea.append("(" + nRows + " rows " + nCols + " attributes " 
			      + nDBClasses + " classes) " + Strings.endl);
	
	GenDBTable.setModel(new DBTableModel());
	MainTabbedPane.setEnabledAt(2, true);
	flipTarget = true; // we get a new database we can flip the
			   // target if required
	status = IDLE;
	GenAbortButton.setEnabled(false);

	// set the copy of the database
	db_copy = new Partition[nCols];
	for (int i = 0; i < nCols; i++)
	  db_copy[i] = db[i];
      }

    if (t == ga)
      {
	timer.stop();
	ClusterAbortButton.setEnabled(false);
	Vector v = null;
	try
	  {
	    v = ga.getResults();
	  }
	catch(IllegalStateException e)
	  {
	    GALogTextArea.append(e.getMessage() + Strings.endl);
	    return;
	  }

	finalChrom = (Chromosome)v.elementAt(0);
	noIterations = (Integer)v.elementAt(1);      

	if (ga.areResultsFinal())
	  GALogTextArea.append("Results are final" + Strings.endl);
	else // if (ga.areResultsPartial())
	  GALogTextArea.append("Results are partial" + Strings.endl);

	if (useTarget == 1)
	  GAResultsTable.setModel(resModel = new GAResultsReferenceModel());
	else
	  GAResultsTable.setModel(resModel = new GAResultsModel());
	ClusterButton.setEnabled(true);

	status = IDLE;
	// enable the Tab for database selection/generation
	MainTabbedPane.setEnabledAt(0, true);
	MainTabbedPane.setEnabledAt(1, true);

	if (lastFitnessMeasureUsed == Global.FM_WE)
	  {
	    // restore the database
	    for (int i = 0; i < nCols; i++)
	      db[i] = db_copy[i];

	    nColsClust = nColsClust_copy;
	  }
      }
  }

  /** Exit the Application */
  private void exitForm(java.awt.event.WindowEvent evt) 
  {
    System.exit(0);
  }
  
  /**
   * @param args the command line arguments
   */
  public static void main(String args[]) 
  {
    new GAClust().show();
  }

  // GAResultsTable model
  private abstract class ResultsTableModel extends AbstractTableModel
  {
    protected ArrayList cells;
    protected ArrayList column_names;

    public int getRowCount()
    {
      return cells.size();
    }
  
    public int getColumnCount()
    {
      return column_names.size();
    }
    
    public Object getValueAt(int row, int column)
    {
      ArrayList cellRow = (ArrayList)cells.get(row);
      Object cell = cellRow.get(column);
      return cell;
    }
    
    public String getColumnName(int i)
    {
      if (i < column_names.size())
	return column_names.get(i).toString();

      return "";
    }

    public void reset()
    {
      cells.clear();
      column_names.clear();
      fireTableDataChanged();
      fireTableStructureChanged();
    }
  }

  // DBTable model
  private class DBTableModel extends ResultsTableModel
  {
    public DBTableModel()
    {
      cells = new ArrayList(nCols);
      column_names = new ArrayList();
      column_names.add("Attribute name");
      column_names.add("Class (cardinality)");

      for (int i = 0; i < nCols; i++)
	{
	  ArrayList innerCell = new ArrayList();
	  innerCell.add("Attribute " + i);
	  innerCell.add(db[i].getClassesAndCardinalities());
	  cells.add(innerCell);
	}

      fireTableDataChanged();
    }

    public void reset()
    {
      for (int i = 0; i < cells.size(); i++)
	((ArrayList)cells.get(i)).clear();
      cells.clear();
      column_names.clear();
      fireTableDataChanged();
      fireTableStructureChanged();
    }
  }

  // GAResultsReferenceModel model
  private class GAResultsReferenceModel extends ResultsTableModel
  {
    public GAResultsReferenceModel()
    {
      // get a local copy of the reference Partition
      Partition refPartLocal = new Partition(refPart.getSize());
      refPartLocal.set(refPart);

      cells = new ArrayList();
      column_names = new ArrayList();
      column_names.add("Reference");
      column_names.add("Clustering");


      ArrayList innerCell = new ArrayList();
      innerCell.add("H(reference) = " 
		    + nf.format(refPartLocal.entropy(entropyMeasure)));
      innerCell.add("H(clustering) = " 
		    + nf.format(finalChrom.entropy(entropyMeasure)));
      cells.add(innerCell);

      innerCell = new ArrayList();
      refPartLocal.computeFitness(db, nColsClust, 
				  entropyMeasure, fitnessMeasure, 
				  wTargetCondOnDB, wDBCondOnTarget, weight);
      innerCell.add("Fitness = " + nf.format(refPartLocal.getFitness()));
      finalChrom.computeFitness(db, nColsClust, 
				entropyMeasure, fitnessMeasure, 
				wTargetCondOnDB, wDBCondOnTarget, weight);
      innerCell.add("Fitness = " + nf.format(finalChrom.getFitness()));
      cells.add(innerCell);

      innerCell = new ArrayList();
      innerCell.add("Reference classes (their cardinalities) ");
      innerCell.add("Clustering classes (their cardinalities) ");
      cells.add(innerCell);

      innerCell = new ArrayList();
      innerCell.add(refPartLocal.getClassesAndCardinalities());
      innerCell.add(finalChrom.getClassesAndCardinalities());
      cells.add(innerCell);

      innerCell = new ArrayList();
      Partition[] c = new Partition[1];
      c[0] = refPartLocal;
      finalChrom.computeFitness(c, 1,
				ImpurityMeasure.GINI, 
				Global.FM_BOTH, null, null, null);
      innerCell.add("H(clustering|reference) +  H(reference|clustering)= " 
		    + nf.format(finalChrom.getFitness()));
      innerCell.add("H(clustering|reference) +  H(reference|clustering)= " 
		    + nf.format(finalChrom.getFitness()));
      cells.add(innerCell);

      innerCell = new ArrayList();
      refPartLocal.computeFitness(db, nColsClust, entropyMeasure,
				  Global.FM_BOTH, null, null, null);
      innerCell.add("Sum H(reference|DB) + H(DB|reference) = " 
		    + nf.format(refPartLocal.getFitness()));
      finalChrom.computeFitness(db, nColsClust, entropyMeasure,
				Global.FM_BOTH, null, null, null);
      innerCell.add("Sum H(clustering|DB) + H(DB|clustering) = " 
		    + nf.format(finalChrom.getFitness()));
      cells.add(innerCell);

      innerCell = new ArrayList();
      innerCell.add("No iterations =  " + noIterations);
      innerCell.add("Time = " + timer.time()/1000 + " sec");
      cells.add(innerCell);
      
      innerCell = new ArrayList();
      innerCell.add("Class(card)");
      innerCell.add("Class(card)[intersection count]");
      cells.add(innerCell);

      ArrayList result = finalChrom.getClassIntersections(refPartLocal);
      for (int i = 0; i < result.size(); i++)
	{
	  ArrayList innerRes = (ArrayList)result.get(i);
	  innerCell = new ArrayList();
	  innerCell.add(innerRes.get(0));
	  innerCell.add(innerRes.get(1));
	  cells.add(innerCell);
	}
      innerCell = new ArrayList();
      innerCell.add("");
      innerCell.add("Classification rate = " 
		    + nf.format(finalChrom.getClassifRate(refPartLocal)));
      cells.add(innerCell);

      refPartLocal = null;
      fireTableDataChanged();
    }

    public void reset()
    {
      for (int i = 0; i < cells.size(); i++)
	((ArrayList)cells.get(i)).clear();
      cells.clear();
      column_names.clear();
      fireTableDataChanged();
      fireTableStructureChanged();
    }
  }

  // GAResults without a reference partition
  private class GAResultsModel extends ResultsTableModel
  {
    public GAResultsModel()
    {
      cells = new ArrayList();
      column_names = new ArrayList();
      column_names.add("Clustering");

      ArrayList innerCell = new ArrayList();
      innerCell.add("H(clustering) = " 
		    + nf.format(finalChrom.entropy(entropyMeasure)));
      cells.add(innerCell);

      innerCell = new ArrayList();
      finalChrom.computeFitness(db, nColsClust, 
				entropyMeasure, fitnessMeasure, 
				wTargetCondOnDB, wDBCondOnTarget, weight);
      innerCell.add("Fitness = " + nf.format(finalChrom.getFitness()));
      cells.add(innerCell);

      innerCell = new ArrayList();
      finalChrom.computeFitness(db, nColsClust, entropyMeasure,
				Global.FM_BOTH, null, null, null);
      innerCell.add("Sum H(clustering|DB) + H(DB|clustering) = " 
		    + nf.format(finalChrom.getFitness()));
      cells.add(innerCell);

      innerCell = new ArrayList();
      innerCell.add("Clustering classes (their cardinalities) ");
      cells.add(innerCell);

      innerCell = new ArrayList();
      innerCell.add(finalChrom.getClassesAndCardinalities());
      cells.add(innerCell);

      innerCell = new ArrayList();
      innerCell.add("No iterations =  " + noIterations);

      cells.add(innerCell);
      innerCell = new ArrayList();
      innerCell.add("Time = " + timer.time()/1000 + " sec");
      cells.add(innerCell);

      fireTableDataChanged();
    }
  }

  // this thread calls the garbage collector
  private class GarbageCollector extends MonitoredThread
  {
    public GarbageCollector(ThreadMonitor m)
    {
      this.monitor = m;
    }
    
    public void execute()
    {
      System.gc();
    }
  }
  
  private void gcThreaded()
  {
    Component selection = MainTabbedPane.getSelectedComponent();
    if (selection == DatabaseSplitPane)
      DBLogTextArea.append(Strings.GCSTART + Strings.dots);
    else if (selection == GenerateSplitPane)
      GenLogTextArea.append(Strings.GCSTART + Strings.dots);
    else //if (selection == GAHorizontalSpitPane)
      GALogTextArea.append(Strings.GCSTART + Strings.dots);
    
    ForceGCMenuItem.setEnabled(false);
    
    // create a monitor to re-enable controls
    monitor = new ThreadMonitor() 
      {
	public void threadTermination(Thread t)
	{
	  Component selection = MainTabbedPane.getSelectedComponent();
	  if (selection == DatabaseSplitPane)
	    DBLogTextArea.append(Strings.GCEND + Strings.dots + Strings.endl);
	  else if (selection == GenerateSplitPane)
	    GenLogTextArea.append(Strings.GCEND + Strings.dots + Strings.endl);
	  else //if (selection == GAHorizontalSpitPane)
	    GALogTextArea.append(Strings.GCEND + Strings.dots + Strings.endl);
	  
	  monitor = null; // we don't need the monitor anymore
	  ForceGCMenuItem.setEnabled(true);
	}
      };
    
    new GarbageCollector(monitor).start();
  }

  // called when user closes application
  private void exitFrame() 
  {
    // don't allow user to exit while a clustering algorithm is still running
    // or a database is generated
    if (status != IDLE)
      return;

    hide();
    dispose();

    System.exit(0);
  }

  
  // Variables declaration
  // Database Tab
  private JMenuBar MainMenuBar;
  private JMenu ProgramMenu;
  private JMenuItem ForceGCMenuItem;
  private JMenuItem ExitMenuItem;
  private JMenu HelpMenu;
  private JMenuItem TopicsMenuItem;
  private JMenuItem AboutMenuItem;
  private JTabbedPane MainTabbedPane;
  private JSplitPane DatabaseSplitPane;
  private JPanel DatabasePanel;
  private JPanel DatabaseCenterPanel;
  private JPanel DatabaseSouthPanel;
  private JLabel DBNameLabel;
  private JPanel DBNameLabelPanel;
  private JPanel DBNamePanel;
  private JTextField DBNameTextField;
  private JPanel BrowsePanel;
  private JButton BrowseButton;
  private JPanel NRowsLabelPanel;
  private JLabel NRowsLabel;
  private JPanel NRowsPanel;
  private JTextField NRowsTextField;
  private JLabel BogusLabel1;
  private JLabel BogusLabel2;
  private JPanel NAttrLabelPanel;
  private JLabel NAttrLabel;
  private JPanel NAttrPanel;
  private JTextField NAttrTextField;
  private JButton OpenButton;
  private JPanel Results;
  private JPanel ResultsNorth;
  private JPanel ResultsSouth;
  private JScrollPane DatabaseScrollPane;
  private JTextArea DBLogTextArea;
  private JTable DBTable;
  private JScrollPane DBTableScrollPane;

  // Generate Tab
  private JSplitPane GenerateSplitPane;
  private JPanel GenerateDBPanel;
  private JPanel GenerateDBNorthPanel;
  private JPanel GenerateDBSouthPanel;
  private JPanel GenDBNameLabelPanel;
  private JLabel GenDBNameLabel;
  private JPanel GenDBNamePanel;
  private JTextField GenDBNameTextField;
  private JCheckBox UseDefaultNamingCheckBox;
  private JPanel UseDefaultNamingPanel;
  private JPanel GenNRowsLabelPanel;
  private JLabel GenNRowsLabel;
  private JPanel GenNRowsPanel;
  private JTextField GenNRowsTextField;
  private JLabel GenBogusLabel1;
  private JPanel GenNAttrLabelPanel;
  private JLabel GenNAttrLabel;
  private JPanel GenNAttrPanel;
  private JTextField GenNAttrTextField;
  private JLabel GenBogusLabel2;
  private JPanel GenNClassesLabelPanel;
  private JLabel GenNClassesLabel;
  private JPanel GenNClassesPanel;
  private JTextField GenNClassesTextField;
  private JLabel GenBogusLabel3;
  private JPanel GenRandomSeedLabelPanel;
  private JLabel GenRandomSeedLabel;
  private JPanel GenRandomSeedPanel;
  private JTextField GenRandomSeedTextField;
  private JLabel GenBogusLabel4;
  private JPanel GenerateLargePanel;
  private JCheckBox GenerateLargeCheckBox;
  private JLabel GenBogusLabel5;
  private JLabel GenBogusLabel6;
  private JButton GenerateButton;
  private JButton GenAbortButton;
  private JProgressBar GenProgressBar;
  private JPanel GenProgressBarPanel;
  private JPanel GenResultsPanel;
  private JPanel GenResultsNorthPanel;
  private JPanel GenResultsSouthPanel;
  private JTable GenDBTable;
  private JScrollPane GenDBTableScrollPane;
  private JScrollPane GenLogScrollPane;
  private JTextArea GenLogTextArea;

  // GA Tab
  private JSplitPane GAHorizontalSplitPane;
  private JSplitPane GASplitPane;
  private JPanel GAPanel;
  private JPanel GACenterPanel;
  private JPanel GASouthPanel;
  private JPanel PopSizeLabelPanel;
  private JLabel PopSizeLabel;
  private JPanel PopSizePanel;
  private JTextField PopSizeTextField;
  private JPanel NClassesClustLabelPanel;
  private JLabel NClassesClustLabel;
  private JPanel NClassesClustPanel;
  private JTextField NClassesClustTextField;
  private JPanel CrossRateLabelPanel;
  private JLabel CrossRateLabel;
  private JPanel CrossRatePanel;
  private JTextField CrossRateTextField;
  private JPanel MutRateLabelPanel;
  private JLabel MutRateLabel;
  private JPanel MutRatePanel;
  private JTextField MutRateTextField;
  private JPanel ClassFitnessLabelPanel;
  private JLabel ClassFitnessLabel;
  private JPanel ClassFitnessPanel;
  private JComboBox ClassFitnessComboBox;
  private JPanel CrossTypeLabelPanel;
  private JLabel CrossTypeLabel;
  private JPanel CrossTypePanel;
  private JComboBox CrossTypeComboBox;
  private JPanel MutTypeLabelPanel;
  private JLabel MutTypeLabel;
  private JPanel MutTypePanel;
  private JComboBox MutTypeComboBox;
  private JPanel DistrTypeLabelPanel;
  private JLabel DistrTypeLabel;
  private JPanel DistrTypePanel;
  private JComboBox DistrTypeComboBox;
  private JPanel EntropyMeasureLabelPanel;
  private JLabel EntropyMeasureLabel;
  private JPanel EntropyMeasurePanel;
  private JComboBox EntropyMeasureComboBox;
  private JPanel FitnessMeasureLabelPanel;
  private JLabel FitnessMeasureLabel;
  private JPanel FitnessMeasurePanel;
  private JComboBox FitnessMeasureComboBox;
  private JPanel FitnessThresholdLabelPanel;
  private JLabel FitnessThresholdLabel;
  private JPanel FitnessThresholdPanel;
  private JTextField FitnessThresholdTextField;
  private JPanel ConsecItrsLabelPanel;
  private JLabel ConsecItrsLabel;
  private JPanel ConsecItrsPanel;
  private JTextField ConsecItrsTextField;
  private JPanel RandomSeedGALabelPanel;
  private JLabel RandomSeedGALabel;
  private JPanel RandomSeedGAPanel;
  private JTextField RandomSeedGATextField;
  private JPanel UseTargetPanel;
  private JCheckBox UseTargetCheckBox;
  private JPanel TargetIDLabelPanel;
  private JLabel TargetIDLabel;
  private JPanel TargetIDPanel;
  private JTextField TargetIDTextField;
  private JPanel UseWeightsPanel;
  private JCheckBox UseWeightsCheckBox;
  private JPanel SampleDBPctLabelPanel;
  private JLabel SampleDBPctLabel;
  private JPanel SampleDBPctPanel;
  private JTextField SampleDBPctTextField;
  private JPanel ExcludeAttrPanel;
  private JCheckBox ExcludeAttrCheckBox;
  private JPanel NRemAttrLabelPanel;
  private JLabel NRemAttrLabel;
  private JPanel NRemAttrPanel;
  private JTextField NRemAttrTextField;
  private JPanel MinimizationLabelPanel;
  private JLabel MinimizationLabel;
  private JPanel MinimizationPanel;
  private JComboBox MinimizationComboBox;
  private JPanel ClusterPanel;
  private JButton ClusterButton;
  private JButton ClusterAbortButton;
  private JLabel BogusLabel3;
  private JLabel BogusLabel4;
  private JLabel BogusLabel5;
  private JPanel GAResultsPanel;
  private JPanel GAResultsNorthPanel;
  private JPanel GALogPanel;
  private JScrollPane GAResultsScrollPane;
  private JTable GAResultsTable;
  private JScrollPane GAScrollPane;
  private JTextArea GALogTextArea;

  private JFileChooser jfc;
  // End of variables declaration//GEN-END:variables
}
