package org.broad.tribble.readers;

import org.apache.log4j.Logger;
import org.broad.tribble.index.Block;
import org.broad.tribble.index.Index;
import org.broad.tribble.index.IndexFactory;
import org.broad.tribble.util.*;

import java.io.IOException;
import java.util.List;
import java.util.Set;

/**
 * Created by IntelliJ IDEA.
 * User: jrobinso
 * Date: May 17, 2010
 * Time: 3:26:34 PM
 * To change this template use File | Settings | File Templates.
 */
public class AsciiQueryReader implements QueryReader {

    private static Logger log = Logger.getLogger(BasicFeatureReader.class);

    protected SeekableStream seekableStream;
    protected Index index;

    public AsciiQueryReader(String featureFile, String indexFile) throws IOException {
        seekableStream = SeekableStreamFactory.getStreamFor(featureFile);
        index = IndexFactory.loadIndex(indexFile);
    }

    public AsciiQueryReader(String featureFile) throws IOException {
        String indexFile = featureFile + ".idx";
        seekableStream = SeekableStreamFactory.getStreamFor(featureFile);
        index = IndexFactory.loadIndex(indexFile);
    }

    public AsciiQueryReader(String featureFile, Index indexInstance) throws IOException {
        seekableStream = SeekableStreamFactory.getStreamFor(featureFile);
        this.index = indexInstance;
    }


    public void close() throws IOException {
        if (seekableStream != null) {
            seekableStream.close();
        }
    }

    public LineReader iterate() throws IOException {
        seekableStream.seek(0);
        return new AsciiLineReader(seekableStream);
    }

    public LineReader query(String chr, int start, int end) {
        return new IndexedReader(chr, start, end);
    }

    public Set<String> getSequenceNames() {
        return index.getSequenceNames();
    }



    public class IndexedReader implements LineReader {

        String chr;
        int start;
        int end;

        AsciiLineReader reader;
        List<Block> blocks;


        // Return a reader to loop over the whole file

        public IndexedReader() {
            reader = new AsciiLineReader(seekableStream);
        }

        // Return a reader to loop over to stream over a query inerval

        public IndexedReader(String chr, int start, int end) {
            this.chr = chr;
            this.start = start;
            this.end = end;
            init();
        }

        public String readLine() throws IOException {
            return reader == null ? null : reader.readLine();
        }

        public void close() {
            if(reader != null) reader.close();
        }


        /**
         * Initialize the reader
         * <p/>
         * todo -- the block collection is really not used, this implementation will stream over entire extent
         * todo -- covered by range of blocks.
         */
        private void init() {

            if (index == null) {
                throw new UnsupportedOperationException("Files must be indexed to support query methods");
            }

            blocks = index.getBlocks(chr, start, end);

            if (blocks == null || blocks.size() == 0) {
                // No features for this query
                reader = null;

            } else {
                Block firstBlock = blocks.get(0);
                Block lastBlock = blocks.get(blocks.size() - 1);

                try {
                    seekableStream.seek(firstBlock.getStartPosition());
                    reader = new AsciiLineReader(seekableStream);
                } catch (IOException ex) {
                    log.error("Error seeking to position: " + firstBlock.getStartPosition(), ex);
                    // TODO -- throw application exception?
                }
            }

        }
    }

}
