/*
 * Copyright (c) 2007-2011 by The Broad Institute of MIT and Harvard.  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
 * 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 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.
 */

/*
 * Created by JFormDesigner on Sat Dec 04 19:26:01 EST 2010
 */

package org.broad.igv.util.stats;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.border.*;

import org.broad.igv.track.AttributeManager;
import org.broad.igv.track.Track;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYStepRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

/**
 * @author jrobinso
 */
public class KMPlotFrame extends JFrame {

    Collection<Track> tracks;
    private XYPlot plot;

    // TODO -- control to set this
    int maxTime = 60;

    public KMPlotFrame(Collection<Track> tracks) {

        //setLocationRelativeTo(owner);

        this.tracks = tracks;

        initComponents();


        XYDataset dataset = updateDataset();
        JFreeChart chart = ChartFactory.createXYLineChart(
                "",
                "Time",
                "Survival",
                dataset,
                PlotOrientation.VERTICAL,
                true,
                true,
                false);

        XYStepRenderer renderer = new XYStepRenderer();
        plot = chart.getXYPlot();
        plot.setRenderer(renderer);
        ChartPanel plotPanel = new ChartPanel(chart);
        contentPanel.add(plotPanel, BorderLayout.CENTER);


        censurColumnControl.addItem("");
        //sampleColumnControl.addItem("");
        survivalColumnControl.addItem("");
        groupByControl.addItem("");

        final List<String> allAttributes = AttributeManager.getInstance().getAttributeNames();
        final List<String> groupableAttributes = AttributeManager.getInstance().getGroupableAttributes();

        // Populate pulldowns, and make guesses for column names.
        String survivalColumn = null;
        String censureColumn = null;
        String sampleColumn = null;
        for (String key : allAttributes) {
            censurColumnControl.addItem(key);
            //sampleColumnControl.addItem(key);
            survivalColumnControl.addItem(key);

            String tmp = key.toLowerCase();
            if (tmp.contains("survival") || tmp.contains("daystodeath")) survivalColumn = key;
            if (tmp.contains("censure")) censureColumn = key;
            if (tmp.contains("sample")) sampleColumn = key;
        }
        for (String key : groupableAttributes) {
            groupByControl.addItem(key);
        }


        if (survivalColumn != null) {
            survivalColumnControl.setSelectedItem(survivalColumn);
        }
        if (censureColumn != null) {
            censurColumnControl.setSelectedItem(censureColumn);
        }
        if (sampleColumn != null) {
            //sampleColumnControl.setSelectedItem(sampleColumn);
        }


    }


    private void closeButtonActionPerformed(ActionEvent e) {
        setVisible(false);
    }

