package usda.weru.mcrew.timeline;

import java.awt.event.ActionEvent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import org.apache.log4j.Logger;
import usda.weru.mcrew.CropDlg;
import usda.weru.mcrew.CropObject;
import usda.weru.mcrew.TablePanel;
import usda.weru.mcrew.OperationDlg;
import usda.weru.mcrew.OperationObject;
import usda.weru.mcrew.RowInfo;
import usda.weru.mcrew.XMLConstants;
import usda.weru.mcrew.timeline.TimelinePanelData.ManageRow;

/**
 * This class will handle what to display and actions to take on a right click.
 * @author jonathanhornbaker
 */
public class OperPopup extends JPopupMenu
{
    public static final long serialVersionUID = 89238947823L;
    
    private final JMenuItem incrDay = new JMenuItem();
    private final JMenuItem decrDay = new JMenuItem();
    private final JMenuItem incrWeek = new JMenuItem();
    private final JMenuItem decrWeek = new JMenuItem();
    private final JMenuItem incrSpec = new JMenuItem();
    private final JMenuItem decrSpec = new JMenuItem();

    private final JMenuItem opDrill = new JMenuItem();
    private final JMenuItem crDrill = new JMenuItem();
    
    private final JMenu multiOpDrill = new JMenu();
    private final JMenu multiCrDrill = new JMenu();
    
    private final TimelinePanel time;
    private ManageRow management;//This field will be null for any non-single selection.

    private RowInfo[] oprns;

    /**
     * Basic constructor.
     * @param input 
     */
    public OperPopup(TimelinePanel input)
    {
        time = input;
        createPopup();
    }
    
    /**
     * Designates which operation has focus for this click.  Only for single selections.
     * @param man 
     */
    public void setManagement(ManageRow man) { management = man; }

    /**
     * Makes the actual visible component of the popup.
     */
    private void createPopup()
    {
        //Date Operations
        incrDay.setText("Increment Operation One Day");
        incrDay.addActionListener((ActionEvent evt) -> { modiDate(1); });
        this.add(incrDay);
        decrDay.setText("Decrement Operation One Day");
        decrDay.addActionListener((ActionEvent evt) -> { modiDate(-1); });
        this.add(decrDay);
        incrWeek.setText("Increment Operation One Week");
        incrWeek.addActionListener((ActionEvent evt) -> { modiDate(7); });
        this.add(incrWeek);
        decrWeek.setText("Decrement Operation One Week");
        decrWeek.addActionListener((ActionEvent evt) -> { modiDate(-7); });
        this.add(decrWeek);
        incrSpec.setText("Specify Date Increment");
        incrSpec.addActionListener((ActionEvent evt) -> { selectDateOffset(1); });
        this.add(incrSpec);
        decrSpec.setText("Specify Date Decrement");
        decrSpec.addActionListener((ActionEvent evt) -> { selectDateOffset(-1); });
        this.add(decrSpec);

        this.addSeparator();
        //Data Operations
        opDrill.setText("Operation Drill-down Screen");
        opDrill.addActionListener((ActionEvent evt) -> { showOpDrillDown(); });
        this.add(opDrill);
        crDrill.setText("Crop Drill-down Screen");
        crDrill.addActionListener((ActionEvent evt) -> { showCrDrillDown(); });
        this.add(crDrill);
        
        multiOpDrill.setText("Operation Drill-down Screen");
        this.add(multiOpDrill);
        multiCrDrill.setText("Crop Drill-down Screen");
        this.add(multiCrDrill);
    }

    /**
     * Notifies the popup of which operations it spans, so it can decide what options
     * are enabled.
     * @param input 
     */
    public void setStretch(RowInfo[] input)
    {
        opDrill.setVisible(true);
        crDrill.setVisible(true);
        multiOpDrill.setVisible(false);
        multiCrDrill.setVisible(false);
        if(input.length > 1)
        {
            opDrill.setEnabled(false);
            crDrill.setEnabled(false);
        }
        else
        {
            opDrill.setEnabled(true);
            if(((OperationObject) input[0].getDataObject(XMLConstants.soperation)).hasCrop()) 
                crDrill.setEnabled(true);
            else crDrill.setEnabled(false);
        }
        oprns = input;
    }
    
