package org.spview.gui;
/*
 * Class to select predictions
 */

import org.spview.filehandler.FortranFormat;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/////////////////////////////////////////////////////////////////////

/**
 * Window to select predictions.
 */
public class JFSelPred extends JFrame implements ActionListener, MouseListener {

    /**
     *
     */
    private static final long serialVersionUID = 2287307861585753581L;
    //	private JobPlay  jobplay;                                        // calling JobPlay
    private final PanAff calling;                                        // calling PanAff
    private final double[] pfx;                                            // frequency
    private final double[] pfy;                                            // intensity
    private final String[] pfjsyn;                                         // assignment string
    private final JScrollPane jsp;
    // menus
    private final JMenu jmls;                                          // local simulation
    private final JMenuItem jmilsshow;                                     // show local simulation
    private final JMenuItem jmilshide;                                     // hide local simulation
    private final JMenuItem jmilssetp;                                     // set local simulation parameters
    private final JCheckBox jcpredall;                                     // slect all pred
    private final boolean lschecked;                                     // loc-sim checked
    private final JButton jbaddassf;
    private final JButton jbaddassi;
    private final JFSimul jfs;                                           // simulation manager
    private final String lnsep;                                            // line separator
    private final Font mono14;                                           // Monospaced 14 font
    // panels
    private JPanel pcentre;
    private int currentpos;                                  // current position of vertical scroll bar
    private boolean locsim;                                        // local simulation status
    private boolean lspending;                                     // loc-sim pending
    private boolean lsallowed;                                     // loc-sim allowed
    private boolean lsscaleok;                                     // loc-sim spectrum scaling factor
    // content
    private int nbixpred;                                      // nb of (area) pred
    private JButton[] jbpred;                                        // a button for each (area) pred
    private int ixdebpred;                                     // (full) index of 1st (area) pred
    private int[] ixpreds;                                       // (area) pred status >> -1: nothing(---), 0: already in exp(ASG), 1: selected(SEL)
    private int ixexp;                                         // selected exp index
    private double[] predx;                                         // (area) pred x
    private double[] predy;                                         // (area) pred y

/////////////////////////////////////////////////////////////////////

    /**
     * Construct a JFSelPred to select predictions.
     *
     * @param ccall   calling PanAff
     * @param cix0    location
     * @param ciy0    location
     * @param cpfx    frequency
     * @param cpfy    intensity
     * @param cpfjsyn assignment string
     */
    public JFSelPred(PanAff ccall, int cix0, int ciy0, double[] cpfx, double[] cpfy, String[] cpfjsyn) {

        super("Predictions selection");                              // main window
        setName("JFSelPred");                                        // for help files

        calling = ccall;                                             // calling PanAff
        pfx = cpfx;                                              // frequency
        pfy = cpfy;                                              // intensity
        pfjsyn = cpfjsyn;                                           // assignment string

        lnsep = System.getProperty("line.separator");
        mono14 = new Font("Monospaced", Font.PLAIN, 14);
        currentpos = 0;                                              // current position of vertical scroll bar
        lschecked = false;                                           // loc-sim NOT checked
        lsallowed = false;                                           // loc-sim NOT allowed

        addWindowListener(new WindowAdapter() {                      // clean end
            public void windowClosing(WindowEvent e) {
                if (locsim) {
                    jmilshide.doClick();                             // hide local simulation
                }
                calling.endSelPred();                                // end prediction selection
                dispose();                                           // free window
            }
        });

        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setLocation(cix0, ciy0);
        setSize(650, 200);

        jfs = new JFSimul(this, cix0, ciy0 + getSize().height + 10);   // simulation manager

//        // MENUS
        JMenuBar jmb = new JMenuBar();
        // local simulation
        jmls = new JMenu("Local simulation");
        jmilsshow = new JMenuItem("Show");
        jmilsshow.addActionListener(this);
        jmls.add(jmilsshow);
        jmilshide = new JMenuItem("Hide");
        jmilshide.addActionListener(this);
        jmls.add(jmilshide);
        jmilssetp = new JMenuItem("Set parameters");
        jmilssetp.addActionListener(this);
        jmls.add(jmilssetp);
        jmb.add(jmls);
        jmls.setVisible(false);
        setJMenuBar(jmb);                                            // set menu bar

        jcpredall = new JCheckBox("Select All");
        jcpredall.setSelected(false);
        jcpredall.addActionListener(this);

        jbaddassf = new JButton("Frequency");
        jbaddassf.setEnabled(false);
        jbaddassf.addActionListener(this);

        jbaddassi = new JButton("Intensity");
        jbaddassi.setEnabled(false);
        jbaddassi.addActionListener(this);

        getContentPane().setLayout(new BorderLayout());

        // panels
        jsp = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        getContentPane().add(jsp, "Center");

        JPanel jp = new JPanel();
        jp.add(jcpredall);
        jp.add(jbaddassf);
        jp.add(jbaddassi);

        getContentPane().add(jp, "South");

        setVisible(false);
    }

/////////////////////////////////////////////////////////////////////

