content: /*
   * The MIT License (MIT)
   *
   * Copyright (c) 2011-2020 Broad Institute, Aiden Lab, Rice University, Baylor College of Medicine
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   *  THE SOFTWARE.
   */
  
  package juicebox.tools.clt.juicer;
  
  import juicebox.HiCGlobals;
  import juicebox.data.ChromosomeHandler;
  import juicebox.data.HiCFileTools;
  import juicebox.data.anchor.MotifAnchorTools;
  import juicebox.tools.clt.CommandLineParserForJuicer;
  import juicebox.tools.clt.JuicerCLT;
  import juicebox.track.feature.*;
  
  import java.awt.*;
  import java.io.File;
  
  /**
   * Created by muhammadsaadshamim on 9/14/15.
   */
  public class CompareLists extends JuicerCLT {
  
      public final static String PARENT_ATTRIBUTE = "parent_list";
      public static final Color AAA = new Color(102, 0, 153);
      public static final Color BBB = new Color(255, 102, 0);
      /**
       * Arbitrary colors for comparison list
       **/
      private static final Color AB = new Color(34, 139, 34);
      private static final Color AA = new Color(0, 255, 150);
      private static final Color BB = new Color(150, 255, 0);
      private int threshold = 10000, compareTypeID = 0;
      private String genomeID, inputFileA, inputFileB, outputPath = "comparison_list.bedpe";
  
      public CompareLists() {
          super("compare [-m threshold] [-c chromosome(s)] <compareType> <genomeID> <list1> <list2> [output_path]\n" +
                  "comparetype:   0 - overlap/intersect within distance threshold\n" +
                  "               1 - comparison with ctcf motifs\n" +
                  "               2 - convergence calculation for list1 with ctcf motifs");
          HiCGlobals.useCache = false;
      }
  
      @Override
      protected void readJuicerArguments(String[] args, CommandLineParserForJuicer juicerParser) {
          if (args.length != 5 && args.length != 6) {
              printUsageAndExit();
          }
  
          compareTypeID = Integer.parseInt(args[1]);
          genomeID = args[2];
          inputFileA = args[3];
          inputFileB = args[4];
          if (args.length == 6) {
              outputPath = args[5];
          } else {
              if (inputFileB.endsWith(".txt")) {
                  outputPath = inputFileB.substring(0, inputFileB.length() - 4) + "_comparison_results.bedpe";
              } else if (inputFileB.endsWith(".bedpe")) {
                  outputPath = inputFileB.substring(0, inputFileB.length() - 6) + "_comparison_results.bedpe";
              } else {
                  outputPath = inputFileB + "_comparison_results.bedpe";
              }
          }
  
          int specifiedMatrixSize = juicerParser.getMatrixSizeOption();
          if (specifiedMatrixSize >= 0) {
              threshold = specifiedMatrixSize;
          }
      }
  
  
      @Override
      public void run() {
  
          ChromosomeHandler handler = HiCFileTools.loadChromosomes(genomeID);
          if (givenChromosomes != null)
              handler = HiCFileTools.stringToChromosomes(givenChromosomes, handler);
  
          Feature2DList listA = null, listB = null;
          if (compareTypeID == 0) {
              listA = Feature2DParser.loadFeatures(inputFileA, handler, false, null, false);
              listB = Feature2DParser.loadFeatures(inputFileB, handler, false, null, false);
  
          } else if (compareTypeID == 1 || compareTypeID == 2) {
              Feature2DWithMotif.useSimpleOutput = true;
              listA = Feature2DParser.loadFeatures(inputFileA, handler, true, null, true);
              listB = Feature2DParser.loadFeatures(inputFileB, handler, true, null, true);
          }
  
          if (compareTypeID == 2) {
              generateHistogramMetrics(listB);
          } else {
              compareTwoLists(listA, listB, compareTypeID);
          }
      }
  
      private void generateHistogramMetrics(Feature2DList list) {
          final int[] metrics = MotifAnchorTools.calculateConvergenceHistogram(list);
          System.out.println("++ : " + metrics[0] + " +- : " + metrics[1] + " -+ : " + metrics[2] + " -- : " + metrics[3]
                  + " not unique : " + metrics[4] + " not complete : " + metrics[5]);
      }
  
      private void compareTwoLists(Feature2DList listA, Feature2DList listB, int compareTypeID) {
          int sizeA = listA.getNumTotalFeatures();
          int sizeB = listB.getNumTotalFeatures();
          System.out.println("List Size: " + sizeA + "(A) " + sizeB + "(B)");
  
          if (compareTypeID == 0) {
              Feature2D.tolerance = 0;
          } else if (compareTypeID == 1) {
              Feature2D.tolerance = threshold;
          }
          Feature2DWithMotif.lenientEqualityEnabled = false;
  
          Feature2DList exactMatches = Feature2DList.getIntersection(listA, listB);
          int numExactMatches = exactMatches.getNumTotalFeatures();
          System.out.println("Number of exact matches: " + numExactMatches);
  
          Feature2D.tolerance = this.threshold;
          Feature2DWithMotif.lenientEqualityEnabled = true;
          //Feature2DList matchesWithinToleranceFromA = Feature2DList.getIntersection(listA, listB);
          //Feature2DList matchesWithinToleranceFromB = Feature2DList.getIntersection(listB, listA);
  
          if (compareTypeID == 0 || compareTypeID == 1) {
              Feature2D.tolerance = threshold;
          }
          Feature2DWithMotif.lenientEqualityEnabled = false;
  
          Feature2DList matchesWithinToleranceUniqueToA = Feature2DTools.subtract(listA, exactMatches);
          matchesWithinToleranceUniqueToA = Feature2DList.getIntersection(matchesWithinToleranceUniqueToA, listB);
  
          Feature2DList matchesWithinToleranceUniqueToB = Feature2DTools.subtract(listB, exactMatches);
          matchesWithinToleranceUniqueToB = Feature2DList.getIntersection(matchesWithinToleranceUniqueToB, listA);
  
          int numMatchesWithinTolA = matchesWithinToleranceUniqueToA.getNumTotalFeatures();
          int numMatchesWithinTolB = matchesWithinToleranceUniqueToB.getNumTotalFeatures();
  
          System.out.println("Number of matches within tolerance: " + numMatchesWithinTolA + "(A) " + numMatchesWithinTolB + "(B)");
  
          Feature2DList uniqueToA = Feature2DTools.subtract(listA, exactMatches);
          uniqueToA = Feature2DTools.subtract(uniqueToA, matchesWithinToleranceUniqueToA);
          uniqueToA = Feature2DTools.subtract(uniqueToA, listB);
  
          Feature2DList uniqueToB = Feature2DTools.subtract(listB, exactMatches);
          uniqueToB = Feature2DTools.subtract(uniqueToB, matchesWithinToleranceUniqueToB);
          uniqueToB = Feature2DTools.subtract(uniqueToB, listA);
  
          int numUniqueToA = uniqueToA.getNumTotalFeatures();
          int numUniqueToB = uniqueToB.getNumTotalFeatures();
  
          System.out.println("Number of unique features: " + numUniqueToA + "(A) " + numUniqueToB + "(B)");
  
          // set parent attribute
          exactMatches.addAttributeFieldToAll(PARENT_ATTRIBUTE, "Common");
          matchesWithinToleranceUniqueToA.addAttributeFieldToAll(PARENT_ATTRIBUTE, "A");
          matchesWithinToleranceUniqueToB.addAttributeFieldToAll(PARENT_ATTRIBUTE, "B");
          uniqueToA.addAttributeFieldToAll(PARENT_ATTRIBUTE, "A*");
          uniqueToB.addAttributeFieldToAll(PARENT_ATTRIBUTE, "B*");
  
          // set colors
          exactMatches.setColor(AB);
          matchesWithinToleranceUniqueToA.setColor(AA);
          matchesWithinToleranceUniqueToB.setColor(BB);
          uniqueToA.setColor(AAA);
          uniqueToB.setColor(BBB);
  
          Feature2DList finalResults = new Feature2DList(exactMatches);
          finalResults.add(matchesWithinToleranceUniqueToA);
          finalResults.add(matchesWithinToleranceUniqueToB);
          finalResults.add(uniqueToA);
          finalResults.add(uniqueToB);
  
          uniqueToA.exportFeatureList(new File(outputPath + "_AAA.bedpe"), false, Feature2DList.ListFormat.NA);
          uniqueToB.exportFeatureList(new File(outputPath + "_BBB.bedpe"), false, Feature2DList.ListFormat.NA);
          finalResults.exportFeatureList(new File(outputPath), false, Feature2DList.ListFormat.NA);
  
          int percentMatch = (int) Math.round(100 * ((double) (sizeB - numUniqueToB)) / ((double) sizeB));
          if (percentMatch > 95) {
              System.out.println("Test passed");
          } else {
              System.out.println("Test failed - " + percentMatch + "% match with reference list");
          }
      }
  }
  