/**
 * Copyright (c) 2010-2011 by Fred Hutchinson Cancer Research Center.  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." FRED HUTCHINSON CANCER RESEARCH CENTER MAKES NO
 * REPRESENTATIONS OR WARRANTES 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 FRED HUTCHINSON CANCER RESEARCH
 * CENTER OR ITS 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 FRED HUTCHINSON CANCER RESEARCH CENTER SHALL BE ADVISED,
 * SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE
 * FOREGOING.
 */

/*
 *
 */
package org.broad.igv.sam;

import com.jidesoft.swing.JidePopupMenu;
import org.apache.log4j.Logger;
import org.broad.igv.PreferenceManager;
import org.broad.igv.feature.*;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.renderer.SpliceJunctionRenderer;
import org.broad.igv.track.*;
import org.broad.igv.ui.IGV;
import org.broad.igv.ui.panel.DataPanel;
import org.broad.igv.ui.panel.IGVPopupMenu;
import org.broad.igv.ui.panel.ReferenceFrame;
import org.broad.igv.renderer.DataRange;
import org.broad.igv.util.BrowserLauncher;
import org.broad.tribble.Feature;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.List;

/**
 * @author dhmay
 *         Finds splice junctions in real time and renders them as Features
 */
public class SpliceJunctionFinderTrack extends FeatureTrack {

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

    AlignmentDataManager dataManager;
    PreferenceManager prefs;
    RenderContext context;
    Genome genome;

    protected int minReadFlankingWidth = 0;
    protected int minJunctionCoverage = 1;

    // The "parent" of the track (a DataPanel).  This release of IGV does not support owner-track releationships
    // directory,  so this field might be null at any given time.  It is updated each repaint.
    DataPanel parent;


    public SpliceJunctionFinderTrack(String id, String name, AlignmentDataManager dataManager, Genome genome) {
        super(id, name);
        super.setDataRange(new DataRange(0, 0, 60));
        this.genome = genome;
        setRendererClass(SpliceJunctionRenderer.class);
        this.dataManager = dataManager;
        prefs = PreferenceManager.getInstance();
    }


    @Override
    protected boolean isShowFeatures(RenderContext context) {
        float maxRange = PreferenceManager.getInstance().getAsFloat(PreferenceManager.SAM_MAX_VISIBLE_RANGE);
        float minVisibleScale = (maxRange * 1000) / 700;
        return context.getScale() < minVisibleScale;

    }


    /**
     * Add a MenuItem to control the minimum flanking width for reads used in finding junctions.
     * If either the start OR the end flanking region is less than this, the read is not used
     *
     * @param menu
     * @return
     */
    public JMenuItem addFlankingWidthTresholdItem(JPopupMenu menu) {
        JMenuItem flankingWidthItem = new JMenuItem("Set minimum read flanking width...");

        flankingWidthItem.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {

                String value = JOptionPane.showInputDialog("Minimum start and end flanking region width: ",
                        Float.valueOf(minReadFlankingWidth));
                if (value == null) {
                    return;
                }
                try {
                    int tmp = Integer.parseInt(value);
                    minReadFlankingWidth = tmp;
                    IGV.getInstance().repaintDataPanels();
                }
                catch (Exception exc) {
                    //log
                }

            }
        });
        menu.add(flankingWidthItem);

        return flankingWidthItem;
    }


    /**
     * Add a MenuItem to control the minimum flanking width for reads used in finding junctions.
     * If either the start OR the end flanking region is less than this, the read is not used
     *
     * @param menu
     * @return
     */
    public JMenuItem addJunctionCoverageTresholdItem(JPopupMenu menu) {
        JMenuItem junctionDepthItem = new JMenuItem("Set minimum junction coverage...");

        junctionDepthItem.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {

                String value = JOptionPane.showInputDialog("Minimum coverage depth for displayed junctions: ",
                        Float.valueOf(minJunctionCoverage));
                if (value == null) {
                    return;
                }
                try {
                    int tmp = Integer.parseInt(value);
                    minJunctionCoverage = tmp;
                    IGV.getInstance().repaintDataPanels();
                }
                catch (Exception exc) {
                    //log
                }

            }
        });
        menu.add(junctionDepthItem);

        return junctionDepthItem;
    }

    /**
     * Override to return a specialized popup menu
     *
     * @return
     */
    @Override
    public IGVPopupMenu getPopupMenu(TrackClickEvent te) {

        IGVPopupMenu popupMenu = new IGVPopupMenu();

        JLabel popupTitle = new JLabel("  " + getName(), JLabel.CENTER);

        Font newFont = popupMenu.getFont().deriveFont(Font.BOLD, 12);
        popupTitle.setFont(newFont);
        if (popupTitle != null) {
            popupMenu.add(popupTitle);
        }

        popupMenu.addSeparator();

        ArrayList<Track> tmp = new ArrayList();
        tmp.add(this);
        TrackMenuUtils.addStandardItems(popupMenu, tmp, te);
        popupMenu.addSeparator();
        addFlankingWidthTresholdItem(popupMenu);
        addJunctionCoverageTresholdItem(popupMenu);
        return popupMenu;
    }


    @Override
    public void setDataRange(DataRange axisDefinition) {
        // Explicitly setting a data range turns off auto-scale
        super.setDataRange(axisDefinition);
    }


    public boolean isLogNormalized() {
        return false;
    }

    public float getRegionScore(String chr, int start, int end, int zoom, RegionScoreType type, ReferenceFrame frame) {
        return 0;
    }

    @Override
    protected void loadFeatures(String chr, int start, int end, RenderContext context) {
        parent = context.getPanel();
        try {
            final AlignmentInterval loadedInterval = dataManager.getLoadedInterval(context);
            if (loadedInterval != null) {
                List<SpliceJunctionFeature> features = loadedInterval.getSpliceJunctions();
                int intervalStart = loadedInterval.getStart();
                int intervalEnd = loadedInterval.getEnd();
                PackedFeatures pf = new PackedFeaturesSpliceJunctions(chr, intervalStart, intervalEnd, features.iterator(), getName());
                packedFeaturesMap.put(context.getReferenceFrame().getName(), pf);
            }
        } catch (IOException e) {
            log.error("Error loading splice junctions", e);
        }
    }

    @Override
    public boolean handleDataClick(TrackClickEvent te) {
        boolean result = super.handleDataClick(te);
        if (parent != null) parent.repaint();

        return result;
    }

}
