package taskspaces.rna;

import java.util.ArrayList;

/**
 * DatabaseEntry represents a lab-isolated set of motifs,
 * structures and constraints. The class instantiated by
 * a parser for XML data representing the entries.
 * @author      Rob Markel
 * @version     1.00 2 January 2003
 */
public class DatabaseEntry implements java.io.Serializable
{
   /** Holds the name of the entry. */
   String name;

   /** Holds the entry sequence modules. */
   String[] modules;

   /** Holds the entry sequence structures. */
   String[] structures;

   /** Holds the valid base pairs. */
   String[] basePairs;

   /** Holds the probabilities for each base pair being selected based on the current composition. */
   float[] pairProbs;

   /** Holds the current percentage composition of bases. */
   float[] composition;

   /** Indicates whether to allow GU or UG pairs. */
   boolean gu;

   /** Holds integer arrays representing pairing rules for this entry. */ 
   ArrayList constraints;

   public DatabaseEntry(String name,String[] modules,String[] structures,ArrayList constraints)
   {
      this.name=name;
      this.modules=modules;
      this.structures=structures;
      this.constraints=constraints;
   }

   /**
    * Sets the composition for this entry.
    * @param f holds percent values for the composition. 
    * @param b <code>true</code> if allow GU, <code>false</code> to disallow. 
    */
   public void setComposition(float[] f,boolean b)
   {
      this.composition=f; 
      this.gu=b;
      initializeArrays();
   }

   /**
    * Modifies modules to match the entry's set of pairing constraints.
    * @return the modified modules. 
    */
   public String[] generateModules(java.util.Random myRand)
   {
      // we need a new variable substitutedModules because modules with the Ns needs to be conserved
      // (for every random sequence, we need to know which brackets can be replaced (N), and which are fixed)
      String[] substitutedModules= (String[])modules.clone();
      //System.out.println("modules "+modules[0]);
      for(int i=0; i<constraints.size(); i++)
      {
         int[] constraint=(int[])constraints.get(i);
 
         //for(int z=0; z<constraint.length; z++) System.out.print(constraint[z]+",");
         
         if(constraint[1]==constraint[3])
         {
            char[] module=(substitutedModules[constraint[1]]).toCharArray();
            for(int j=0; j<constraint[0]; j++)
            {
               char[] pair=getPair(myRand);
               //System.out.println("pair "+pair[0]+pair[1]);
               if(module[constraint[2]+j]=='N')
               {
                  module[constraint[2]+j]=pair[0];
               }
               if(module[constraint[4]+constraint[0]-j-1]=='N')
               {
                  //module[(constraint[4]+constraint[0])-j]=pair[1];
                  module[(constraint[4]+constraint[0])-j-1]=pair[1];
               }
            }
            substitutedModules[constraint[1]]=new String(module);
         }
         else
         {
            char[] firstModule=(substitutedModules[constraint[1]]).toCharArray();
            //System.out.println("firstmodule "+ new String(firstModule));
            char[] secondModule=(substitutedModules[constraint[3]]).toCharArray();
            for(int j=0; j<constraint[0]; j++)
            {
               char[] pair=getPair(myRand);
               //System.out.println("pair "+pair[0]+pair[1]);
               if(firstModule[constraint[2]+j]=='N')
               {
                  firstModule[constraint[2]+j]=pair[0];
                  //System.out.println("firstmodule "+ new String(firstModule));
               }
               if(secondModule[constraint[4]+constraint[0]-j-1]=='N')
               {
                  //secondModule[constraint[4]+constraint[0]-j]=pair[1];
                  secondModule[constraint[4]+constraint[0]-j-1]=pair[1];
               }
            }
            substitutedModules[constraint[1]]=new String(firstModule);
            substitutedModules[constraint[3]]=new String(secondModule);
         }
      }
      // *** be careful *** : looks like the replace method replaces ALL occurrences STARTING FROM position i !!!
      // therefore: loop backwards
      for(int i=substitutedModules.length-1; i>=0; i--) substitutedModules[i]=substitutedModules[i].replace('N',SequenceGenerator.getCompositionBase(composition,myRand));
      //System.out.println("submodules "+substitutedModules[0]);
      return substitutedModules;
   }

   /**
    * Returns this entry's constraints.
    * @return the constriants.
    */
   public ArrayList getConstraints() {return constraints;}

