/*
 * calFactorDialog.java
 *
 * Created on May 24, 2004, 1:56 PM
 */
package usda.weru.weps;

import com.klg.jclass.cell.JCCellEditor;
import com.klg.jclass.cell.JCCellEditorListener;
import com.klg.jclass.cell.JCCellEditorSupport;
import com.klg.jclass.cell.JCCellInfo;
import com.klg.jclass.cell.JCComponentCellRenderer;
import com.klg.jclass.cell.JCKeyModifier;
import com.klg.jclass.table.CellStyleModel;
import com.klg.jclass.table.JCCellRange;
import com.klg.jclass.table.JCTable;
import com.klg.jclass.table.JCTableEnum;
import com.klg.jclass.table.data.JCEditableVectorDataSource;
import com.klg.jclass.table.data.JCVectorDataSource;
import de.schlichtherle.io.File;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.text.Format;
import java.text.SimpleDateFormat;
import usda.weru.util.*;

import java.util.*;
import usda.weru.mcrew.*;
import javax.swing.*;

/**
 * This GUI helps the user in telling what the calibration factors are like and
 * their details regarding their project name, current run, selected management file,
 * the planting date for various crops and their biomass adjustment fact, etc.
 * @author manmohan
 */
public class CalFactorDialog extends usda.weru.weps.gui.CalFactorDialog_n implements PropertyChangeListener {

    private File c_managementFile;
    private Vector<CalibrationAdjustment> c_adjustments = new Vector<CalibrationAdjustment>();
    private PropertyChangeSupport changes;
    private File currentFile;
    private File projectDirectory;
    private JCVectorDataSource ds;
    private JCTable table;

    /**  Default constructor that creates the new GUI form as CalibrationFactors */
    public CalFactorDialog(RunProgram runprogram, usda.weru.util.ConfigData cd, RunFileData rfd) {

        //Create table
        createTable();

        changes = new PropertyChangeSupport(this);
        changes.addPropertyChangeListener(runprogram);
        cd.addPropertyChangeListener(this);
        rfd.addPropertyChangeListener(this);
        cd.fireAll(this);
        rfd.fireAll(this);
    }

    public void setVisible(boolean b) {
        setVisible(b, true);
    }

    public void setVisible(final boolean b, boolean invokeOnSwing) {
        if (invokeOnSwing) {
            SwingUtilities.invokeLater(new Runnable() {

                public void run() {
                    setVisible(b, false);
                }
            });
        }
        else {
            super.setVisible(b);
        }
    }

    private void createTable() {
        //Table
        table = new JCTable();
        JP_table.add(table, BorderLayout.CENTER);
        table.setTrackCursor(false);

        //Data
        ds = new JCEditableVectorDataSource();
        table.setRowLabelDisplay(false);
        table.setDataSource(ds);

        //Scrolling
        table.setVertSBPosition(JCTableEnum.POSITION_AT_SIDE);
        table.setHorizSBPosition(JCTableEnum.POSITION_AT_SIDE);
        table.setVertSBDisplay(JCTableEnum.SCROLLBAR_AS_NEEDED);
        table.setHorizSBDisplay(JCTableEnum.SCROLLBAR_AS_NEEDED);
        table.setAutoScroll(JCTableEnum.AUTO_SCROLL_BOTH);

        //Resizing
        table.setAllowCellResize(JCTableEnum.RESIZE_COLUMN);
        table.setAllowResizeBy(JCTableEnum.RESIZE_BY_LABELS);


        //Columns
        String labels[] = {"Planting\nDate", "Crop", "Biomass\nAdj.\nFactor", ""};
        ds.setNumColumns(labels.length);
        ds.setColumnLabels(labels);

        table.setPixelWidth(0, 85);
        table.setPixelWidth(1, 200);
        table.setPixelWidth(2, 60);
        table.setPixelWidth(3, 100);

        table.setPixelHeight(-1, 50);

        //Header style
        CellStyleModel labelStyle = table.getDefaultLabelStyle();
        labelStyle.setBackground(new Color(246, 200, 84));
        labelStyle.setCellRenderer(new MyMultilineCellRenderer());

        table.getDefaultCellStyle().setEditable(false);
        CellStyleModel dateStyle = (CellStyleModel) table.getDefaultCellStyle().clone();
        dateStyle.setCellRenderer(new MyDateCellRenderer());
        table.setCellStyle(new JCCellRange(JCTableEnum.ALLCELLS, 0, JCTableEnum.ALLCELLS, 0), dateStyle);

        CellStyleModel saveAsStyle = (CellStyleModel) table.getDefaultCellStyle().clone();
        SaveAsCellRendererEditor button = new SaveAsCellRendererEditor();
        saveAsStyle.setCellRenderer(button);
        saveAsStyle.setCellEditor(button);
        saveAsStyle.setEditable(true);
        table.setCellStyle(new JCCellRange(JCTableEnum.ALLCELLS, 3, JCTableEnum.ALLCELLS, 3), saveAsStyle);


        //table.revalidate();

        //Rows
        ds.setNumRows(0);

    }
    protected String c_cropDirPath;

