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.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import usda.weru.mcrew.CropDlg;
import usda.weru.mcrew.CropObject;
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;
    public static final Logger LOGGER = LogManager.getLogger(OperPopup.class);

    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.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.error("Name not set properly on Multioperation drill down menu."
                    + "  Should be int indicated location of the operation.");
        }
    }
}
