package uk.ac.ebi.atlas.experimentloader.analytics.baseline;

import au.com.bytecode.opencsv.CSVReader;
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import uk.ac.ebi.atlas.commons.streams.ObjectInputStream;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

import static com.google.common.base.Preconditions.checkArgument;

/*
 * Reads tsv input of:
 *
 * Gene ID Gene Name g1 g2 g3 g4 g5
 * mus1    musName    1  2  3  0  5
 *
 * and returns BaselineExpressionDTOs of:
 *
 * mus1, g1, 1
 * mus1, g2, 2
 * mus1, g3, 3
 * mus1, g5, 5
 *
 * NB: expression levels of 0 are skipped
 */
public class BaselineExpressionDtoInputStream implements ObjectInputStream<BaselineExpressionDto> {

    private static final Logger LOGGER = Logger.getLogger(BaselineExpressionDtoInputStream.class);

    private static final int GENE_ID_COLUMN_INDEX = 0;
    private static final int FIRST_EXPRESSION_LEVEL_INDEX = 2;

    private final CSVReader csvReader;
    private final Queue<BaselineExpressionDto> queue = new LinkedList<>();
    private final String[] assayGroupIds;

    public BaselineExpressionDtoInputStream(CSVReader csvReader) {
        this.csvReader = csvReader;
        String[] headers = readCsvLine();
        this.assayGroupIds = (String[]) ArrayUtils.subarray(headers, FIRST_EXPRESSION_LEVEL_INDEX, headers.length);
    }

    @Override
    public void close() throws IOException {
        csvReader.close();
    }

    private String[] readCsvLine() {
        try {
            return csvReader.readNext();
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
            throw new IllegalStateException("Exception thrown while reading next csv line.", e);
        }
    }

    @Override
    public BaselineExpressionDto readNext() {
        if (queue.isEmpty()) {
            ImmutableList<? extends BaselineExpressionDto> baselineExpressionDtos = readNextLineOfExpressionLevels();

            if (baselineExpressionDtos == null) {
                //EOF
                return null;
            }

            queue.addAll(baselineExpressionDtos);
        }

        return queue.remove();
    }


    private ImmutableList<? extends BaselineExpressionDto> readNextLineOfExpressionLevels() {

        ImmutableList<? extends BaselineExpressionDto> baselineExpressionDtos;

        // loop until we have a line of expression levels, or return null if EOF
        do {
            String[] line = readCsvLine();
            if (line == null) {
                // EOF
                return null;
            }

            String geneId = line[GENE_ID_COLUMN_INDEX];
            String[] expressionLevels = (String[]) ArrayUtils.subarray(line, FIRST_EXPRESSION_LEVEL_INDEX, line.length);
            baselineExpressionDtos = createList(geneId, assayGroupIds, expressionLevels);
        } while (baselineExpressionDtos.isEmpty());

        return baselineExpressionDtos;

    }

    private ImmutableList<? extends BaselineExpressionDto> createList(String geneId, String[] assayGroupIds, String[] expressionLevels) {
        checkArgument(assayGroupIds.length == expressionLevels.length);

        ImmutableList.Builder<BaselineExpressionDto> builder = ImmutableList.builder();

        for (int i = 0; i < expressionLevels.length; i++) {
            String assayGroupId = assayGroupIds[i];
            Double expressionLevel = Double.parseDouble(expressionLevels[i]);
            if (expressionLevel != 0.0) {
                builder.add(new BaselineExpressionDto(geneId, assayGroupId, expressionLevel));
            }
        }

        return builder.build();
    }
}

@@ -1992,38 +1992,27 @@
 readNext
-LineOfExpressionLevels
+NonZeroLine
 ();%0A%0A   
@@ -2223,17 +2223,16 @@
 %0A    %7D%0A%0A
-%0A
     priv
@@ -2294,214 +2294,25 @@
 Next
-LineOfExpressionLevels() %7B%0A%0A        ImmutableList%3C? extends BaselineExpressionDto%3E baselineExpressionDtos;%0A%0A        // loop until we have a line of expression levels, or return null if EOF%0A        do %7B%0A    
+NonZeroLine() %7B%0A%0A
     
@@ -2350,28 +2350,24 @@
 ();%0A        
-   
- 
 if (line == 
@@ -2390,23 +2390,15 @@
     
-    
 // EOF%0A
-    
     
@@ -2422,35 +2422,27 @@
 ll;%0A        
-    %7D%0A%0A    
+%7D%0A%0A
         Stri
@@ -2481,20 +2481,16 @@
 INDEX%5D;%0A
-    
         
@@ -2606,19 +2606,62 @@
         
-   
+ImmutableList%3C? extends BaselineExpressionDto%3E
  baselin
@@ -2731,24 +2731,25 @@
 evels);%0A
+%0A
         
 %7D while 
@@ -2744,15 +2744,10 @@
     
-%7D while
+if
  (ba
@@ -2777,16 +2777,45 @@
 Empty())
+ return readNextNonZeroLine()
 ;%0A%0A     
@@ -2848,17 +2848,16 @@
 onDtos;%0A
-%0A
     %7D%0A%0A 

refactor - use recursion, its cleaner