    public void propertyChange(PropertyChangeEvent e) {
        if (e.getPropertyName().equals(usda.weru.util.ConfigData.CurrentProj)) {
            projectDirectory = new File(Util.parse((String) e.getNewValue()));
        }
        else if (e.getPropertyName().equals(RunFileData.ManageFile)) {
            currentFile = new File((String) e.getNewValue());
        }
        else if (e.getPropertyName().equals(usda.weru.util.ConfigData.CropDB)) {
            c_cropDirPath = e.getNewValue().toString();
        }
    }

    /**
     * This button is used to close the calibration factor dialog once the
     * user is done accessing the information needed.
     * @param evt The action event that is generated when this "Close" button is hit.
     */
    public void JBClose_actionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:
        setVisible(false);
        dispose();
    }

    /**
     * This button is used to apply the calibration factor to the management file in the
     * run directory.
     * @param evt The action event that is generated when this "Apply" button is hit.
     */
    protected void JB_apply_actionPerformed(java.awt.event.ActionEvent evt) {

        //Is MCREW open?
        if (Mcrew.isOpen()) {
            JOptionPane.showMessageDialog(this, "Unable to set current management file.\nPlease close MCREW first.", "Calibration", JOptionPane.WARNING_MESSAGE);
            return;
        }

// We shouldn't be checking the soil UI when we are only attempting a management file save - LEW
        //Is soil open?
//        if (usda.weru.soil.Soil.isOpen()){
//            JOptionPane.showMessageDialog(this, "Unable to set current management file.\nPlease close the soil editor.", "Calibration", JOptionPane.WARNING_MESSAGE);
//            return;
//        }

        //We only want to work with files in the project, not template files.

        File fileInProject = new File(projectDirectory, currentFile.getName());
        File preBackupInProject = new File(fileInProject.getAbsolutePath());
        File postBackupInProject = null;

        //Do we Need to backup the current file?
        if (preBackupInProject.exists()) {
            postBackupInProject = Util.incrementFileName(fileInProject, "_backup", ".man");
            boolean backupResult = preBackupInProject.renameTo(postBackupInProject);
            if (!backupResult) {
                JOptionPane.showMessageDialog(this, "Unable to save backup of the current management file.\n" + fileInProject.getPath(), "Calibration", JOptionPane.WARNING_MESSAGE);
                return;
            }
        }

        if (Util.copyFile(c_managementFile, fileInProject)) {
            //We don't need extra backups in the project folder.
            if (postBackupInProject != null) {
                postBackupInProject.delete();
            }
            changes.firePropertyChange(RunFileData.ManageFile, null, fileInProject.getAbsolutePath());
            JOptionPane.showMessageDialog(this, "The current project is now using the calibrated management file.", "Calibration", JOptionPane.INFORMATION_MESSAGE);
            dispose();
        }
        else {
            JOptionPane.showMessageDialog(this, "Unable to copy the calibrated management file to the project.\n" + c_managementFile.getPath(), "Calibration", JOptionPane.WARNING_MESSAGE);
            postBackupInProject.renameTo(fileInProject);
        }



    }
    protected Map<CalibrationAdjustment, CropObject> c_cropObjects;

    public void updateManagementFile() {
        if(c_hasBadValues){
            return;
        }
        ManageData manData = new ManageData();
        JB_apply.setEnabled(false);
        File backupFile = Util.incrementFileName(c_managementFile, "_backup", ".man");
        boolean appliedAdjustments = false;
        boolean renameResult = c_managementFile.renameTo(backupFile);
        
        
        
        if (renameResult) {
            Format dateFormat = new SimpleDateFormat("MMM dd, yy");
            String notesHeader = "Crop Calibration Adjusment From [" + JTF_runName.getText() + "] on " + dateFormat.format(new Date()) + "\n";
            List <String[]> manTable = new LinkedList <String[]>();
            manTable.add(new String[]{"Date", "Crop", "Target", "Units", "Old", "New"});

            manData.readDataFile(backupFile.getPath());
            //Do Magic, loop over each adjustment.  Find the crop record and change the value.

            for (CalibrationAdjustment adjustment : c_adjustments) {
                for (Object o : manData.getRows()) {
                    RowInfo row = (RowInfo) o;
                    OperationObject operation = (OperationObject) row.getAllDataObjects().get("operation");
                    if (operation.hasCrop()) {
                        if (row.getDate().toString().equals(adjustment.date.toString())) {
                            CropObject crop = operation.getCrop();
                            if (crop.getCropName().trim().equals(adjustment.crop)) {
                                //We found the operation
                                adjustment.oldValue = crop.getValue("cbafact", 0);
                                crop.setValue("cbafact", adjustment.value, 0);
                                String targetYield = crop.getValue("tgtyield");
                                String targetYieldUnits = crop.getValue("hyldunits");
                                appliedAdjustments = true;
                                String cropNotes = crop.getParameter("crop_notes").getValue().toString();
                                
                                String[][] cropTable = new String[2][];
                                cropTable[0] = new String[] {"Target", "Units", "Old", "New"};
                                cropTable[1] = new String[] {targetYield, targetYieldUnits, adjustment.oldValue, adjustment.value};

                                cropNotes += "\n" + notesHeader;
                                cropNotes += Util.makePrettyTable(cropTable) + "\n";
                                                                                                
                                crop.getParameter("crop_notes").setValue(cropNotes);

                                manTable.add(new String[]{dateFormat.format(adjustment.date.getTime()), adjustment.crop, targetYield, targetYieldUnits, adjustment.oldValue, adjustment.value});
                                
                                if (c_cropObjects == null) {
                                    c_cropObjects = new Hashtable<CalibrationAdjustment, CropObject>();
                                }
                                c_cropObjects.put(adjustment, crop);
                            }


                        }
                    }
                }
            }


            if (manTable.size() > 1) {
                String notes = notesHeader;
                notes += Util.makePrettyTable(manTable.toArray(new String[manTable.size()][]));
                manData.mwepsmanfilenotes = manData.mwepsmanfilenotes + "\n" + notes + "\n";
            }

            if (appliedAdjustments) {
                manData.writeDataFile(c_managementFile.getPath());
                this.JB_apply.setEnabled(true);

            }
            else {
                JOptionPane.showMessageDialog(this, "Could not find the crop records in the management file", "Calibration", JOptionPane.WARNING_MESSAGE);
                backupFile.renameTo(c_managementFile);
            }


        }
        else {
            JOptionPane.showMessageDialog(this, "Unable to save backup of the management file.\nApplication of the adjustment values was aborted.", "Calibration", JOptionPane.WARNING_MESSAGE);
        }

    }
    private boolean c_hasBadValues;

    public void addCalibrationAdjustment(String date, String crop, String biomassAdjFactor) {
        // now takes two string arguments so we can get a temporary workaround "calibration" issue - LEW



        JulianCalendar d = new JulianCalendar(date.trim(), date.trim());
        CalibrationAdjustment ca = new CalibrationAdjustment(d, crop, biomassAdjFactor);
        if (!ca.valid){
            c_hasBadValues = true;
            biomassAdjFactor = "ERR";
        }
        c_adjustments.add(ca);


        Vector<Object> values = new Vector<Object>();
        values.add(d);
        values.add(crop);
        values.add(biomassAdjFactor);
        values.add(ca);


        ds.addRow(JCTableEnum.MAXINT, null, values);
        //setTableLooks();
        updateApplyButton();
    }

    public void setManagementFile(File file) {
        c_managementFile = file;
        updateApplyButton();

    }

    private void updateApplyButton() {
        if (!c_hasBadValues && c_managementFile != null && c_adjustments.size() > 0) {
            JB_apply.setEnabled(true);
        }
        else {
            JB_apply.setEnabled(false);
        }
    }

    static class CalibrationAdjustment {

        public JulianCalendar date;
        public String crop;
        public String value;
        public String oldValue;
        public boolean valid;

        public CalibrationAdjustment(JulianCalendar d, String c, String v) {
            date = d;
            crop = c.trim();
            value = v;

            if(v.startsWith("*****")){
                value = "ERR";
                valid = false;
            }
            else{
                valid = true;
            }
        }
    }

    class SaveAsCellRendererEditor extends JButton implements JCComponentCellRenderer, JCCellEditor, ActionListener {

        protected JCCellEditorSupport c_support = new JCCellEditorSupport();
        protected CalibrationAdjustment ca;

        public SaveAsCellRendererEditor() {
            super("Save As");
            addActionListener(this);
        }

        public Component getRendererComponent(JCCellInfo cellInfo, Object o, boolean selected) {
            if(o instanceof CalibrationAdjustment){
                CalibrationAdjustment ca = (CalibrationAdjustment) o;
                setEnabled(ca.valid);
            }

            return this;
        }

        public void initialize(AWTEvent ev, JCCellInfo info, Object o) {
            setEnabled(info.isEditable());
            if (isEnabled()) {
                if(o instanceof CalibrationAdjustment){
                ca = (CalibrationAdjustment) o;
                setEnabled(ca.valid);
            }
                doClick(100);
            }
        }

        public Component getComponent() {
            return this;
        }

        public Object getCellEditorValue() {
            return null;
        }

        public boolean stopCellEditing() {
            return true;
        }

        public boolean isModified() {
            return false;
        }

        public void cancelCellEditing() {
        }

        public JCKeyModifier[] getReservedKeys() {
            return null;
        }

        public void addCellEditorListener(JCCellEditorListener l) {
            c_support.addCellEditorListener(l);
        }

        public void removeCellEditorListener(JCCellEditorListener l) {
            c_support.removeCellEditorListener(l);
        }

        public void actionPerformed(ActionEvent e) {
            WepsFileChooser wfc = new WepsFileChooser(WepsFileChooser.CROP, c_cropDirPath, WepsFileChooser.SAVE);
            wfc.setAccessory(JP_cropNotes);
            File cropDir = new File(c_cropDirPath);
            File newCrop = new File(cropDir, ca.crop + "_CALIB");
            newCrop = Util.incrementFileName(newCrop, null, ".crop");
            CropObject crop = c_cropObjects.get(ca);
            JTA_cropNotes.setText(crop.getParameter("crop_notes").getValue().toString());
            wfc.setPersitSelectedFile(false);
            wfc.setCurrentDirectory(newCrop.getParentFile());
            wfc.setSelectedFile(newCrop);
            wfc.setPersitSelectedFile(true);
            int result = wfc.showDialog(CalFactorDialog.this);
            if (result == wfc.APPROVE_OPTION) {
                crop.getParameter("crop_notes").setValue(JTA_cropNotes.getText());
                newCrop = new File(wfc.getSelectedFile());
                crop.writeXMLFile(newCrop.getAbsolutePath());
                return;
            }
        }
    }
}
    
    