    /**
     * Show area selected predictions.
     *
     * @param cnbixpred  nb of (area) pred
     * @param cixdebpred (full) index of 1st (area) pred
     * @param cixpreds   (area) pred status >> -1: nothing(---), 0: already assigned(ASG), 1: selected(SEL)
     * @param cixexp     selected exp index
     */
    public void setContent(int cnbixpred, int cixdebpred, int[] cixpreds, int cixexp) {

        nbixpred = cnbixpred;                                       // nb of (area) pred
        ixdebpred = cixdebpred;                                      // (full) index of 1st (area) pred
        ixpreds = cixpreds;                                        // (area) pred status
        ixexp = cixexp;                                          // selected exp index

        if (nbixpred == 0) {
            // nothing to show
            setVisible(false);
        } else {
            jbpred = new JButton[nbixpred];                          // for each point
            int nbsable = 0;                                         // nb of selectable pred
            int nbassi = 0;                                         // nb of assigned   pred

            pcentre = new JPanel(new GridLayout(Math.max(5, nbixpred), 1, 0, 0));  // at least 5 lines
            // create prediction buttons
            int offset = 0;
            for (int j = 0; j < nbixpred; j++) {
                while (pfy[ixdebpred + offset + j] < PanAff.getThreshold()) offset++;
                int i = ixdebpred + offset + j;                                 // (full) index of (area) pred
                if (ixpreds[j] == -1) {                        // unselected
                    jbpred[j] = new JButton("--- : " + FortranFormat.formFreq(pfx[i]) + " | " + FortranFormat.formInt(pfy[i]) + " | " + pfjsyn[i]);
                    jbpred[j].setToolTipText("Select/unselect prediction");
                    nbsable++;
                } else if (ixpreds[j] == 0) {                        // assigned
                    jbpred[j] = new JButton("ASG : " + FortranFormat.formFreq(pfx[i]) + " | " + FortranFormat.formInt(pfy[i]) + " | " + pfjsyn[i]);
                    nbassi++;
                } else {                                               // selected
                    jbpred[j] = new JButton("SEL : " + FortranFormat.formFreq(pfx[i]) + " | " + FortranFormat.formInt(pfy[i]) + " | " + pfjsyn[i]);
                    jbpred[j].setToolTipText("Select/unselect prediction");
                }
                jbpred[j].setFont(mono14);
                jbpred[j].addActionListener(this);
                jbpred[j].addMouseListener(this);
                pcentre.add(jbpred[j]);
            }
            // set menu buttons status
            // Select
            jcpredall.setSelected(nbsable == 0);

            // Local simulation
            if (nbassi == 0) {
                jmls.setEnabled(false);
            } else {
                jmls.setEnabled(true);
                // set predx, predy of assigned pred
                predx = new double[nbassi];
                predy = new double[nbassi];
                int curi = 0;                                        // current index
                for (int j = 0; j < nbixpred; j++) {
                    int i = ixdebpred + j;                             // (full) index of (area) pred
                    if (ixpreds[j] == 0) {
                        predx[curi] = pfx[i];
                        predy[curi] = pfy[i];
                        curi++;
                    }
                }
            }
            jmilsshow.setEnabled(true);
            jmilshide.setEnabled(false);
            jmilssetp.setEnabled(false);
            locsim = false;                                      // loc-sim NOT enabled
            lspending = false;                                      // loc-sim NOT pending
            lsscaleok = false;                                      // loc-sim spectrum scaling factor NOT set
            // Add pred assignment(s) to exp
            //jmaddass.setEnabled(false);
            jbaddassf.setEnabled(false);
            jbaddassi.setEnabled(false);

            // show it
            jsp.setViewportView(pcentre);
            setVisible(true);
        }
    }

