package uk.ac.ebi.quickgo.index.annotation.coterms;

import uk.ac.ebi.quickgo.annotation.common.document.AnnotationDocMocker;
import uk.ac.ebi.quickgo.annotation.common.document.AnnotationDocument;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Before;
import org.junit.Test;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;

/**
 * @author Tony Wardell
 * Date: 26/11/2015
 * Time: 16:26
 * Created with IntelliJ IDEA.
 */
public class CoTermsAggregationWriterTest {

    public static final String[] TWO_SAME_GENEPRODUCTS = {"A0A000", "A0A000"};
    public static final String[] TWO_DIFFERENT_GENE_PRODUCTS = {"A0A000", "A0A001"};
    public static final String REPLACEMENT_GOID = "GO:0009999";
    CoTermsAggregationWriter aggregator;

    @Before
    public void setup() {
        aggregator = new CoTermsAggregationWriter(t -> true);
    }

    @Test
    public void calculateStatisticsForTwoRecordsWithTheSameGoTerm() throws Exception {

        List<AnnotationDocument> docs = writeDocs(TWO_SAME_GENEPRODUCTS);
        completeAggregation(docs);

        //Now test
        Map<String, Map<String, AtomicLong>> matrix = aggregator.getCoTerms();

        assertThat(matrix.keySet(), hasSize(1));

        Map<String, AtomicLong> coTerms = matrix.get(AnnotationDocMocker.GO_ID);
        assertThat(coTerms, is(notNullValue()));
        assertThat(coTerms.keySet(), hasSize(1));

        //Is the only one
        AtomicLong ac = coTerms.get(AnnotationDocMocker.GO_ID);
        assertThat(ac.get(), is(1L));

        assertThat(aggregator.getTotalOfAnnotatedGeneProducts(), is(1L));
        assertThat(aggregator.getGeneProductCounts().keySet(), hasSize(1));
        assertThat(aggregator.getGeneProductCounts().get(docs.get(0).goId).get(), is(1L));
        assertThat(aggregator.getGeneProductCounts().get(docs.get(1).goId).get(), is(1L));

    }

    @Test
    public void calculateStatisticsForTwoRecordsWithDifferentGoTermsAndDifferentGeneProductSoNoCoTerms() throws
                                                                                                         Exception {
        List<AnnotationDocument> docs = writeDocs(TWO_DIFFERENT_GENE_PRODUCTS);
        docs.get(1).goId = REPLACEMENT_GOID;
        completeAggregation(docs);

        Map<String, Map<String, AtomicLong>> matrix = aggregator.getCoTerms();

        assertThat(matrix.keySet(), hasSize(2));

        Map<String, AtomicLong> coTerms1 = matrix.get(docs.get(0).goId);
        assertThat(coTerms1.keySet(), hasSize(1));
        AtomicLong ac1 = coTerms1.get(docs.get(0).goId);
        assertThat(ac1.get(), is(1l));

        Map<String, AtomicLong> coTerms2 = matrix.get(docs.get(1).goId);
        assertThat(coTerms2.keySet(), hasSize(1));
        AtomicLong ac2 = coTerms2.get(docs.get(1).goId);
        assertThat(ac2.get(), is(1l));

        assertThat(aggregator.getTotalOfAnnotatedGeneProducts(), is(2l));
        assertThat(aggregator.getGeneProductCounts().keySet(), hasSize(2));
        assertThat(aggregator.getGeneProductCounts().get(docs.get(0).goId).get(), is(1L));
        assertThat(aggregator.getGeneProductCounts().get(docs.get(1).goId).get(), is(1L));
    }

    @Test
    public void calculateStatisticsForTwoRecordsWithTheDifferentGoTermsSameGeneProduct() throws Exception {

        List<AnnotationDocument> docs = writeDocs(TWO_SAME_GENEPRODUCTS);
        docs.get(1).goId = REPLACEMENT_GOID;
        completeAggregation(docs);

        //Now test
        Map<String, Map<String, AtomicLong>> matrix = aggregator.getCoTerms();

        assertThat(matrix.keySet(), hasSize(2));

        Map<String, AtomicLong> coTerms1 = matrix.get(docs.get(0).goId);
        assertThat(coTerms1.keySet(), hasSize(2));
        AtomicLong ac1x1 = coTerms1.get(docs.get(0).goId);
        assertThat(ac1x1.get(), is(1L));
        AtomicLong ac1x2 = coTerms1.get(docs.get(1).goId);
        assertThat(ac1x1.get(), is(1L));

        Map<String, AtomicLong> coTerms2 = matrix.get(docs.get(1).goId);
        assertThat(coTerms2.keySet(), hasSize(2));
        AtomicLong ac2x1 = coTerms2.get(docs.get(1).goId);
        assertThat(ac2x1.get(), is(1L));
        AtomicLong ac2x2 = coTerms2.get(docs.get(1).goId);
        assertThat(ac2x2.get(), is(1L));

        assertThat(aggregator.getTotalOfAnnotatedGeneProducts(), is(1L));
        assertThat(aggregator.getGeneProductCounts().keySet(), hasSize(2));
        assertThat(aggregator.getGeneProductCounts().get(docs.get(0).goId).get(), is(1L));
        assertThat(aggregator.getGeneProductCounts().get(docs.get(1).goId).get(), is(1L));
    }

    @Test
    public void zeroAnnotationsProcessedIfPredicateNotTrue() throws Exception {
        List<AnnotationDocument> docs = writeDocs(TWO_SAME_GENEPRODUCTS);
        completeAggregation(docs);

        CoTermsAggregationWriter aggregatorFalse = new CoTermsAggregationWriter(t -> false);
        Map<String, Map<String, AtomicLong>> matrix = aggregatorFalse.getCoTerms();
        assertThat(matrix.keySet(), hasSize(0));
        assertThat(aggregatorFalse.getTotalOfAnnotatedGeneProducts(), is(0L));
        assertThat(aggregatorFalse.getGeneProductCounts().keySet(), hasSize(0));
    }

    @Test(expected = IllegalArgumentException.class)
    public void exceptionThrownIfNullAnnotationPassedToAddRowToMatrix() throws Exception {
        aggregator.write(null);
    }

    @Test(expected = IllegalArgumentException.class)
    public void exceptionThrownIfNullPredicatePassedToConstructor() {
        new CoTermsAggregationWriter(null);
    }

    private List<AnnotationDocument> writeDocs(String... geneProductIds) throws Exception {
        List<AnnotationDocument> docs = new ArrayList<>();

        for (int i = 0; i < geneProductIds.length; i++) {
            docs.add(AnnotationDocMocker.createAnnotationDoc(geneProductIds[i]));
        }
        return docs;
    }

    private void completeAggregation(List<AnnotationDocument> docs) throws Exception {
        aggregator.write(docs);
        aggregator.finish();
    }

}

@@ -717,29 +717,30 @@
 est %7B%0A%0A    p
-ublic
+rivate
  static fina
@@ -793,37 +793,38 @@
 %22A0A000%22%7D;%0A    p
-ublic
+rivate
  static final St
@@ -887,21 +887,22 @@
 %7D;%0A    p
-ublic
+rivate
  static 
@@ -5945,49 +5945,45 @@
 or (
-int i = 0; i %3C geneProductIds.length; i++
+String geneProductId : geneProductIds
 ) %7B%0A
@@ -6060,12 +6060,8 @@
 ctId
-s%5Bi%5D
 ));%0A

Make constants private.