    public void setStretch(RowInfo[] input, boolean multiOp)
    {
        if(!multiOp) setStretch(input);
        opDrill.setVisible(false);
        crDrill.setVisible(false);
        multiOpDrill.setVisible(true);
        multiCrDrill.setVisible(true);
        multiOpDrill.removeAll();
        multiCrDrill.removeAll();
        for(int index = 0; index < input.length; index ++)
        {
            RowInfo row = input[index];
            JMenuItem subOpDrill = new JMenuItem();
            subOpDrill.setName(Integer.toString(index));
            OperationObject opOb = (OperationObject) row.getDataObject(XMLConstants.soperation);
            String name = opOb.mOperationName;
            subOpDrill.setText(name);
            subOpDrill.addActionListener((ActionEvent evt) -> { showMultiOpDrillDown(evt); });
            multiOpDrill.add(subOpDrill);
            
            JMenuItem subCrDrill = new JMenuItem();
            subCrDrill.setText(name);
            subCrDrill.setName(Integer.toString(index));
            subCrDrill.addActionListener((ActionEvent evt) -> { showMultiCrDrillDown(evt); });
            multiCrDrill.add(subCrDrill);
            subCrDrill.setEnabled(opOb.hasCrop());
        }
        oprns = input;
    }

    /**
     * Modifies the date of all operations currently activated by the popup
     * by the specified number.
     * @param input 
     */
    public void modiDate(int input)
    {
        for(RowInfo row : oprns)
        {
            row.setDate(row.getDate().increment(input));
        }
        time.repaint();
    }

    /**
     * Gives the user a dialogue box in which they can specify a number for which
     * to offset the days.
     * @param multiplier 
     */
    public void selectDateOffset(int multiplier)
    {
        int result = 0;
        String res = (String) JOptionPane.showInputDialog(time, "Specify number of days to offset:", 
                "Select Days to Offset", JOptionPane.PLAIN_MESSAGE, null, null, "1");
        boolean valid = false;
        try
        {
            result = Integer.parseInt(res);
            if(result > -1) valid = true;
        }
        catch(NumberFormatException nfe) {}
        while(!valid)
        {
            res = (String) JOptionPane.showInputDialog(time, "Input must be a positive integer.\n"
                    + "Specify number of days to offset:", "Select Days to Offset", 
                    JOptionPane.PLAIN_MESSAGE, null, null, "1");
            try
            {
                result = Integer.parseInt(res);
                if(result < 0) continue;
                valid = true;
            }
            catch(NumberFormatException nfe) {}
        }
        modiDate(result * multiplier);
    }

    /**
     * Brings up the Operation drill down screen iff there is only one currently
     * selected operation.
     */
    public void showOpDrillDown()
    {
        if(oprns.length > 1 || oprns.length == 0) return;
        OperationObject op = (OperationObject) oprns[0].getDataObject(XMLConstants.soperation);
        String dateString = oprns[0].getDate().getDate();
        OperationDlg operationDlg = new OperationDlg(management.getTable(),
                op, dateString, management.data, oprns[0]);
        operationDlg.setModal(true);
        operationDlg.setVisible(true);
    }

    /**
     * Brings up the Crop drill down Screen iff there is only one currently selected
     * operation && that operation contains a crop.
     */
    public void showCrDrillDown()
    {
        if(oprns.length > 1 || oprns.length == 0) return;
        OperationObject op = (OperationObject) oprns[0].getDataObject(XMLConstants.soperation);
        if(!op.hasCrop()) return;
        CropObject cr = op.getCrop();
        CropDlg cropDrill = new CropDlg(management.getTable(), cr.mCropName, cr, 
                management.data, oprns[0], time.getSelected());
        cropDrill.setModal(true);
        cropDrill.setVisible(true);
    }
    
    public void showMultiOpDrillDown(ActionEvent evt)
    {
        try
        {
            int order = Integer.parseInt(((JMenuItem) evt.getSource()).getName());
            OperationObject op = (OperationObject) oprns[order].getDataObject(XMLConstants.soperation);
            String dateString = oprns[order].getDate().getDate();
            OperationDlg operationDlg = new OperationDlg(management.getTable(),
                    op, dateString, management.data, oprns[order]);
            operationDlg.setModal(true);
            operationDlg.setVisible(true);
        }
        catch(NumberFormatException nfe)
        {
            Logger LOGGER = Logger.getLogger(OperPopup.class);
            LOGGER.error("Name not set properly on Multioperation drill down menu."
                    + "  Should be int indicated location of the operation.");
        }
    }
    
    public void showMultiCrDrillDown(ActionEvent evt)
    {
        try
        {
            int order = Integer.parseInt(((JMenuItem) evt.getSource()).getName());
            OperationObject op = (OperationObject) oprns[order].getDataObject(XMLConstants.soperation);
            if(!op.hasCrop()) return;
            
            CropObject cr = op.getCrop();
            CropDlg cropDrill = new CropDlg(management.getTable(), cr.mCropName, cr, 
                    management.data, oprns[order], time.getSelected());
            cropDrill.setModal(true);
            cropDrill.setVisible(true);
        }
        catch(NumberFormatException nfe)
        {
            Logger LOGGER = Logger.getLogger(OperPopup.class);
            LOGGER.error("Name not set properly on Multioperation drill down menu."
                    + "  Should be int indicated location of the operation.");
        }
    }
}
