/*
 * -------------------------------------------------------------------------
 *      $Id: FPanel.java,v 1.5 2006/05/05 19:58:46 brophy Exp $
 * -------------------------------------------------------------------------
 *      Copyright (c) 1999 Visual Numerics Inc. All Rights Reserved.
 *
 *      This software is confidential information which is proprietary to
 *      and a trade secret of Visual Numerics, Inc.  Use, duplication or
 *      disclosure is subject to the terms of an appropriate license
 *      agreement.
 *
 *      VISUAL NUMERICS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
 *      SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING
 *      BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 *      FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. VISUAL
 *      NUMERICS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
 *      AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
 *      ITS DERIVATIVES.
 *--------------------------------------------------------------------------
 */

/*
 * FPanel.java
 *
 * Created on September 13, 2004, 3:52 PM
 */

package com.imsl.demo.heatmaps;

import com.imsl.chart.*;
import com.imsl.stat.Sort;
import java.util.*;
import java.io.*;
import java.awt.event.*;
import java.awt.Color;


public class FPanel extends javax.swing.JPanel implements MouseMotionListener {

    private Chart chart;
    private AxisXY axis;
    private HashMap map;
    private String[][] labels;
    private String oldKey="nada";
    private javax.swing.JFrame parentFrame;
    private final int xMin = 0;
    private final int xMax = 10;