   /**
    * Returns this entry's sequence modules.
    * @return the sequence modules.
    */
   public String[] getModules() {return modules;}

   /**
    * Returns this entry's sequence structures.
    * @return the sequence structures.
    */
   public String[] getStructures() {return structures;}

   /**
    * Returns this entry's name.
    * @return the entry name.
    */
   public String getName() {return name;}


   /**
    * Initializes the pairProbs probabilities array
    * with the probabilities of each base pair being
    * selected based on the percentages in the composition
    * array.
    * @return void.
    */
   private void initializeArrays()
   {
      float sum;
      int pairs;
      if(gu) {pairs=6;} 
      else {pairs=4;}
      pairProbs=new float[pairs];
      basePairs=new String[pairs];
      float a=composition[0];
      float c=composition[1];
      float g=composition[2];
      float u=composition[3];
      float CG=(g*c);
      float UA=(u*a)+CG;
      float GC=(g*c)+UA;
      float AU=(a*u)+GC;
      float UG=0;
      float GU=0;
      if(gu)
      {
         UG=(u*g)+AU;
         GU=(g*u)+UG;
         sum=GU;
      }
      else {sum=AU;}
      if(gu)
      {
	 // this was the original code, which was wrong I think
         // pairProbs[4]=GU/sum;
         // pairProbs[5]=UG/sum;
         // basePairs[4]="GU";
         // basePairs[5]="UG";
         pairProbs[5]=GU/sum;
         pairProbs[4]=UG/sum;
         basePairs[5]="GU";
         basePairs[4]="UG";
      }
      if(sum==0) sum=1;
      pairProbs[0]=CG/sum;
      pairProbs[1]=UA/sum;
      pairProbs[2]=GC/sum;
      pairProbs[3]=AU/sum;
      basePairs[0]="CG";
      basePairs[1]="UA";
      basePairs[2]="GC";
      basePairs[3]="AU";
      for(int ii=0;ii<pairs;ii++)
	  {
	      //System.out.println(basePairs[ii]+": "+pairProbs[ii]);

	  }

   }
   
   /**
    * Returns a pair of bases using the probabilities
    * in the pairProbs array set by the initializeArrays 
    * method.
    * @return the base pair.
    */ 
   private char[] getPair()
   {
       // this routine is used in the current version of the code 15Apr04
      String pair=null;
         java.util.Random myRand = new java.util.Random(10);
	                System.out.println("putting seed 10 db 1");
			
			//      double d=Math.random();
			double d=myRand.nextDouble();
      if(d<pairProbs[0]) pair=basePairs[0];
      if(d<pairProbs[1] && d>=pairProbs[0]) pair=basePairs[1];
      if(d<pairProbs[2] && d>=pairProbs[1]) pair=basePairs[2];
      if(gu)
      {
         if(d<pairProbs[3] && d>=pairProbs[2]) pair=basePairs[3];
         if(d<pairProbs[4] && d>=pairProbs[3]) pair=basePairs[4];
         if(d>pairProbs[4]) pair=basePairs[5];
      }
      else 
      { 
         if(d>pairProbs[2]) pair=basePairs[3]; 
      }
      //      System.out.println(pair);
      return pair.toCharArray();
   }


   private char[] getPair(java.util.Random myRand)
   {
       // this routine is used in the current version of the code 15Apr04
      String pair=null;
      //         java.util.Random myRand = new java.util.Random(10);
      //                System.out.println("putting seed 10 db 1");
			
			//      double d=Math.random();
			double d=myRand.nextDouble();
      if(d<pairProbs[0]) pair=basePairs[0];
      if(d<pairProbs[1] && d>=pairProbs[0]) pair=basePairs[1];
      if(d<pairProbs[2] && d>=pairProbs[1]) pair=basePairs[2];
      if(gu)
      {
         if(d<pairProbs[3] && d>=pairProbs[2]) pair=basePairs[3];
         if(d<pairProbs[4] && d>=pairProbs[3]) pair=basePairs[4];
         if(d>pairProbs[4]) pair=basePairs[5];
      }
      else 
      { 
         if(d>pairProbs[2]) pair=basePairs[3]; 
      }
      //      System.out.println(pair);
      return pair.toCharArray();
   }
}
