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

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import org.spview.filehandler.FortranFormat;


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

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

    /**
	 * 
	 */
	private static final long serialVersionUID = 2287307861585753581L;
//	private JobPlay  jobplay;                                        // calling JobPlay
    private PanAff   calling;                                        // calling PanAff
    private double[] pfx;                                            // frequency
    private double[] pfy;                                            // intensity
    private String[] pfjsyn;                                         // assignment string

    // panels
    private JPanel      pcentre;
    private JScrollPane jsp;
    private int         currentpos;                                  // current position of vertical scroll bar

    // menus
    private JMenu     jmpred;                                        // select     pred
    private JMenuItem jmipredall;                                    // select all pred
    private JMenuItem jmipredno;                                     // select no  pred
    private JMenu     jmls;                                          // local simulation
    private JMenuItem jmilsshow;                                     // show local simulation
    private JMenuItem jmilshide;                                     // hide local simulation
    private JMenuItem jmilssetp;                                     // set local simulation parameters
    private boolean   locsim;                                        // local simulation status
    private boolean   lspending;                                     // loc-sim pending
    private boolean   lschecked;                                     // loc-sim checked
    private boolean   lsallowed;                                     // loc-sim allowed
    private boolean   lsscaleok;                                     // loc-sim spectrum scaling factor
    private JMenu     jmaddass;                                      // add assignment
    private JMenuItem jmiaddassf;                                    // add frequency assignment
    private JMenuItem jmiaddassi;                                    // add intensity assignment

    // 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
    private double    umin;                                          // area min frequency
    private double    umax;                                          // area max frequency
    private JFSimul   jfs;                                           // simulation manager

    private String lnsep;                                            // line separator
    private String fisep;                                            // file separator
    private Font   mono14;                                           // Monospaced 14 font

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

    /**
	 * 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");
        fisep  = System.getProperty("file.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();
        // select all
        jmpred = new JMenu("Select");
        jmipredall = new JMenuItem("All");
        jmipredall.setEnabled(false);
        jmipredall.addActionListener(this);
        jmpred.add(jmipredall);
        jmipredno = new JMenuItem("No");
        jmipredno.setEnabled(false);
        jmipredno.addActionListener(this);
        jmpred.add(jmipredno);
        // 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 );
        // add assignment
        jmaddass = new JMenu("Add pred assignment(s) to exp");
        jmaddass.setEnabled(false);
        // related to frequency
        jmiaddassf = new JMenuItem("frequency");
        jmiaddassf.addActionListener(this);
        jmaddass.add(jmiaddassf);
        // related to intensity
        jmiaddassi = new JMenuItem("intensity");
        jmiaddassi.addActionListener(this);
        jmaddass.add(jmiaddassi);

        jmb.add(jmpred);
        jmb.add(jmls);
        jmb.add(jmaddass);
        setJMenuBar(jmb);                                            // set menu bar

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

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

        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
            for( int j=0; j<nbixpred; j++ ) {
                int i = ixdebpred+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
            if( nbsable == 0 ) {
                jmpred.setEnabled(false);
            }
            else {
                jmpred.setEnabled(true);
                jmipredall.setEnabled(true);
                jmipredno.setEnabled(false);
            }
            // 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);

            // 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
        for( int j=0; j<nbixpred; j++ ) {
            int i = ixdebpred+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
        if( nbsable == 0 ) {
            jmipredall.setEnabled(false);
        }
        else {
            jmipredall.setEnabled(true);
        }
        // Select-No
        if( nbsassi != 0 ) {                                         // some are selected or assigned
            jmipredno.setEnabled(true);
            // 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 ++;
                }
            }
        }
        else {
            jmipredno.setEnabled(false);
        }
        // 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 {
                if( lschecked && ! lsallowed ) {                     // loc-sim NOT allowed
                    jmls.setEnabled(false);
                }
                else {
                    jmls.setEnabled(true);
                }
            }
        }
        // Add pred assignment(s) to exp
        if( ixexp <  0 ||
            nbs   == 0    ) {
            // no exp selected or no pred selected
            jmaddass.setEnabled(false);
        }
        else {
            jmaddass.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 event
            if( evt.getSource() == jmipredall ) {
                // select all button
                if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) {
                    // help
                    PopFile.show(getName()+fisep+"jmipredall");
                    return;
                }
                // found
                for( int j=0; j<nbixpred; j++ ) {                    // for each visible point
                    if( ixpreds[j] != 0 ) {                          // not assigned
                        ixpreds[j] = 1;                              // set to selected
                    }
                }
                found = true;
                currentpos = 0;                                      // top of jsp
            }
            if( evt.getSource() == jmipredno ) {
                // select none button
                if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) {
                    // help
                    PopFile.show(getName()+fisep+"jmipredno");
                    return;
                }
                // 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( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) {
                // help
                PopFile.show(getName()+fisep+"jmilsshow");
                return;
            }
            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
            if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) {
                // help
                PopFile.show(getName()+fisep+"jmilshide");
                return;
            }
            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
            if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) {
                // help
                PopFile.show(getName()+fisep+"jmilssetp");
                return;
            }
            // 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() == jmiaddassf ||
            evt.getSource() == jmiaddassi    ) {
            if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) {
                // help
                if( evt.getSource() == jmiaddassf ) {
                    PopFile.show(getName()+fisep+"jmiaddassf");
                }
                else {
                    PopFile.show(getName()+fisep+"jmiaddassi");
                }
                return;
            }
            boolean freq;
            if( evt.getSource() == jmiaddassf ) {                    // frequency
                freq = true;
            }
            else {                                                   // intensity
                freq = false;
            }
            calling.addAss2exp( freq );                              // processed by PanAff
            return;
        }
    }

    /**
     * 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 ) {

        umin = cumin;                                                // area min frequency
        umax = cumax;                                                // area max frequency
        jfs.setLsBasic( umin, umax );                                // 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();
    }

}