    // Locally update content
    private void locSetContent() {

        int nbs = 0;                                             // nb of selected   pred
        int nbsable = 0;                                             // nb of selectable pred
        int nbsassi = 0;                                             // nb of selected or assigned pred

        pcentre = new JPanel(new GridLayout(Math.max(5, nbixpred), 1, 0, 0));
        // create prediction buttons
        int offset = 0;
        for (int j = 0; j < nbixpred; j++) {
            while (pfy[ixdebpred + offset + j] < PanAff.getThreshold()) offset++;
            int i = ixdebpred + offset + j;
            if (ixpreds[j] == -1) {                            // unselected
                jbpred[j] = new JButton("--- : " + FortranFormat.formFreq(pfx[i]) + " | " + FortranFormat.formInt(pfy[i]) + " | " + pfjsyn[i]);
                jbpred[j].setToolTipText("Select/unselect prediction");
                nbsable++;
            } else if (ixpreds[j] == 0) {                            // assigned
                jbpred[j] = new JButton("ASG : " + FortranFormat.formFreq(pfx[i]) + " | " + FortranFormat.formInt(pfy[i]) + " | " + pfjsyn[i]);
                nbsassi++;
            } else {                                                   // selected
                jbpred[j] = new JButton("SEL : " + FortranFormat.formFreq(pfx[i]) + " | " + FortranFormat.formInt(pfy[i]) + " | " + pfjsyn[i]);
                jbpred[j].setToolTipText("Select/unselect prediction");
                nbs++;
                nbsassi++;
            }
            jbpred[j].setFont(mono14);
            jbpred[j].addActionListener(this);
            jbpred[j].addMouseListener(this);
            pcentre.add(jbpred[j]);
        }
        // set menu buttons status
        // Select-All
        jcpredall.setSelected(nbsable == 0);
        if (nbsassi != 0) { // some are selected or assigned
            // set predx, predy of selected or assigned pred
            predx = new double[nbsassi];
            predy = new double[nbsassi];
            int curi = 0; // current index
            for (int j = 0; j < nbixpred; j++) {
                int i = ixdebpred + j; // (full) index of (area) pred
                if (ixpreds[j] >= 0) {
                    predx[curi] = pfx[i];
                    predy[curi] = pfy[i];
                    curi++;
                }
            }
        }
        // show running loc-sim
        if (locsim) {
            if (nbsassi == 0) {
                // nothing to show
                calling.setLocSim(false);
                jmls.setEnabled(false);
            } else {
                // some are selected or assigned
                if (jfs.calLocSim(predx, predy)) {
                    // loc-sim calculated
                    // show it
                    calling.setLocSim(locsim);
                } else {
                    // nothing to show
                    calling.setLocSim(false);
                }
                jmls.setEnabled(true);
            }
        } else {
            // NO running loc-sim
            if (nbsassi == 0) {                                     // NO selected or assigned  pred
                jmls.setEnabled(false);
            } else {
                // loc-sim NOT allowed
                jmls.setEnabled(!lschecked || lsallowed);
            }
        }
        // Add pred assignment(s) to exp
        if (ixexp < 0 ||
                nbs == 0) {
            // no exp selected or no pred selected
            //jmaddass.setEnabled(false);
            jbaddassf.setEnabled(false);
            jbaddassi.setEnabled(false);
        } else {
            jbaddassf.setEnabled(true);
            jbaddassi.setEnabled(true);
        }

        // update view
        jsp.setViewportView(pcentre);
        jsp.getVerticalScrollBar().setValue(currentpos);             // at the right position
    }

/////////////////////////////////////////////////////////////////////

    // Mouse events are managed to show in Panaff (yellow square)
    // which pred is currently pointed by mouse (by its index)

    /**
     * Process Mouse event.
     */
    public void mouseEntered(MouseEvent mevt) {

        for (int j = 0; j < nbixpred; j++) {                            // for each visible point
            int ixep = ixdebpred + j;                                  // (full) index of (area) pred
            if (mevt.getSource() == jbpred[j]) {
                calling.setPredable(ixep);
                break;
            }
        }
    }

    /**
     * Process Mouse event.
     */
    public void mouseExited(MouseEvent mevt) {

        for (int j = 0; j < nbixpred; j++) {                            // for each visible point
//            int ixep = ixdebpred+j;                                  // (full) index of (area) pred
            if (mevt.getSource() == jbpred[j]) {
                calling.setPredable(-1);
                break;
            }
        }
    }

    /**
     * Not impemented.
     */
    public void mouseClicked(MouseEvent mevt) {
    }

    /**
     * Not impemented.
     */
    public void mousePressed(MouseEvent mevt) {
    }

    /**
     * Not impemented.
     */
    public void mouseReleased(MouseEvent mevt) {
    }