    public XYDataset updateDataset() {

        XYSeriesCollection dataset = new XYSeriesCollection();

        final String survivalColumn = (String) survivalColumnControl.getSelectedItem();
        final String censureColumn = (String) censurColumnControl.getSelectedItem();
        final String groupByColumn = (String) groupByControl.getSelectedItem();
        if (survivalColumn != null) {
            ArrayList<DataPoint> dataPoints = new ArrayList(tracks.size());
            HashSet<String> participants = new HashSet();
            for (Track t : tracks) {
                try {
                    // Get the participant (sample) attribute value for this track
                    //final Object selectedItem = sampleColumnControl.getSelectedItem();
                    //if (selectedItem != null) {
                    String participant = t.getSample(); // t.getAttributeValue(selectedItem.toString());


                    if (!participants.contains(participant)) {   // Don't add same participant twice.
                        participants.add(participant);

                        // Get the survival time.
                        String survivalString = t.getAttributeValue(survivalColumn);
                        int survivalDays = Integer.parseInt(survivalString);
                        int survival = survivalDays;

                        // Is the patient censured at the end of the survival period?
                        String censureString = censureColumn == null ? null : t.getAttributeValue(censureColumn);
                        boolean censured = censureString != null && censureString.equals("1");

                        String group = groupByColumn == null ? null : t.getAttributeValue(groupByColumn);
                        if (group == null) group = "<No value>";
                        dataPoints.add(new DataPoint(participant, survival, censured, group));
                    } else {
                        // TODO -- check consistency of participant data
                    }
                    // }
                } catch (NumberFormatException e) {
                    // Just skip
                }
            }

            // Segregate by group
            Map<String, ArrayList<DataPoint>> map = new HashMap();
            for (DataPoint dp : dataPoints) {
                String g = dp.getGroup();
                ArrayList<DataPoint> pts = map.get(g);
                if (pts == null) {
                    pts = new ArrayList();
                    map.put(g, pts);
                }
                pts.add(dp);
            }


            //XYSeries series1;
            for (Map.Entry<String, ArrayList<DataPoint>> entry : map.entrySet()) {

                java.util.List<DataPoint> pts = entry.getValue();
                Collections.sort(pts);

                int[] time = new int[pts.size()];
                boolean[] censured = new boolean[pts.size()];
                for (int i = 0; i < pts.size(); i++) {
                    //int months = Math.max(1, pts.get(i).time / 30);  // <=  TODO -- HARDCODED MONTH DATE
                    time[i] = pts.get(i).time;
                    censured[i] = pts.get(i).censured;
                }

                java.util.List<KaplanMeierEstimator.Interval> controlIntervals = KaplanMeierEstimator.compute(time, censured);

                XYSeries series1 = new XYSeries(entry.getKey());
                for (KaplanMeierEstimator.Interval interval : controlIntervals) {
                    series1.add(interval.getEnd(), interval.getCumulativeSurvival());
                }
                dataset.addSeries(series1);
            }
        }
        return dataset;

    }

    private void survivalColumnControlActionPerformed(ActionEvent e) {
        XYDataset dataset = updateDataset();
        plot.setDataset(dataset);
        repaint();

    }

    public static class DataPoint implements Comparable<DataPoint> {
        String participant;
        int time;
        boolean censured;
        private String group;

        DataPoint(String participant, int time, boolean censured, String group) {
            this.censured = censured;
            this.participant = participant;
            this.group = group;
            this.time = time;
        }

        public int compareTo(DataPoint dataPoint) {
            return time - dataPoint.time;
        }

        public String getGroup() {
            return group;
        }

    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents
        // Generated using JFormDesigner non-commercial license
        dialogPane = new JPanel();
        contentPanel = new JPanel();
        panel1 = new JPanel();
        panel2 = new JPanel();
        label2 = new JLabel();
        survivalColumnControl = new JComboBox();
        panel3 = new JPanel();
        label3 = new JLabel();
        censurColumnControl = new JComboBox();
        panel4 = new JPanel();
        label4 = new JLabel();
        groupByControl = new JComboBox();

        //======== this ========
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setTitle("Kaplan-Meier Plot");
        Container contentPane = getContentPane();
        contentPane.setLayout(new BorderLayout());

        //======== dialogPane ========
        {
            dialogPane.setBorder(new EmptyBorder(12, 12, 12, 12));
            dialogPane.setLayout(new BorderLayout());

            //======== contentPanel ========
            {
                contentPanel.setLayout(new BorderLayout());

                //======== panel1 ========
                {
                    panel1.setAlignmentX(0.0F);
                    panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));

                    //======== panel2 ========
                    {
                        panel2.setAlignmentX(1.0F);
                        panel2.setLayout(null);

                        //---- label2 ----
                        label2.setText("Survival column");
                        panel2.add(label2);
                        label2.setBounds(new Rectangle(new Point(5, 10), label2.getPreferredSize()));

                        //---- survivalColumnControl ----
                        survivalColumnControl.addActionListener(new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                survivalColumnControlActionPerformed(e);
                            }
                        });
                        panel2.add(survivalColumnControl);
                        survivalColumnControl.setBounds(120, 5, 235, survivalColumnControl.getPreferredSize().height);

