/*
 * 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.
 */


package org.broad.igv.ui;



import org.broad.igv.ui.util.MessageUtils;
import org.broad.igv.feature.SequenceManager;
import org.broad.igv.session.ViewContext;
import org.broad.igv.track.RegionScoreType;
import org.broad.igv.track.TrackType;

import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

/**
 * @author eflakes
 */
public class RegionOfInterest extends MouseInputAdapter {

    private String chr;
    private String description;
    private Integer start;    // In Chromosome coordinates
    private Integer end;      // In Chromosome coordinates
    private Color backgroundColor = Color.RED;
    private Color foregroundColor = Color.BLACK;
    private JPopupMenu popupMenu;
    private Component parent;
    private WaitCursorManager.CursorToken token;

    /**
     * A bounded region on a chromosome.
     *
     * @param chromosomeName
     * @param start          The region starting position on the chromosome.
     * @param end            The region starting position on the chromosome.
     * @param description
     */
    public RegionOfInterest(String chromosomeName, Integer start, Integer end, String description) {

        this.chr = chromosomeName;
        this.description = description;
        this.start = start;
        this.end = end;
    }

    public String getChr() {
        return chr;
    }

    public String getDescription() {
        return description;
    }


    public void setEnd(Integer end) {
        this.end = end;
    }

    public void setStart(Integer start) {
        this.start = start;
    }

    public Integer getEnd() {
        return end;
    }

    public Integer getStart() {
        return start;
    }

    public Color getBackgroundColor() {
        return backgroundColor;
    }

    public void setBackgroundColor(Color backgroundColor) {
        this.backgroundColor = backgroundColor;
    }

    public Color getForegroundColor() {
        return foregroundColor;
    }


    public void setForegroundColor(Color foregroundColor) {
        this.foregroundColor = foregroundColor;
    }

    protected JPopupMenu getPopupMenu(final Point point) {

        Set<TrackType> loadedTypes = IGVMainFrame.getInstance().getTrackManager().getLoadedTypes();

        popupMenu = new JPopupMenu();

        if (loadedTypes.contains(TrackType.COPY_NUMBER) ||
                loadedTypes.contains(TrackType.ALLELE_SPECIFIC_COPY_NUMBER) ||
                loadedTypes.contains(TrackType.CNV)) {
            JMenuItem item = new JMenuItem("Sort by amplification");
            item.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {

                    IGVMainFrame.getInstance().getTrackManager().sortByRegionScore(RegionOfInterest.this, RegionScoreType.AMPLIFICATION);
                    IGVMainFrame.getInstance().getContentPane().repaint();
                }
            });
            popupMenu.add(item);


            item = new JMenuItem("Sort by deletion");
            item.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {

                    IGVMainFrame.getInstance().getTrackManager().sortByRegionScore(RegionOfInterest.this, RegionScoreType.DELETION);
                    IGVMainFrame.getInstance().getContentPane().repaint();
                }
            });
            popupMenu.add(item);
        }

        if (loadedTypes.contains(TrackType.GENE_EXPRESSION)) {
            JMenuItem item = new JMenuItem("Sort by expression");
            item.addActionListener(new ActionListener() {

                public void actionPerformed(ActionEvent e) {

                    IGVMainFrame.getInstance().getTrackManager().sortByRegionScore(RegionOfInterest.this, RegionScoreType.EXPRESSION);
                    IGVMainFrame.getInstance().getContentPane().repaint();
                }
            });

            popupMenu.add(item);
        }

        JMenuItem item = new JMenuItem("Sort by value");
        item.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {

                IGVMainFrame.getInstance().getTrackManager().sortByRegionScore(RegionOfInterest.this, RegionScoreType.SCORE);
                IGVMainFrame.getInstance().getContentPane().repaint();
            }
        });
        popupMenu.add(item);

        popupMenu.addSeparator();

        item = new JMenuItem("Copy sequence");
        item.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                String genomeId = ViewContext.getInstance().getGenomeId();
                byte[] seqBytes = SequenceManager.readSequence(genomeId, chr, start, end);
                if (seqBytes == null) {
                   MessageUtils.showMessage("Sequence not available");
                } else {
                    String sequence = new String(seqBytes);
                    StringSelection stringSelection = new StringSelection(sequence);
                    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                    clipboard.setContents(stringSelection, null);
                }
            }
        });
        popupMenu.add(item);

        popupMenu.add(new JSeparator());

        item = new JMenuItem("Delete");
        item.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {

                // TODO -- There's something strange and circular about these references
                ViewContext viewContext = ViewContext.getInstance();
                Collection<RegionOfInterest> regionsOfInterest =
                        IGVMainFrame.getInstance().getSession().getRegionsOfInterest(chr);

                if (regionsOfInterest != null) {

                    Iterator iterator = regionsOfInterest.iterator();
                    while (iterator.hasNext()) {
                        RegionOfInterest region = (RegionOfInterest) iterator.next();

                        Integer start = region.getStart();
                        Integer end = region.getEnd();

                        if ((start == null) || (end == null)) {
                            continue;
                        }

                        Integer regionStart = viewContext.getPixelPosition(start);
                        Integer regionEnd = viewContext.getPixelPosition(end);

                        if ((regionStart == null) || (regionEnd == null)) {
                            continue;
                        }

                        if ((point.x >= regionStart) && (point.x <= regionEnd)) {
                            iterator.remove();
                        }
                    }
                }
                IGVMainFrame.getInstance().repaintDataAndHeaderPanels();
            }
        });
        popupMenu.add(item);

        return popupMenu;
    }

    /**
     * Method description
     *
     * @param e
     */
    @Override
    public void mousePressed(MouseEvent e) {
        showPopup(e);
    }

    /**
     * Method description
     *
     * @param e
     */
    @Override
    public void mouseReleased(MouseEvent e) {
        showPopup(e);
    }

    /**
     * Method description
     *
     * @param e
     */
    @Override
    public void mouseEntered(MouseEvent e) {
    }

    /**
     * Method description
     *
     * @param e
     */
    @Override
    public void mouseExited(MouseEvent e) {
    }

    /**
     * Method description
     *
     * @param e
     */
    @Override
    public void mouseMoved(MouseEvent e) {

        Point point = e.getPoint();

        ViewContext viewContext = ViewContext.getInstance();
        if ((point.x >= viewContext.getPixelPosition(start))
                && (point.x <= viewContext.getPixelPosition(end))) {

            parent.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));

        } else {
            parent.setCursor(Cursor.getDefaultCursor());
        }
    }

    /**
     * Method description
     *
     * @return
     */
    public Component getParent() {
        return parent;
    }

    private void showPopup(MouseEvent e) {

        ViewContext viewContext = ViewContext.getInstance();
        Point point = e.getPoint();

        if ((point.x >= viewContext.getPixelPosition(start))
                && (point.x <= viewContext.getPixelPosition(end))) {

            getPopupMenu(point).show(e.getComponent(), e.getX(), e.getY());

        }
    }

    /**
     * Method description
     *
     * @param parent
     */
    public void setParent(Component parent) {
        this.parent = parent;
    }
}
