package uk.ac.ebi.atlas.profiles.json;

import com.google.common.base.Function;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import uk.ac.ebi.atlas.model.*;
import uk.ac.ebi.atlas.search.SemanticQuery;
import uk.ac.ebi.atlas.search.baseline.BaselineExperimentProfile;
import uk.ac.ebi.atlas.search.baseline.BaselineExperimentProfilesList;
import uk.ac.ebi.atlas.search.baseline.LinkToBaselineProfile;

import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class ExternallyViewableProfilesList<DataColumnDescriptor extends DescribesDataColumns,
        Prof extends Profile<DataColumnDescriptor, ? extends Expression, Prof>, Unit extends ExpressionUnit> {

    private final GeneProfilesList<Prof> profiles;

    private final Function<Prof, URI> provideLinkToProfile;

    private final List<DataColumnDescriptor> prescribedOrderOfColumns;

    private final Function<Prof, Unit> expressionUnitForProfile;

    public ExternallyViewableProfilesList(GeneProfilesList<Prof> profiles,
                                          Function<Prof, URI> provideLinkToProfile,
                                          List<DataColumnDescriptor> prescribedOrderOfColumns,
                                          Function<Prof, Unit> expressionUnitForProfile){
        this.profiles = profiles;
        this.provideLinkToProfile = provideLinkToProfile;
        this.prescribedOrderOfColumns = prescribedOrderOfColumns;
        this.expressionUnitForProfile = expressionUnitForProfile;
    }

    public static ExternallyViewableProfilesList<FactorAcrossExperiments, BaselineExperimentProfile, ExpressionUnit.Absolute>
    createForExperimentProfiles(SemanticQuery geneQuery, BaselineExperimentProfilesList experimentProfiles, List<FactorAcrossExperiments> dataColumns) {
        return new ExternallyViewableProfilesList<>(
                experimentProfiles, new LinkToBaselineProfile(geneQuery), dataColumns, (Function<BaselineExperimentProfile, ExpressionUnit.Absolute>) baselineExperimentProfile -> baselineExperimentProfile.getExperimentType().isRnaSeqBaseline() ? ExpressionUnit.Absolute.Rna.TPM : ExpressionUnit.Absolute.Protein.ANY);
    }

    public JsonObject asJson(){
        JsonObject result = new JsonObject();
        for(Map.Entry<String, String> e: profiles.properties().entrySet()){
            result.addProperty(e.getKey(), e.getValue());
        }

        JsonArray rows = new JsonArray();
        for(Prof profile : profiles){
            rows.add(convert(profile));
        }
        result.add("rows", rows);

        return result;
    }

    private JsonObject convert(Prof profile){

        JsonObject result = new JsonObject();
        for(Map.Entry<String, String> e: profile.properties().entrySet()){
            result.addProperty(e.getKey(), e.getValue());
        }
        JsonArray expressions = new JsonArray();
        for(DataColumnDescriptor c: prescribedOrderOfColumns){
            expressions.add(Optional.ofNullable(profile.getExpression(c)).map(e -> e.toJson()).orElse(new JsonObject()));
        }
        result.add("expressions", expressions);
        result.addProperty("uri", provideLinkToProfile.apply(profile).toString());
        result.addProperty("expressionUnit", expressionUnitForProfile.apply(profile).toString());

        return result;

    }



}

@@ -1313,16 +1313,17 @@
 Profile)
+ 
 %7B%0A      
@@ -1564,16 +1564,20 @@
 c static
+%0A   
  Externa
@@ -1733,16 +1733,48 @@
 neQuery,
+%0A                               
  Baselin
@@ -1816,16 +1816,48 @@
 rofiles,
+%0A                               
  List%3CFa
@@ -1982,16 +1982,32 @@
 rofiles,
+%0A               
  new Lin
@@ -2040,84 +2040,53 @@
 ry),
- dataColumns, (Function%3CBaselineExperimentProfile, ExpressionUnit.Absolute%3E)
+%0A                dataColumns,%0A               
  bas
@@ -2177,16 +2177,40 @@
 line() ?
+%0A                       
  Express
@@ -2235,16 +2235,40 @@
 na.TPM :
+%0A                       
  Express
@@ -2335,16 +2335,17 @@
 asJson()
+ 
 %7B%0A      
@@ -2387,32 +2387,33 @@
 t();%0A        for
+ 
 (Map.Entry%3CStrin
@@ -2451,32 +2451,33 @@
 es().entrySet())
+ 
 %7B%0A            re
@@ -2770,16 +2770,17 @@
 profile)
+ 
 %7B%0A%0A     
@@ -2831,16 +2831,17 @@
      for
+ 
 (Map.Ent
@@ -2894,16 +2894,17 @@
 rySet())
+ 
 %7B%0A      
@@ -3025,16 +3025,17 @@
      for
+ 
 (DataCol
@@ -3076,16 +3076,17 @@
 Columns)
+ 
 %7B%0A      
@@ -3127,16 +3127,37 @@
 ullable(
+%0A                    
 profile.
@@ -3493,12 +3493,10 @@
 %0A    %7D%0A%0A
-%0A%0A
 %7D%0A

Reformat code