    /**
     * Process events.
     */
    public void actionPerformed(ActionEvent evt) {

        // pred selection
        boolean found = false;                                       // pred selection not found
        currentpos = 0;
        for (int j = 0; j < nbixpred; j++) {                            // for each visible point
//            int ixep = ixdebpred+j;                                  // (full) index of (area) pred
            if (evt.getSource() == jbpred[j]) {
                // prediction button
                // found
                if (ixpreds[j] == 0) {                              // assigned : inactive
                    return;
                }
                ixpreds[j] = -ixpreds[j];                            // reverse status
                found = true;                                        // end search
                currentpos = jsp.getVerticalScrollBar().getValue();  // current position of vertical scroll bar
                break;
            }
        }
        if (!found) {
            // scan other pred selection even1
            if (evt.getSource() == jcpredall) {
                if (jcpredall.isSelected()) {
                    // select all button
                    // found
                    for (int j = 0; j < nbixpred; j++) {                    // for each visible point
                        if (ixpreds[j] != 0) {                          // not assigned
                            ixpreds[j] = 1;                              // set to selected
                        }
                    }
                } else {
                    // found
                    for (int j = 0; j < nbixpred; j++) {                    // for each visible point
                        if (ixpreds[j] != 0) {                          // not assigned
                            ixpreds[j] = -1;                             // set to unselected
                        }
                    }
                }
                found = true;
                currentpos = 0;                                      // top of jsp
            }
        }
        if (found) {                                                // pred selection changed
            locSetContent();                                         // update window content
            calling.drawPredSel();                                   // update PanAff (draw)
            calling.setJta();                                        // update PanAff (TextArea)
            return;
        }
        // local simulation
        if (evt.getSource() == jmilsshow) {
            // loc-sim show button
            if (lsallowed) {                                        // lsallowed is set by PanAff through setLsBasic
                if (!jfs.isSimParmSet()) {                         // simulation parameters have to be setted first
                    lspending = true;                                // loc-sim asked
                    return;
                }
                // loc-sim spectrum scaling factor
                if (!lsscaleok) {
                    // not set
                    // set loc-sim scale by mean of ALL (area) pred
                    double[] cpredx = new double[nbixpred];
                    double[] cpredy = new double[nbixpred];
                    for (int j = 0; j < nbixpred; j++) {
                        int i = ixdebpred + j;
                        cpredx[j] = pfx[i];
                        cpredy[j] = pfy[i];
                    }
                    if (jfs.calLocSim(cpredx, cpredy)) {
                        // loc-sim spectrum calculated
                        calling.setLsScale();                        // set loc-sim spectrum scaling factor in PanAff
                        lsscaleok = true;                            // loc-sim spectrum scaling factor is set
                    }
                }
                // calculate loc-sim spectrum limited to selected pred
                if (jfs.calLocSim(predx, predy)) {
                    locsim = true;                                   // loc-sim running
                    jmilsshow.setEnabled(false);
                    jmilshide.setEnabled(true);
                    jmilssetp.setEnabled(true);
                    calling.setLocSim(locsim);                       // set (and show) loc-sim spectrum in PanAff
                } else {
                    calling.setLocSim(false);                        // do NOT show loc-sim spectrum in PanAff
                }
            } else {                                                   // ! lsallowed
                JOptionPane.showMessageDialog(null, "Local simulation is not allowed" + lnsep +
                        "Prediction has to be associated to a spectrum data file");
                jmls.setEnabled(false);
            }
            return;
        }
        if (evt.getSource() == jmilshide) {
            // loc-sim hide button
            locsim = false;                                          // NO loc-sim running
            jmilsshow.setEnabled(true);
            jmilshide.setEnabled(false);
            calling.setLocSim(locsim);                               // do NOT show loc-sim spectrum in PanAff
            return;
        }
        if (evt.getSource() == jmilssetp) {
            // loc-sim set parameters
            // only need to be set visible (simParmSet will be called by JFSimul once parameters ready)
            jfs.setVisible(true);
            return;
        }
        // add assignment(s)
        if (evt.getSource() == jbaddassf ||
                evt.getSource() == jbaddassi) {
            boolean freq;
            // frequency
            // intensity
            freq = evt.getSource() == jbaddassf;
            calling.addAss2exp(freq);                              // processed by PanAff
        }
    }

    /**
     * Set local simulation basics.
     *
     * @param cumin      area min frequency
     * @param cumax      area max frequency
     * @param clsallowed loc-sim allowed status
     */
    public void setLsBasic(double cumin, double cumax, boolean clsallowed) {

        // area min frequency
        // area max frequency
        jfs.setLsBasic(cumin, cumax);                                // set in JFSimul
        lsallowed = clsallowed;                                      // loc-sim allowed status
    }

    /**
     * Simulation parmeters are set (called by JFSimul).
     */
    public void simParmSet() {

        if (lspending ||
                locsim) {
            // locsim pending or running
            lspending = false;
            lsscaleok = false;                                      // has to be resetted
            jmilsshow.setEnabled(true);
            jmilsshow.doClick();                                     // loc-sim show as do a click
        }
    }

    /**
     * Get loc-sim spectrum X.
     */
    public double[] getLsx() {

        return jfs.getLsx();
    }

    /**
     * Get loc-sim spectrum Y.
     */
    public double[] getLsy() {

        return jfs.getLsy();
    }

}
