package uk.ac.ebi.gxa.loader.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.ebi.gxa.loader.datamatrix.DataMatrixStorage;
import uk.ac.ebi.gxa.utils.CBitSet;
import uk.ac.ebi.gxa.utils.CPair;
import uk.ac.ebi.gxa.utils.EfvTree;
import uk.ac.ebi.gxa.utils.Pair;
import uk.ac.ebi.microarray.atlas.model.Assay;
import uk.ac.ebi.microarray.atlas.model.Sample;

import java.util.*;

import static java.util.Collections.sort;

class NetCDFData {
    final private Logger log = LoggerFactory.getLogger(this.getClass());

    // Note that matchedUniqueValues includes both ef-efvs ad sc-scvs
    private EfvTree<CPair<String, String>> matchedUniqueValues = null;
    private DataMatrixStorage storage;
    private List<String> uniqueValues; // scvs/efvs
    private final Map<Assay, List<Sample>> assayToSamples = new LinkedHashMap<Assay, List<Sample>>();


    public void setStorage(DataMatrixStorage storage) {
        this.storage = storage;
    }

    public void addToStorage(String designElement, Iterator<Float> values) {
        storage.add(designElement, values);
    }

    public void setUniqueValues(List<String> uniqueValues) {
        this.uniqueValues = uniqueValues;
    }

    public List<Assay> getAssays() {
        return new ArrayList<Assay>(assayToSamples.keySet());
    }

    public void addAssay(Assay assay) {
        assayToSamples.put(assay, assay.getSamples());
    }

    int getWidth() {
        return assayToSamples.keySet().size() + (isAnalyticsTransferred() ? uniqueValues.size() * 2 : 0);  // expressions + pvals + tstats
    }

    boolean isAnalyticsTransferred() {
        return matchedUniqueValues != null;
    }

    Map<Pair<String, String>, DataMatrixStorage.ColumnRef> getTStatDataMap() {
        if (!isAnalyticsTransferred())
            return null;

        Map<Pair<String, String>, DataMatrixStorage.ColumnRef> tstatMap = new HashMap<Pair<String, String>, DataMatrixStorage.ColumnRef>();
        for (EfvTree.EfEfv<CPair<String, String>> efEfv : matchedUniqueValues.getNameSortedList()) {
            final int oldPos = uniqueValues.indexOf(encodeEfEfv(efEfv.getPayload()));
            tstatMap.put(Pair.create(efEfv.getEf(), efEfv.getEfv()),
                    new DataMatrixStorage.ColumnRef(storage, assayToSamples.keySet().size() + uniqueValues.size() + oldPos));
        }
        return tstatMap;
    }

    Map<Pair<String, String>, DataMatrixStorage.ColumnRef> getPValDataMap() {
        if (!isAnalyticsTransferred())
            return null;

        Map<Pair<String, String>, DataMatrixStorage.ColumnRef> pvalMap = new HashMap<Pair<String, String>, DataMatrixStorage.ColumnRef>();
        for (EfvTree.EfEfv<CPair<String, String>> efEfv : matchedUniqueValues.getNameSortedList()) {
            final int oldPos = uniqueValues.indexOf(encodeEfEfv(efEfv.getPayload()));
            pvalMap.put(Pair.create(efEfv.getEf(), efEfv.getEfv()),
                    new DataMatrixStorage.ColumnRef(storage, assayToSamples.keySet().size() + oldPos));
        }
        return pvalMap;
    }

    private String encodeEfEfv(CPair<String, String> pair) {
        return pair.getFirst() + "||" + pair.getSecond();
    }

    Map<String, DataMatrixStorage.ColumnRef> getAssayDataMap() {
        Map<String, DataMatrixStorage.ColumnRef> result = new HashMap<String, DataMatrixStorage.ColumnRef>();
        int i = 0;
        for (Assay assay : assayToSamples.keySet()) {
            result.put(assay.getAccession(), new DataMatrixStorage.ColumnRef(storage, i));
            i++;
        }
        return result;
    }