    /** Creates new form FPanel */
    public FPanel(javax.swing.JFrame parent) {
        this.parentFrame = parent;

        initComponents();
        setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.85*parent.getSize().height)));

        setChart();
        jPanelChart.setPreferredSize(new java.awt.Dimension(parent.getSize().width, (int)(0.66*parent.getSize().height)));
        try {
            getData();
        } catch (Exception e) {
            e.printStackTrace();
        }
        update(0);
    }


    private void setChart() {
        chart = jPanelChart.getChart();
        axis = new AxisXY(chart);
        axis.setViewport(0.05,0.80,0.05,0.95);

        // Set axis ranges
        axis.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF);
        axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF);
        axis.getAxisX().setWindow(0.0, 10.0);
        axis.getAxisY().setWindow(0.0, 10.0);

        // Add a MouseMotionListener to the chart.
        jPanelChart.addMouseMotionListener(this);
    }


    // load data set
    public void getData() throws IOException, java.text.ParseException {
        InputStream is = getClass().getResourceAsStream("NASDAQ100.txt");
        Reader fr = new InputStreamReader(is);
        LineNumberReader lnr = new LineNumberReader(fr);

        map = new HashMap(135);
        while (true) {
            String line = lnr.readLine();
            if (line == null)  break;
            StringTokenizer st = new StringTokenizer(line,"\t");
            String sym = st.nextToken();
            String nam = st.nextToken();
            double las = Double.valueOf(st.nextToken()).doubleValue();
            double cha = Double.valueOf(st.nextToken()).doubleValue();
            double hig = Double.valueOf(st.nextToken()).doubleValue();
            double low = Double.valueOf(st.nextToken()).doubleValue();
            long vol = Long.valueOf(st.nextToken()).longValue();
            double clo = Double.valueOf(st.nextToken()).doubleValue();
            Stock s = new Stock(sym,nam,las,cha,hig,low,vol,clo);
            map.put(sym,s);
        }
    }


    // Draw the graph
    private void drawGraph(int num, double[][] data, String[][] labels) {
        //Heatmap heatmap = new Heatmap(axis, 0, num, 0, num, -2.5, 2.5, data, Colormap.SPECTRAL);
        double ext = findExtreme(data);
        Heatmap heatmap = new Heatmap(axis, 0, num, 0, num, -ext, ext, data, new RedGreenColormap());
        heatmap.setHeatmapLabels(labels);
        heatmap.setTextColor("black");
        heatmap.getHeatmapLegend().setPaint(true);
        heatmap.getHeatmapLegend().setTextFormat("##.##");
        heatmap.getHeatmapLegend().setTitle("Percent Change");
        axis.getAxisX().setPaint(false);
        axis.getAxisY().setPaint(false);
    }

    // Find min & max of scaled values
    private double findExtreme(double[][] data) {
        double ext = 0;
        for (int i=0; i<data[0].length; i++) {
            for (int j=0; j<data.length; j++) {
                if (Math.abs(data[i][j]) > ext) ext = Math.abs(data[i][j]);
            }
        }
        return ext;
    }


    // print the details for the current mouse location
    private void getDetails(String key) {
        Stock s = (Stock)map.get(key);
        StringBuffer sb = new StringBuffer(s.getSymbol());
        sb.append(": "+s.getName()+"\n");
        sb.append("Last: "+s.getLast()+"\t% Change: "+s.getChange()+"\n");
        sb.append("High: "+s.getHigh()+"\tLow: "+s.getLow()+"\n");
        sb.append("Close: "+s.getClose()+"\tVolume: "+s.getVolume()+"\n");
        displayText.setText(sb.toString());
    }


    // resort the data based on combo box selection
    // this could be done once since the data in this demo
    // are static; however, if one were receiving realtime
    // updates, the sort would have to occur live.
    private void sortData(int sel) {
        final int num = 10;
        final int num2 = num*num;
        double data[][] = new double[num][num];
        labels = new String[num][num];
        Set keys;
        Iterator iter;
        double[] tmpData = new double[num2];
        double[] tmpSort = new double[num2];
        String[] tmpLab = new String[num2];
        int[] perms = new int[num2];

        switch (sel) {
            case 0:
                // sort by key -- easiest is to use a TreeMap
                TreeMap tree = new TreeMap(map);
                keys = tree.keySet();
                iter = keys.iterator();

                for (int i = 0;  i < num;  i++) {
                    for (int j = 0;  j < num;  j++) {
                        String key = (String)iter.next();
                        Stock s = (Stock)map.get(key);
                        String sym = s.getSymbol();
                        data[j][num-1-i] = s.getChange();
                        labels[j][num-1-i] = sym;
                    }
                }
                break;
            case 1:
                // sort by % change, ascending
                keys = map.keySet();
                iter = keys.iterator();
                for (int i=0; i<num2; i++) {
                    String key = (String)iter.next();
                    Stock s = (Stock)map.get(key);
                    String sym = s.getSymbol();
                    tmpData[i] = s.getChange();
                    tmpLab[i] = sym;
                    perms[i] = i;
                }
                Sort.ascending(tmpData, perms);
                for (int i=0; i<num; i++) {
                    for (int j=0; j<num; j++) {
                        data[j][num-1-i] = tmpData[i*num + j];
                        labels[j][num-1-i] = tmpLab[perms[i*num + j]];
                    }
                }
                break;
            case 2:
                // sort by % change, descending
                keys = map.keySet();
                iter = keys.iterator();
                for (int i=0; i<num2; i++) {
                    String key = (String)iter.next();
                    Stock s = (Stock)map.get(key);
                    String sym = s.getSymbol();
                    tmpData[i] = s.getChange();
                    tmpLab[i] = sym;
                    perms[i] = i;
                }
                Sort.descending(tmpData, perms);
                for (int i=0; i<num; i++) {
                    for (int j=0; j<num; j++) {
                        data[j][num-1-i] = tmpData[i*num + j];
                        labels[j][num-1-i] = tmpLab[perms[i*num + j]];
                    }
                }
                break;
            case 3:
                // sort by volume
                keys = map.keySet();
                iter = keys.iterator();
                for (int i=0; i<num2; i++) {
                    String key = (String)iter.next();
                    Stock s = (Stock)map.get(key);
                    String sym = s.getSymbol();
                    tmpSort[i] = s.getVolume();
                    tmpData[i] = s.getChange();
                    tmpLab[i] = sym;
                    perms[i] = i;
                }
                Sort.ascending(tmpSort, perms);
                for (int i=0; i<num; i++) {
                    for (int j=0; j<num; j++) {
                        data[j][num-1-i] = tmpData[perms[i*num + j]];
                        labels[j][num-1-i] = tmpLab[perms[i*num + j]];
                    }
                }
                break;
        }

        drawGraph(num, data, labels);
    }

    // Redraw the chart.
    public void update(int sel) {
        sortData(sel);
        repaint();
    }


    private void initComponents() {
        jPanel = new javax.swing.JPanel();
        jLabel = new javax.swing.JLabel();
        String[] sortChoices = {"Symbol", "% Change Ascending", "% Change Descending", "Volume"};
        jComboBox = new javax.swing.JComboBox(sortChoices);

        displayText = new javax.swing.JTextArea(2, 30);
        jPanelChart = new com.imsl.chart.JPanelChart();

        setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));
        setPreferredSize(new java.awt.Dimension(500, 600));

        jLabel.setText("Sort by: ");
        jPanel.add(jLabel);

        jComboBox.setSelectedIndex(0);
        jComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                update(jComboBox.getSelectedIndex());
            }
        });
        jPanel.add(jComboBox);

        add(jPanel);

        displayText.setEditable(false);
        displayText.setText("Move the mouse over the heat map for details.");
        displayText.setPreferredSize(new java.awt.Dimension(500, 16));
        displayText.setBackground(getBackground());
        add(displayText);

        jPanelChart.setPreferredSize(new java.awt.Dimension(500, 500));
        add(jPanelChart);
    }


    // Implement MouseMotionListener
    public void mouseMoved(MouseEvent e) {
        double user[] = {0,0};
        axis.mapDeviceToUser(e.getX(), e.getY(), user);
        if ((user[0] < xMin) || (user[0] > xMax) ||
            (user[1] < xMin) || (user[1] > xMax)) {

            displayText.setText("Move the mouse over the heat map for details.");
            return;
        }

        String key = labels[(int)user[0]][(int)user[1]];
        if (!key.equals(oldKey)) {
            oldKey = key;
            getDetails(key);
        }
    }

    public void mouseDragged(MouseEvent e) {
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables

    private javax.swing.JLabel jLabel;

    private javax.swing.JComboBox jComboBox;

    private com.imsl.chart.JPanelChart jPanelChart;

    private javax.swing.JTextArea displayText;

    private javax.swing.JPanel jPanel;

    // End of variables declaration//GEN-END:variables

    private class RedGreenColormap implements com.imsl.chart.Colormap {
      int[] c = new int[] {16711680,16515072,16384000,16187392,16056320,15859712,15728640,15597568,15400960,15269888,15073280,14942208,14745600,14614528,14483456,14286848,14155776,13959168,13828096,13631488,13500416,13369344,13172736,
                           13041664,12845056,12713984,12582912,12386304,12255232,12058624,11927552,11730944,11599872,11468800,11272192,11141120,10944512,10813440,10616832,10485760,10354688,10158080,10027008,9830400,9699328,9568256,
                           9371648,9240576,9043968,8912896,8716288,8585216,8454144,8257536,8126464,7929856,7798784,7602176,7471104,7340032,7143424,7012352,6815744,6684672,6553600,6685443,6817543,7015179,7147279,7344915,7477015,
                           7609115,7806751,7938851,8136487,8268587,8466223,8598323,8730423,8928059,9060159,9257795,9389895,9587531,9719631,9851731,10049367,10181467,10379103,10511203,10643303,10840939,10973039,11170675,11302775,
                           11500411,11632511,11764611,11962247,12094347,12291983,12424083,12621719,12753819,12885919,13083555,13215655,13413291,13545391,13677491,13875127,14007227,14204863,14336963,14534599,14666699,14798799,14996435,
                           15128535,15326171,15458271,15655907,15788007,15920107,16117743,16249843,16447479,16579579,16777215,16514299,16251639,15988723,15726063,15463147,15200487,14937827,14674911,14412251,14149335,13886675,13623759,
                           13361099,13098439,12835523,12572863,12309947,12047287,11784371,11521711,11259051,10996135,10733475,10470559,10207899,9945239,9682323,9419663,9156747,8894087,8631171,8368511,8105851,7842935,7580275,7317359,
                           7054699,6791783,6529123,6266463,6003547,5740887,5477971,5215311,4952651,4689735,4427075,4164159,3901499,3638583,3375923,3113263,2850347,2587687,2324771,2062111,1799195,1536535,1273875,1010959,748299,485383,
                           222723,25600,26112,26624,27392,27904,28672,29184,29952,30464,31232,31744,32512,33024,33536,34304,34816,35584,36096,36864,37376,38144,38656,39424,39936,40704,41216,41728,42496,43008,43776,44288,45056,45568,
                           46336,46848,47616,48128,48896,49408,49920,50688,51200,51968,52480,53248,53760,54528,55040,55808,56320,57088,57600,58112,58880,59392,60160,60672,61440,61952,62720,63232,64000,64512,65280};

      public java.awt.Color color(double t) {
         int i = (int)(t*255);
         return new java.awt.Color(c[i]);
      }
    }
}