gt:                         match = protein.get(0).startsWith(locus+"_");
context: package analysis;
  
  import java.io.*;
  import java.util.*;
  
  /**
   * @author Boyang Zhao
   * @version 1.0
   * @description implementation of algorithms for analyzing phosphopeptides
   *
   */
  
   /**
    * about initialization
    * all the static variables are settings that has to be initialized separately
    * these setting static variables are blank even after instantization of class
    * protFileName and orthoFileName are the only two static variables that are initialized during instantization
    * in this program, the values for these static variables are filled in at start of program with the Utilities.updateSettings() method
    */
  
   /**
    * locus is a deprecated term. the program was originally designed with swiss-prot database in mind but has since switched to HomoloGene
    * locus below represents the unique identifier for the orthologous group
    * definitions:
    * locus = HID|gene symbols
    * locus_species = HID|gene symbols_[species with spaces]
    */
  
  public class Analysis {
      /* data structure declaration */
  
      //data structures have same total row # - entries correspond
      //{phosphositeSList, phosphositeDB, phosphositeAlignDB, cscoresDB}
      //{locusSList, locusList}
  
      //databases
      public ArrayList<String> peptideInputs; //[input seq (w/ symbols)]
      public ArrayList<ArrayList<String>> peptideDB; //[[input seq (w/ symbols), phosphosites]]
      public ArrayList<String> peptideDBambi; //[[input seq (w/ symbols)]]
      public ArrayList<ArrayList<String>> protDB; //[[locus, locus_species, accession number, gene symbol, protein seq]]
      public ArrayList<ArrayList<String>> phosphositeDB; //[[locus, locus_species, phosphosite, gene symbol, corresponding phosphosites of other species]]
      public ArrayList<ArrayList<String>> locusList; //[[locus, # of orthologs, start index in orthologDB, end index in orthologDB]]
      public ArrayList<ArrayList<String>> orthologDB; //[[locus, locus_species, accession number, gene symbol, protein seq]]
      public ArrayList<ArrayList<String>> cscoresDB; //[[locus, phosphosite, site conservation score, motif conservation score]]
  
      //book keepings
          //public
      public ArrayList<char[][]> phosphositeAlignDB; //[[2D residues alignment]]; index of ArrayList corresponds to phophosite, same ordering as phosphositeDB
                                                     //for char 2D array: each row represents each alignment pos (-1, 0, +1) and each col represents different orthologs
      public long runningTime;
      
          //internal
      private TreeSet<String> locusSList; //[locus]
      public HashMap<String, String> phosphositeSList; //key: [locus \t locus_species \t phosphosite \t gene symbol]; value: input peptide indices (index starts at 1)
      private long startTime;
      private long endTime;
  
      //settings
          //public
      public String inputSpecies;
      public static boolean display;
          //internal
      private final int siteAlignTotalLen;
      private javax.swing.JFrame parentFrame;
      private boolean db_local;
          //paths
      public static String dbFolderPath;
      public static String protFileName;
      public static String orthoFileName;
      public static String exeFolderPath;
      public static String alnOutFolderPath;
      public static ArrayList<String> db_species;
      public static ArrayList<String> db_target;
          //analysis parameters
      public static int siteAlignNgbrLen;
      public static char cPlaceholder; //TODO currently not used
      public static char nPlaceholder; //TODO currently not used
  
      //error handling
      public boolean analyzeStatus;
  
      /**
       * Analysis constructor, initialize all variables
       * @param speciespath
       * @param dbpath
       */
      public Analysis(String speciespath, String dbpath, javax.swing.JFrame parent, boolean displayinput) {
          //inializations
          parentFrame = parent;
          display = displayinput;
          peptideInputs = new ArrayList<String>();
          peptideDB = new ArrayList<ArrayList<String>>();
          peptideDBambi = new ArrayList<String>();
          protDB = new ArrayList<ArrayList<String>>();
          phosphositeDB = new ArrayList<ArrayList<String>>();
          locusList = new ArrayList<ArrayList<String>>();
          orthologDB = new ArrayList<ArrayList<String>>();
          phosphositeAlignDB = new ArrayList<char[][]>();
          cscoresDB = new ArrayList<ArrayList<String>>();
          locusSList = new TreeSet<String>();
          phosphositeSList = new HashMap<String, String>();
          protFileName = speciespath;
          orthoFileName = dbpath;
          db_local = orthoFileName.endsWith(".ws") ? false : true;
          analyzeStatus = true;
          siteAlignTotalLen = siteAlignNgbrLen*2+1;
      }
      
      /**
       * dispatch input into analysis methods for computation
       */
      public void analyzePeptides() {
          
          startTime = System.currentTimeMillis();
          
          if (peptideInputs.isEmpty()) {
              Utilities.displayMessage("Please enter in at least one sequence before continue.", parentFrame);
          } else {
              try {
                  Utilities.setOverallMax(100);
                  createProtDB();
                  Utilities.setOverallProgress(25);
                  createOrthologDB();
                  Utilities.setOverallProgress(50);
                  createSeqAlignment();
                  Utilities.setOverallProgress(75);
                  createCScoresDB();
                  Utilities.setOverallProgress(100);
              } catch (Exception e){
                  Utilities.displayMessage(e.getMessage(), parentFrame);
                  analyzeStatus = false;
              }
          }
          
          endTime = System.currentTimeMillis();
          runningTime = endTime - startTime;
      }
  
      private void createPhosphositeDB(){
          for(String psite : phosphositeSList.keySet()){
              System.out.print(psite);
              phosphositeDB.add(new ArrayList(Arrays.asList(psite.split("\\t"))));
          }
      }
  
      /**
       * create an 2-D array of homologous proteins in same-species
       * @modifies peptideDB, locusSList, phosphositeSList, protDB, peptideDBambi
       */
      private void createProtDB() throws Exception {
  
          Utilities.startTask("Task 1 of 4: Generating Protein Database - parsing local binary database");
  
          //create an input stream from local binary database file (same species)
          //then save the database in the form of a 2D array
          //structure: [[locus_species],[accession number],[gene symbol],[sequence]]
          ArrayList<ArrayList<String>> db2DArrayList = Utilities.deserializeDB(dbFolderPath+protFileName, 200000);
  
          if (analyzeStatus) {
              Utilities.startTask("Task 1 of 4: Generating Protein Database", peptideInputs.size());
  
              inputSpecies = Utilities.getSpecies(db2DArrayList.get(0).get(0), false);
  
              //start searching for phosphoprotein (same species)
              for (int i = 0; i < peptideInputs.size(); i++) {
                  //note input already has all char converted to upper case
                  String rawSeq = peptideInputs.get(i);
                  String pOnlySeq = rawSeq.replaceAll("[^A-Z\\*]*", ""); //keep the * for phosphorylation, remove all other symbols
                  String cleanedSeq = rawSeq.replaceAll("[^A-Z]*", "");
  
                  //find matches of peptide sequence in protein database of same species
                  //protein db is parsed as 2D array and saved in db2DArrayList
                  ArrayList<String> firstMatch = new ArrayList<String>();
                  int matchN = 0;
  
                  int z=0;
  
                  Iterator<ArrayList<String> > iterL = db2DArrayList.iterator();
                  while(iterL.hasNext()){z++;
                      boolean match = false;
                      ArrayList<String> protein = iterL.next();
                      match = protein.get(3).toUpperCase().contains(cleanedSeq);
  
                      if (match) {
                          if (matchN == 0) {
                              firstMatch.add(rawSeq);
                              firstMatch.add(protein.get(0)); //locus_species
                              firstMatch.add(protein.get(1)); //accession number
                              firstMatch.add(protein.get(2)); //gene symbol
                              firstMatch.add(protein.get(3)); //protein sequence
                          } else {
                              //if multiple matches found, save into separate database
                              //can also save this to database; currently there's no use for saving this.
                              //[a 2D array].add(new ArrayList(Arrays.asList(rawSeq,protein.get(0),protein.get(1),protein.get(2),protein.get(3))));
                          }
  
                          matchN++;
                      }
                  }
                  
                  //if only one corresponding protein is found, then this will be further analyzed
                  if (matchN == 1) {
                      //determine phosphosite(s) from this phosphopeptide
                      //first pos number of input seq
                      int indexPeptSeq = firstMatch.get(4).indexOf(cleanedSeq);
                      int checkasterisk = pOnlySeq.indexOf("*", 0);
                      int findasterisk = checkasterisk;
                      int pN = 0; //keeps track of total number of *, need this to calculate the correct site position
                      String phosphosites = "";
                      if (checkasterisk != -1) {
                          //phosphorylation exists, get locus first
                          //get locus and prot to protDB is haven't done so already
                          String locussp = firstMatch.get(1);
                          String locus = Utilities.getLocus(locussp);
  
                          if (locusSList.add(locus)) {
                              //[locus, locus_species, accession number, gene symbol, protein seq]
                              protDB.add(new ArrayList(Arrays.asList(locus,firstMatch.get(1),firstMatch.get(2),firstMatch.get(3),firstMatch.get(4))));
                          }
  
                          //now determine the phosphosite positions
                          do {
                              pN++;
                              int phosphosite = indexPeptSeq + findasterisk - pN;
                              char aaphosphosite = firstMatch.get(4).charAt(phosphosite);
                              int realphosphosite = phosphosite + 1; //index starts at 0, but real count starts at 1
                              String hashkey = locus+"\t"+firstMatch.get(1)+"\t"+String.valueOf(aaphosphosite)+realphosphosite+"\t"+firstMatch.get(3);
                              String hashvalue = phosphositeSList.get(hashkey); //hash value keeps track of input indices (index starts at 1) for given phosphosite
                              if(hashvalue != null){
                                  hashvalue = hashvalue+";"+String.valueOf(i+1);
                              } else {
                                  hashvalue = String.valueOf(i+1);
                              }
                              phosphositeSList.put(hashkey, hashvalue);
                              phosphosites += String.valueOf(aaphosphosite)+realphosphosite+", ";
                              findasterisk++;
  
                              findasterisk = pOnlySeq.indexOf("*", findasterisk);
                          } while (findasterisk != -1);
  
                          phosphosites = phosphosites.substring(0, phosphosites.length()-2);
  
                          peptideDB.add(new ArrayList(Arrays.asList(rawSeq,phosphosites)));
                      } else {
                          peptideDBambi.add(rawSeq);
                          peptideDB.add(new ArrayList(Arrays.asList(rawSeq,"no phosphosite found - see help for more info")));
                      }
  
                  } else if (matchN == 0) {
                      peptideDBambi.add(rawSeq);
                      peptideDB.add(new ArrayList(Arrays.asList(rawSeq,"no protein match found - see help for more info")));
                  } else {
                      peptideDBambi.add(rawSeq);
                      peptideDB.add(new ArrayList(Arrays.asList(rawSeq,"multiple protein matches found - see help for more info")));
                  }
  
                  Utilities.setTaskProgress(i+1);
              }
          }
      }
  
      /**
       * create an 2-D array of orthologs across multiple species
       * @modifies orthologDB
       */
      private void createOrthologDB() throws Exception {
          if(db_local)
              Utilities.startTask("Task 2 of 4: Generating Ortholog Database - parsing binary local database");
          else
              Utilities.startTask("Task 2 of 4: Generating Ortholog Database - parsing homologene database");
  
          if(locusSList.isEmpty())
              return;
  
          ArrayList<ArrayList<String>> db2DArrayList = new ArrayList<ArrayList<String>>();
          HashMap<String, HashSet> hDB_hash = new HashMap<String, HashSet>();
          if(db_local){
              //create an input stream from local binary database file (multiple species)
              //then save the database in the form of a 2D array
              //structure: [[locus],[accession number],[gene name],[sequence]]
              db2DArrayList = Utilities.deserializeDB(dbFolderPath+orthoFileName, 500000);
          } else {
              //get the hash table (key=HID; value=list of proteins delimited by "|")
              ObjectInputStream inputStream = null;
              inputStream = new ObjectInputStream(new BufferedInputStream(new FileInputStream(Analysis.dbFolderPath + Utilities.gethDBfilename()), 500000));
              inputStream.readObject();
              hDB_hash = (HashMap<String, HashSet>) inputStream.readObject();
              if (inputStream != null) {
                  inputStream.close();
              }
          }
          
          //search for proteins from other species that have the same locus
          if (analyzeStatus) {
              Utilities.startTask("Task 2 of 4: Generating Ortholog Database", locusSList.size());
  
              Iterator<String> iter = locusSList.iterator();
              int i = 0; //track locus
              int start = 0, end = 0; //track index in orthologDB
              while(iter.hasNext()){
                  String locus = iter.next();
                  int matchesNum = 0;
  
                  if(db_local){
                      //loop through all proteins in db of other species (db2DArrayList)
                      //and pull out all protein sequences that are of the same locus
                      for (ArrayList<String> protein : db2DArrayList) {
                          boolean match = false;
  