    private EfvTree<CPair<String, String>> matchUniqueValues
            (EfvTree<CBitSet> from, EfvTree<CBitSet> to) {
        final List<EfvTree.Ef<CBitSet>> fromTree = matchValuesSort(from);
        final List<EfvTree.Ef<CBitSet>> toTree = matchValuesSort(to);

        EfvTree<CPair<String, String>> result = new EfvTree<CPair<String, String>>();
        for (EfvTree.Ef<CBitSet> toProperty : toTree) {
            List<EfvTree.Efv<CBitSet>> dest = new ArrayList<EfvTree.Efv<CBitSet>>(toProperty.getEfvs());
            Collections.sort(dest);

            boolean matched = false;
            for (EfvTree.Ef<CBitSet> fromProperty : fromTree) {
                List<EfvTree.Efv<CBitSet>> src = new ArrayList<EfvTree.Efv<CBitSet>>(fromProperty.getEfvs());
                Collections.sort(src);

                // So basically for each EF/SC in the destination we find all the EF/SCs having the same number of EFVs/SCVs
                // and assume these are the same EFs/SCs as proven by comparing payloads, i.e. bit patterns
                // The very reason for it is, we can rename EFs/SCs, and we have no surrogate keys for them, so
                // we can only guess whether or not EFs/SCs are same. Still, as long as the number of EFVs stays the same
                // and assays are assigned to EFVs in the same manner, statistics don't change, hence we should be
                // safe to carry it over
                if (!src.equals(dest))
                    continue;

                for (int i = 0; i < src.size(); ++i)
                    result.putCaseSensitive(toProperty.getEf(), dest.get(i).getEfv(),
                            new CPair<String, String>(fromProperty.getEf(), src.get(i).getEfv()));
                matched = true;
            }

            if (!matched) {
                log.info("NetCDF and DB EF/SC values not matched -- will need to recompute statistics");
                return null;
            }
        }

        return result;
    }

    private List<EfvTree.Ef<CBitSet>> matchValuesSort(EfvTree<CBitSet> efvTree) {
        final List<EfvTree.Ef<CBitSet>> fromTree = efvTree.getNameSortedTree();
        for (EfvTree.Ef<CBitSet> ef : fromTree) {
            sort(ef.getEfvs());
        }
        return fromTree;
    }
}

@@ -36,65 +36,8 @@
 e;%0A%0A
-import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A
 impo
@@ -412,82 +412,8 @@
 a %7B%0A
-    final private Logger log = LoggerFactory.getLogger(this.getClass());%0A%0A
     
@@ -3586,1866 +3586,19 @@
     
-final List%3CEfvTree.Ef%3CCBitSet%3E%3E fromTree = matchValuesSort(from);%0A        final List%3CEfvTree.Ef%3CCBitSet%3E%3E toTree = matchValuesSort(to);%0A%0A        EfvTree%3CCPair%3CString, String%3E%3E result = new EfvTree%3CCPair%3CString, String%3E%3E();%0A        for (EfvTree.Ef%3CCBitSet%3E toProperty : toTree) %7B%0A            List%3CEfvTree.Efv%3CCBitSet%3E%3E dest = new ArrayList%3CEfvTree.Efv%3CCBitSet%3E%3E(toProperty.getEfvs());%0A            Collections.sort(dest);%0A%0A            boolean matched = false;%0A            for (EfvTree.Ef%3CCBitSet%3E fromProperty : fromTree) %7B%0A                List%3CEfvTree.Efv%3CCBitSet%3E%3E src = new ArrayList%3CEfvTree.Efv%3CCBitSet%3E%3E(fromProperty.getEfvs());%0A                Collections.sort(src);%0A%0A                // So basically for each EF/SC in the destination we find all the EF/SCs having the same number of EFVs/SCVs%0A                // and assume these are the same EFs/SCs as proven by comparing payloads, i.e. bit patterns%0A                // The very reason for it is, we can rename EFs/SCs, and we have no surrogate keys for them, so%0A                // we can only guess whether or not EFs/SCs are same. Still, as long as the number of EFVs stays the same%0A                // and assays are assigned to EFVs in the same manner, statistics don't change, hence we should be%0A                // safe to carry it over%0A                if (!src.equals(dest))%0A                    continue;%0A%0A                for (int i = 0; i %3C src.size(); ++i)%0A                    result.putCaseSensitive(toProperty.getEf(), dest.get(i).getEfv(),%0A                            new CPair%3CString, String%3E(fromProperty.getEf(), src.get(i).getEfv()));%0A                matched = true;%0A            %7D%0A%0A            if (!matched) %7B%0A                log.info(%22NetCDF and DB EF/SC values not matched -- will need to recompute statistics%22);%0A                return null;%0A            %7D%0A        %7D%0A%0A        return result
+return null
 ;%0A  

Make review easier by dropping dead code (it won't be used in this branch, ever)