                        { // compute preferred size
                            Dimension preferredSize = new Dimension();
                            for(int i = 0; i < panel2.getComponentCount(); i++) {
                                Rectangle bounds = panel2.getComponent(i).getBounds();
                                preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
                                preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
                            }
                            Insets insets = panel2.getInsets();
                            preferredSize.width += insets.right;
                            preferredSize.height += insets.bottom;
                            panel2.setMinimumSize(preferredSize);
                            panel2.setPreferredSize(preferredSize);
                        }
                    }
                    panel1.add(panel2);

                    //======== panel3 ========
                    {
                        panel3.setAlignmentX(1.0F);
                        panel3.setLayout(null);

                        //---- label3 ----
                        label3.setText("Censored column");
                        panel3.add(label3);
                        label3.setBounds(new Rectangle(new Point(5, 10), label3.getPreferredSize()));

                        //---- censurColumnControl ----
                        censurColumnControl.addActionListener(new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                survivalColumnControlActionPerformed(e);
                            }
                        });
                        panel3.add(censurColumnControl);
                        censurColumnControl.setBounds(120, 5, 235, censurColumnControl.getPreferredSize().height);

                        { // compute preferred size
                            Dimension preferredSize = new Dimension();
                            for(int i = 0; i < panel3.getComponentCount(); i++) {
                                Rectangle bounds = panel3.getComponent(i).getBounds();
                                preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
                                preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
                            }
                            Insets insets = panel3.getInsets();
                            preferredSize.width += insets.right;
                            preferredSize.height += insets.bottom;
                            panel3.setMinimumSize(preferredSize);
                            panel3.setPreferredSize(preferredSize);
                        }
                    }
                    panel1.add(panel3);

                    //======== panel4 ========
                    {
                        panel4.setAlignmentX(1.0F);
                        panel4.setLayout(null);

                        //---- label4 ----
                        label4.setText("Group by");
                        panel4.add(label4);
                        label4.setBounds(new Rectangle(new Point(5, 10), label4.getPreferredSize()));

                        //---- groupByControl ----
                        groupByControl.addActionListener(new ActionListener() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                survivalColumnControlActionPerformed(e);
                            }
                        });
                        panel4.add(groupByControl);
                        groupByControl.setBounds(120, 5, 235, groupByControl.getPreferredSize().height);

                        { // compute preferred size
                            Dimension preferredSize = new Dimension();
                            for(int i = 0; i < panel4.getComponentCount(); i++) {
                                Rectangle bounds = panel4.getComponent(i).getBounds();
                                preferredSize.width = Math.max(bounds.x + bounds.width, preferredSize.width);
                                preferredSize.height = Math.max(bounds.y + bounds.height, preferredSize.height);
                            }
                            Insets insets = panel4.getInsets();
                            preferredSize.width += insets.right;
                            preferredSize.height += insets.bottom;
                            panel4.setMinimumSize(preferredSize);
                            panel4.setPreferredSize(preferredSize);
                        }
                    }
                    panel1.add(panel4);
                }
                contentPanel.add(panel1, BorderLayout.NORTH);
            }
            dialogPane.add(contentPanel, BorderLayout.CENTER);
        }
        contentPane.add(dialogPane, BorderLayout.CENTER);
        setSize(565, 510);
        setLocationRelativeTo(getOwner());
        // JFormDesigner - End of component initialization  //GEN-END:initComponents
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables
    // Generated using JFormDesigner non-commercial license
    private JPanel dialogPane;
    private JPanel contentPanel;
    private JPanel panel1;
    private JPanel panel2;
    private JLabel label2;
    private JComboBox survivalColumnControl;
    private JPanel panel3;
    private JLabel label3;
    private JComboBox censurColumnControl;
    private JPanel panel4;
    private JLabel label4;
    private JComboBox groupByControl;
    // JFormDesigner - End of variables declaration  //GEN-END:variables


}
