/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.google.cloud.genomics.localrepo;

import com.google.cloud.genomics.localrepo.BamFile.IndexedBamFile;
import com.google.cloud.genomics.localrepo.dto.Readset;
import com.google.cloud.genomics.localrepo.util.Suppliers;

import net.sf.picard.sam.SamFileHeaderMerger;
import net.sf.samtools.SAMFileHeader;
import net.sf.samtools.SAMFileHeader.SortOrder;

import org.joda.time.DateTimeUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class BamFilesReadset {

  public static BamFilesReadset create(
      String readsetId,
      String sample,
      String datasetId,
      Set<IndexedBamFile> bamFiles) {
    return new BamFilesReadset(readsetId, sample, datasetId, bamFiles);
  }

  private final Set<IndexedBamFile> bamFiles;
  private final String datasetId;
  private final String readsetId;
  private final String sample;

  private final Supplier<Readset> readset = Suppliers.memoize(() -> Readset.create(
      getReadsetId(), getSample(), getDatasetId(), DateTimeUtils.currentTimeMillis(), getBamFiles()
      .stream().map(BamFile::getFileData).collect(Collectors.toCollection(() -> new ArrayList<>(
      new TreeSet<>(Comparator.comparing(Readset.FileData::getFileUri)))))));

  private final Supplier<SAMFileHeader> header = Suppliers.memoize(() -> new SamFileHeaderMerger(
      SortOrder.coordinate, bamFiles.stream().map(BamFile::getHeader).collect(Collectors.toList()),
      true).getMergedHeader());

  private BamFilesReadset(
      String readsetId,
      String sample,
      String datasetId,
      Set<IndexedBamFile> bamFiles) {
    this.readsetId = readsetId;
    this.sample = sample;
    this.datasetId = datasetId;
    this.bamFiles = bamFiles;
  }

  @Override public boolean equals(Object obj) {
    if (null != obj && BamFilesReadset.class == obj.getClass()) {
      BamFilesReadset rhs = (BamFilesReadset) obj;
      return Objects.equals(getReadsetId(), rhs.getReadsetId())
          && Objects.equals(getSample(), rhs.getSample())
          && Objects.equals(getDatasetId(), rhs.getDatasetId())
          && Objects.equals(getBamFiles(), rhs.getBamFiles());
    }
    return false;
  }

  public Set<IndexedBamFile> getBamFiles() {
    return bamFiles;
  }

  public String getDatasetId() {
    return datasetId;
  }

  public Readset getReadset() {
    return readset.get();
  }

  public String getReadsetId() {
    return readsetId;
  }

  public String getSample() {
    return sample;
  }

  @Override public int hashCode() {
    return Objects.hash(
        getReadsetId(),
        getSample(),
        getDatasetId(),
        getBamFiles());
  }

  @Override public String toString() {
    return String.format(
        "readsetId: %s sample: %s datasetId: %s bamFiles: %s",
        getReadset(),
        getSample(),
        getDatasetId(),
        getBamFiles());
  }

  SAMFileHeader getHeader() {
    return header.get();
  }
}

@@ -1576,17 +1576,16 @@
 sample;%0A
-%0A
   privat
@@ -1614,17 +1614,327 @@
 et%3E 
+readset;%0A  private final Supplier%3CSAMFileHeader%3E header;%0A%0A  private BamFilesReadset(String readsetId, String sample, String datasetId,%0A      Set%3CIndexedBamFile%3E bamFiles) %7B%0A    this.
 readset
+Id
  =
+ readsetId;%0A    this.sample = sample;%0A    this.datasetId = datasetId;%0A    this.bamFiles = bamFiles;%0A    this.readset =%0A       
  Sup
@@ -1966,24 +1966,30 @@
 set.create(%0A
+      
       getRea
@@ -1997,16 +1997,28 @@
 setId(),
+%0A           
  getSamp
@@ -2022,16 +2022,28 @@
 ample(),
+%0A           
  getData
@@ -2050,16 +2050,28 @@
 setId(),
+%0A           
  DateTim
@@ -2097,16 +2097,28 @@
 illis(),
+%0A           
  getBamF
@@ -2134,52 +2134,117 @@
     
-.stream().map(BamFile::getFileData).collect(
+          .stream()%0A                .map(BamFile::getFileData)%0A                .collect(%0A                    
 Coll
@@ -2285,23 +2285,16 @@
 yList%3C%3E(
-%0A      
 new Tree
@@ -2309,16 +2309,41 @@
 mparator
+%0A                        
 .compari
@@ -2386,57 +2386,33 @@
 ));%0A
-%0A
   
-private final Supplier%3CSAMFileHeader%3E header =
+  this.header =%0A       
  Sup
@@ -2456,23 +2456,16 @@
 rMerger(
-%0A      
 SortOrde
@@ -2495,16 +2495,29 @@
 stream()
+%0A            
 .map(Bam
@@ -2562,22 +2562,16 @@
 List()),
-%0A     
  true).g
@@ -2592,263 +2592,8 @@
 ());
-%0A%0A  private BamFilesReadset(%0A      String readsetId,%0A      String sample,%0A      String datasetId,%0A      Set%3CIndexedBamFile%3E bamFiles) %7B%0A    this.readsetId = readsetId;%0A    this.sample = sample;%0A    this.datasetId = datasetId;%0A    this.bamFiles = bamFiles;
 %0A  %7D

fix compile problem on Mac OS X