/*
 * Copyright (c) 2007-2010 by The Broad Institute, Inc. and the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * This software is licensed under the terms of the GNU Lesser General Public License (LGPL), Version 2.1 which
 * is available at http://www.opensource.org/licenses/lgpl-2.1.php.
 *
 * THE SOFTWARE IS PROVIDED "AS IS." THE BROAD AND MIT MAKE NO REPRESENTATIONS OR WARRANTIES OF
 * ANY KIND CONCERNING THE SOFTWARE, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT
 * OR OTHER DEFECTS, WHETHER OR NOT DISCOVERABLE.  IN NO EVENT SHALL THE BROAD OR MIT, OR THEIR
 * RESPECTIVE TRUSTEES, DIRECTORS, OFFICERS, EMPLOYEES, AND AFFILIATES BE LIABLE FOR ANY DAMAGES OF
 * ANY KIND, INCLUDING, WITHOUT LIMITATION, INCIDENTAL OR CONSEQUENTIAL DAMAGES, ECONOMIC
 * DAMAGES OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER THE BROAD OR MIT SHALL
 * BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE
 * FOREGOING.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.broad.igv.feature.dranger;

import org.apache.log4j.Logger;
import org.broad.igv.exceptions.ParserException;
import org.broad.igv.feature.Feature;
import org.broad.igv.feature.Genome;
import org.broad.igv.feature.Strand;
import org.broad.igv.session.ViewContext;
import org.broad.igv.track.FeatureCollectionSource;
import org.broad.igv.track.FeatureTrack;
import org.broad.igv.util.AsciiLineReader;
import org.broad.igv.util.ParsingUtils;
import org.broad.igv.util.ResourceLocator;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author jrobinso
 */
public class DRangerParser {
    int numColumn;
    int chr1Column;
    int str1Column;
    int pos1Column;
    int chr2Column;
    int str2Column;
    int pos2Column;
    int tumreadsColumn;
    int normreadsColumn;
    int classColumn;
    int spanColumn;
    int site1Column;
    int site2Column;
    int qualityColumn;
    int scoreColumn;

    static Logger log = Logger.getLogger(DRangerParser.class);

    //num	chr1	str1	pos1	chr2	str2	pos2
    //1	    chr1	(+)	21083863	chr1	(+)	25279578
    // tumreads	normreads	class	span	site1	site2	quality	score
    // 48	    0	    long_range	4195715	3'-UTR of ENST0000037493
    public List<FeatureTrack> loadTracks(ResourceLocator locator) {

        String[] tokens = new String[100];
        List<FeatureTrack> tracks = new ArrayList();
        AsciiLineReader reader = null;
        List<Feature> features = new ArrayList(5000);

        int parseColumn = -1;
        String nextLine = null;
        try {
            Genome genome = ViewContext.getInstance().getGenome();

            reader = ParsingUtils.openAsciiReader(locator);
            setColumns(reader.readLine());
            while ((nextLine = reader.readLine()) != null) {
                int nTokens = ParsingUtils.split(nextLine, tokens, '\t');
                if (nTokens > pos2Column) {
                    int index = Integer.parseInt(tokens[numColumn]);

                    String chr1 = genome.getChromosomeAlias(tokens[chr1Column]);
                    int pos1 = Integer.parseInt(tokens[pos1Column]);
                    String str1 = tokens[str1Column];
                    Strand strand1 = (str1.equals("0") || str1.equals("(+)")) ? Strand.POSITIVE : Strand.NEGATIVE;

                    String chr2 = genome.getChromosomeAlias(tokens[chr2Column]);
                    int pos2 = Integer.parseInt(tokens[pos2Column]);
                    String str2 = tokens[str2Column];
                    Strand strand2 = (str2.equals("0") || str2.equals("(+)")) ? Strand.POSITIVE : Strand.NEGATIVE;

                    DRangerFeature feature = new DRangerFeature(chr1, pos1, strand1, chr2, pos2, strand2);
                    feature.setIndex(index);

                    if (tumreadsColumn > 0) {
                        feature.setTumreads(toInt(tokens[tumreadsColumn]));
                    }
                    if (normreadsColumn > 0) {
                        feature.setNormreads(toInt(tokens[normreadsColumn]));
                    }
                    if (classColumn > 0) {
                        feature.setFeatureClass(tokens[classColumn]);
                    }
                    if (spanColumn > 0) {
                        feature.setSpan(toInt(tokens[spanColumn]));
                    }
                    if (site1Column > 0) {
                        feature.setSite1(tokens[site1Column]);
                    }
                    if (site2Column > 0) {
                        feature.setSite2(tokens[site2Column]);
                    }
                    if (qualityColumn > 0) {
                        feature.setQuality(toInt(tokens[qualityColumn]));
                    }
                    if (scoreColumn > 0) {
                        feature.setScore(toInt(tokens[scoreColumn]));
                    }

                    features.add(feature);
                }
            }
        }
        catch (NumberFormatException ne) {
            throw new ParserException("Column " + parseColumn + " must be a numeric value", reader.getCurrentLineNumber(), nextLine);
        }
        catch (Exception e) {
            log.error("Error parsing dRanger file", e);
            if (nextLine != null && reader.getCurrentLineNumber() != 0) {
                throw new ParserException(e.getMessage(), e, reader.getCurrentLineNumber(), nextLine);
            } else {
                throw new RuntimeException(e);
            }

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

        FeatureTrack track = new FeatureTrack(locator, new FeatureCollectionSource(features));
        track.setName(locator.getTrackName());
        track.setRendererClass(DRangerRenderer.class);
        tracks.add(track);

        return tracks;
    }

    private int toInt(String token) {
        try {
            return Integer.parseInt(token);
        }
        catch (NumberFormatException e) {
            return 0;
        }
    }


    private void setColumns(String header) throws Exception {
        String[] tokens = header.split("\t");

        Map<String, Integer> map = new HashMap();
        for (int i = 0; i < tokens.length; i++) {
            map.put(tokens[i].toLowerCase(), i);
        }

        chr1Column = map.get("chr1").intValue();
        str1Column = map.get("str1").intValue();
        pos1Column = map.get("pos1").intValue();
        chr2Column = map.get("chr2").intValue();
        str2Column = map.get("str2").intValue();
        pos2Column = map.get("pos2").intValue();

        if (map.containsKey("num")) {
            numColumn = map.get("num").intValue();
        }
        if (map.containsKey("tumreads")) {
            tumreadsColumn = map.get("tumreads").intValue();
        }
        if (map.containsKey("normreads")) {
            tumreadsColumn = map.get("normreads").intValue();
        }
        if (map.containsKey("class")) {
            classColumn = map.get("class").intValue();
        }
        if (map.containsKey("span")) {
            spanColumn = map.get("span").intValue();
        }
        if (map.containsKey("site1")) {
            site1Column = map.get("site1").intValue();
        }
        if (map.containsKey("site2")) {
            site2Column = map.get("site2").intValue();
        }
        if (map.containsKey("quality")) {
            qualityColumn = map.get("quality").intValue();
        }
        if (map.containsKey("score")) {
            scoreColumn = map.get("score").intValue();
        }
    }
}
