package bicat.run_machine;

import java.util.Collections;
import java.util.LinkedList;

import javax.swing.JOptionPane;

import bicat.algorithms.bimax.BiMax;
import bicat.gui.BicatGui;

/**
 * <p>Title: BicAT Tool </p>
 * <p>Copyright: Copyright (c) 2004</p>
 * @author Amela Prelic
 * @version 1.0
 *
 * Run Machine for BiMax algorithm. The code for the BiMax algorithm is kept
 * separate, in bicat.runMachine.bimax subpackage.
 *
 **/

public class RunMachine_BiMax_java extends RunMachine {

  static boolean extended;

  // ===========================================================================
  public RunMachine_BiMax_java() { }
  public RunMachine_BiMax_java(BicatGui o) { owner = o; }

  // ===========================================================================
  /**
   * Takes a dataset, stores it, runs <code>bimax</code> on it, and
   * performs basic operations on the results to prepare them for local use.
   *
   *  Its completion is marked by a function call
   * in the <code>finished</code> method in the local <code>SwingWorker</code>
   *  object.
   *
   * */ 
  public synchronized void runBiclustering(final ArgumentsBiMax args) {

    extended = args.isExtended();

    if(true) System.out.println("RUN MACHINE BIMAX: is extended? "+extended);

    nrGenes = args.getNumberGenes();
    nrChips = args.getNumberChips();

    cullDegenerate = extended; // true;

    // create new BiMax object linked with the ProgressMonitor
    final BiMax B = new BiMax();
    final int[][] matrix = args.getBinaryData();

    final int g_low = args.getMinGenes();
    final int c_low = args.getMinChips();

    // start BiMax in a separate thread
    final SwingWorker worker = new SwingWorker() {

      public Object construct() {

        if(extended)
          System.out.println("Running Extended Biclustering... ");

        if(owner.debug)
          System.out.println("Started BiMax in a new thread!\n"+
                             "Matrix dimensions are: "+matrix.length+" / "+matrix[0].length);

        B.run(matrix, matrix.length, matrix[0].length, "1", "no", g_low, c_low, null);
        return null;
      }

      public void finished() {

        System.out.println("Getting results from BiMax...");

        computedBiclusters = B.getBiclusters();
        outputBiclusters = null;

        if(extended) {
          if(true) System.out.println("Since it is extended ... ");
          transferListExtended(matrix);
          outputBiclusters = cleanBiclusterList(outputBiclusters);
        }
        else transferList();

        owner.finishUpRun(args.getDatasetIdx(), outputBiclusters, args.getPreprocessOptions(), "BiMax");
        JOptionPane.showMessageDialog(null, "Calculations finished.\nThe results can be found in the bicluster results section of the current dataset.");

      }
    } ;
    worker.start();
  }

  // ===========================================================================
  // ***** Transfer list Extended - applicable only for BiMax algorithm ....

  /**
   *
   * Retrieve the list of <code>bimax.Bicluster</code> objects
   * computed by <code>bimax.Bimax</code> to the local representation,
   * <code>bicat.biclustering.Bicluster</code> objects. (Called if the
   * discretization procedure of the data was Co-Expressed patterns.) <br>
   *
   * The transferred list is automatically sorted (by Size).
   * <p>
   *
   * */
  private void transferListExtended(int[][] binary_matrix) {

    // should appropriately translate the BCs
    int gc = binary_matrix.length/2;
    int cc = binary_matrix[0].length/2;

    bicat.run_machine.Bicluster_bitset bIn;        // Bicluster object from bcs list that will be made into a Bicluster
    bicat.biclustering.Bicluster bOut;            // new Bicluster object that will be added to the outputBiclusters list

    int[] genes, chips;                           // aux. arrays for gene sets and chips sets of a bc

    outputBiclusters = new LinkedList();

    for(int i=0; i<computedBiclusters.size(); i++) {

      bIn = (bicat.run_machine.Bicluster_bitset)computedBiclusters.get(i);
      genes = bIn.getGenes();
      chips = bIn.getChips();

      if(cullDegenerate) if ((genes.length <= 1) || (chips.length <= 1)) continue;

      // translate the gene and chip indices - modulo gc/cc - (adjusting output from Bica)
      for(int j=0; j< genes.length; j++) genes[j] = genes[j] % gc;
      for(int j=0; j< chips.length; j++) chips[j] = chips[j] % cc;

      bOut = new bicat.biclustering.Bicluster(i, genes, chips);
      outputBiclusters.add(bOut);
    }

    // SORT works?
    Collections.sort(outputBiclusters);
  }

  // ===========================================================================
  /* Remove the duplicate biclusters: Necessary for "extended" BiMax run. */
  private LinkedList cleanBiclusterList(LinkedList list) {
    for(int i=0; i<list.size(); i++)
      for(int j=i+1; j<outputBiclusters.size(); j++) {
        if ( ( (bicat.biclustering.Bicluster)list.get(j)).compareTo((bicat.biclustering.Bicluster)list.get(i)) == 0) {
          list.remove(j);
          j--;
          break;
        }
      }
    return list;
  }

}