/* Title:		OperationDlg.java
 * Version	
 * Author		Sada
 * Company: USDA-ARS
 * Date:    July, 2003
 * Description: OperationDlg screen displays the values of all parameters of the selected operation.
 * Paramter values can also be modified from here. Also, modified values can be saved as a new operation.
 * 
 */
package usda.weru.mcrew;

import com.klg.jclass.cell.JCCellInfo;
import java.awt.*;
import java.awt.event.*;
import de.schlichtherle.truezip.file.TFile;
import javax.swing.*;
import java.util.*;

import com.klg.jclass.cell.editors.*;
import com.klg.jclass.cell.renderers.*;
import com.klg.jclass.table.*;
import com.klg.jclass.table.data.*;
import javax.help.CSH;
import javax.help.HelpBroker;
import javax.help.HelpSet;

import usda.weru.util.*;
import usda.weru.weps.fuel.FuelChooser;

/**
 * OperationDlg screen displays the values of all parameters of the selected operation.
 * Paramter values can also be modified from here. Also, modified values can be saved as
 * a new operation.
 */
public class OperationDlg extends usda.weru.mcrew.gui.OperationDlg_n {

    private static final long serialVersionUID = 1L;

    static final int MIN_WIDTH = 820;
    static final int MIN_HEIGHT = 600;
    int sideOffset = 10;
    int componentOffSet = 5;
    Hashtable<String, String> c_tooltipTable;
    private JList<Identity> mProcessGroupList;
    private ArrayList<Identity> outTab;
    //DefaultListModel mNameListModel;
    // myListModel mIdListModel;
    //DefaultListModel mIdListModel; // even though (presently) only action names are put in the JList, the corresponding 
    myListModel<Identity> mIdListModel; // even though (presently) only action names are put in the JList, the corresponding 
    // identities are stored in mIdListModel for faster access to the appropriate actions.
    Vector<Action> mActions;
    int mSelectedIndex, mAdditionalIndex, listOffsetIndex;
    Identity mSelectedIdentity, mAdditionalIdentity;
    OperationObject mOprnObj; // holds a copy (clone) of Operation Object passed to the constructor4
    private OperationMeta mOprnMeta;
    OperationObject mOriginalOprn; // Holds the operation object passed. This is updated only if user clicks OK.
    String mOperationActionName;
    ActionJCTable mOperationTable, mMiddleTable, mLowerTable;
    /**
     * Variables to store whether the Drill down can save, and offending cells
     */
    private InputLimits.TableStatus allowSave = InputLimits.TableStatus.OKAY;
    ArrayList<Integer> outHard = new ArrayList<Integer>();
    ArrayList<Integer> outSoft = new ArrayList<Integer>();
    //An array list of parameter names corresponding to outTab, for stacking outlimits.
    ArrayList<String> outTabName = new ArrayList<String>();
    
    private Table origin; //This is just so we can activate checkData upon exit.
    
    /* The mOperationTable is fixed i.e. it always shows the operation parameter and is placed in the UpperPanel. */
    /**
     * This is the default group that is selected when the operation dialog screen appears.
     */
    public static final int kDefaultSelection = 0;
    /**
     * The foreground color of the text in each of the cells in operaation dialog tables.
     */
//    public static Color SelectedForegroundColor = Color.black;
    /**
     * The 
     */
//    public static Color SecondaryForegroundColor = Color.black;
    /**
     * The background color that shows selected rows in the tables and the process
     * list in the text area of an operation dialog.
     */
//    public static Color SelectedBackgroundColor = Color.blue;
    /**
     * The background color that shows selected group for a process in the text area
     * of an operation dialog.
     */
//    public static Color SecondaryBackgroundColor = Color.lightGray;
    /**
     * The foreground color of the text in each of the cells in operaation dialog tables.
     */
//    public static Color ForegroundColor = Color.black;
    /**
     * The background color of the cells in which the text is to be entered in various 
     * rows of the operation dialog table.
     */
//    public static Color BackGroundColor = Color.white;
    /**
     * String that separates the process or group Id from the actual value that is 
     * visible in the text area of the operation dialog.
     */
    public static final String sIdNameSeparator = ":";
    /**
     * String that indicates if there are no actions available.
     */
    public static final String sNoAction = "No Action";
    /**
     * String that shows the parameters that are associated with a group.
     */
    public static final String sGroupParameters = "Groups Parameters  ";
    /**
     * String that shows the parameters that are associated with a process.
     */
    public static final String sProcessParameters = "Process Parameters  ";
    /**
     * The parameters that are used for selecting the objects to be viewed in bottom 
     * panel i:e the process panel
     */
    public static final String sSelectionParameters = "Selection Parameters  ";
    /**
     * Indicates whether the data in any of the three tables of operation panels
     * has been changed. Set to true if changed else false.
     */
    protected boolean dataChanged = false;
    /**
     * Flag that indicates if the data in the notes of the Operation Drill Down Screen was
     * changed which helps in saving the values in the underlying datastructure - neha
     */
    protected boolean notesDataChanged = false;
    ManageData c_manage;
    RowInfo c_row;

    /**
     * Three argument constructor that needs the pointer to a frame in which it is
     * to be displayed, the operation object that hold the operation data together,
     * and the date string.
     * @param tab: table origin.
     *      also derives the frame object in which the GUI is displayed.
     * @param pOprnObj The operation object that holds all the information to be
     * displayed in the operation dialog GUI.
     * @param pDate The date string to be set for the datefield.
     * @param manage
     * @param row
     */
    public OperationDlg(Table tab, OperationObject pOprnObj, String pDate, ManageData manage, RowInfo row) {
        super(Util.getParentJFrame(tab));
        origin = tab;
        outTab = new ArrayList<Identity>();
        c_manage = manage;
        c_row = row;
        //mNameListModel = new DefaultListModel();
        mOriginalOprn = pOprnObj;
//		mOprnObj = (OperationObject)mOriginalOprn.clone();
        mOprnObj = mOriginalOprn;

        //  mIdListModel = new DefaultListModel(); // identities are converted to Actionnames in cellRenderer() functions
        mIdListModel = new myListModel<Identity>();
        JTF_operationName.setText(pOprnObj.getOperationName());
        JTF_date.setText(pDate);

        mOperationTable = new ActionJCTable(this);
        mMiddleTable = new ActionJCTable(this);
        mLowerTable = new ActionJCTable(this);

        //Intialize these booleans to false. Since they are static variables
        //their values will persist between different instantiations of OperationDlg
        //till Weps is closed - neha
        dataChanged = false;
        notesDataChanged = false;

        initialize();
  
        mProcessGroupList = new JList<>(mIdListModel);
        mProcessGroupList.setSelectedIndex(kDefaultSelection);
        mSelectedIndex = kDefaultSelection;
        if (mIdListModel.get(mSelectedIndex) != null) {
            mSelectedIdentity = mIdListModel.get(mSelectedIndex); // set 0th item as default selected

            setAllSelections();
            mProcessGroupList.addMouseListener(new ListMouseAdapter());
            mProcessGroupList.setCellRenderer(new CustomCellRenderer());
        }
        JSP_list.getViewport().setView(mProcessGroupList);

        //OperationParamPanel.add(mOperationTable);
        JSP_upperParam.getViewport().setView(mOperationTable);
        JSP_middleParam.getViewport().setView(mMiddleTable);
        JSP_lowerParam.getViewport().setView(mLowerTable);
        showTables();
        Util.loadToolTips((Container) this, new TFile("mcrew_cfg", "mcrewtooltips.cfg"));
        //setSize(700,500);
        //pack();
        //Set the tool tip help to be taken from this file
        // Util.loadToolTips((Container) this, new File("mcrew_cfg", "mcrewtooltips.cfg"));
    }
    
    /**
     * This method initialises the operation table data with the meta data that is 
     * associated with identities as keys to the respective objects e:g Action objects 
     * or datastructures that hold these objects.
     */
    public void initialize() {
        int ListModelIndex = 0;

        mActions = mOprnObj.getAllActions();
        Vector<Identity> mActionIdVec = mOprnObj.getAllIds();

        for (int i = 0; i < mActionIdVec.size(); i++) {

            Identity identity = mActionIdVec.get(i);
            Action action = mActions.get(i);
            if (action.isOperation()) {
                mOperationTable.setData(action);

                mOperationActionName = identity.toString() + sIdNameSeparator + action.getActionName();
                JL_OperationAction.setText(mOperationActionName);
                listOffsetIndex++;  // Operation action not added to display list, so increment offset counter

                continue; // Theres no need to add Operation action into ProcessGroup action JList
            }

            //mNameListModel.add(ListModelIndex, actionName + "("+ identity.toString() + ")");
            mIdListModel.add(ListModelIndex, identity);
            ListModelIndex++;
        }

        c_tooltipTable = Util.loadToolTipsTable(new TFile("mcrew_cfg", "mcrewtooltips.cfg"));

        addHelp();
        
            
        
        

    }

    
    
    /**
     * This method checks the new data to be put in, indicates a change of cell
     * color if necessary.
     * 
     * For initialization.
     * @param row
     * @param catParams
     * @return 
     */
    private InputLimits.TableStatus checkDataInit(int row, Vector<String> catParams)
    {
        String paramName = catParams.get(row);
        for(Action token : mOprnObj.getAllActions())
        {
            try
            {
                String value = token.getValue(paramName);
                ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(token.getIdentity());
                ParameterMeta limits = actionMeta.getParameterMeta(paramName);
                if(limits.getGroupAttribute(paramName, XMLConstants.svalueattribute).
                        equals(XMLConstants.schoice)) return InputLimits.TableStatus.CHOICE;
                if(limits.getGroupAttribute(paramName, XMLConstants.svalueattribute).
                        equals(XMLConstants.smultiline)) return InputLimits.TableStatus.CHOICE;
                if(token.getIdentity().equals(new Identity(51, "P")))
                {
                    //We only want to try and bound an item if it is listed under decomp parms
                    if(mOprnObj.getCrop().getParameter("idc") != null)
                    {   
                        if(mOprnObj.getCrop().getParameter("idc").getValue().equals("0") 
                                && !mOprnObj.getCrop().mCropMeta.getDecompNames().contains(paramName))
                            return InputLimits.TableStatus.OKAY;
                    }
                }
                InputLimits limiter = limits.getLimits();
                //If the display is in English Units, we want to convert it to metric for the tests.
                if(MCREWConfig.getDisplayUnit() == 1) value = limits.convertToPrimaryUnits(value);
                InputLimits.TableStatus currentCellStatus = limiter.evaluateInput(value);
                setOutTab(currentCellStatus, token, paramName);
                return currentCellStatus;
            }
            catch(NullPointerException incorectAction){}
        }
        return InputLimits.TableStatus.OKAY;
    }
    
    /**
     * This method checks the new data to be placed in a cell, indicates a change of cell
     * color if necessary.
     * 
     * For later changes.
     * @param value
     * @param catParams
     * @return 
     */
    private InputLimits.TableStatus checkDataCell(String value, String paramName)
    {
        for(Action token : mOprnObj.getAllActions())
        {
            try
            {
                if(value == null) return InputLimits.TableStatus.OKAY;
                String text = value;
                ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(token.getIdentity());
                ParameterMeta limits = actionMeta.getParameterMeta(paramName);
                if(limits.getGroupAttribute(paramName, XMLConstants.svalueattribute).
                        equals(XMLConstants.schoice)) return InputLimits.TableStatus.CHOICE;
                if(limits.getGroupAttribute(paramName, XMLConstants.svalueattribute).
                        equals(XMLConstants.smultiline)) return InputLimits.TableStatus.CHOICE;
                if(token.getIdentity().equals(new Identity(51, "P")))
                {
                    //We only want to try and bound an item if it is listed under decomp parms
                    if(mOprnObj.getCrop().getParameter("idc") != null)
                    {
                        if(mOprnObj.getCrop().getParameter("idc").getValue().equals("0") 
                                && !mOprnObj.getCrop().mCropMeta.getDecompNames().contains(paramName))
                            return InputLimits.TableStatus.OKAY;
                    }
                }
                InputLimits limiter = limits.getLimits();
                //If the display is in English Units, we want to convert it to metric for the tests.
                if(MCREWConfig.getDisplayUnit() == 1) text = limits.convertToPrimaryUnits(value);
                InputLimits.TableStatus currentCellStatus = limiter.evaluateInput(text);
                setOutTab(currentCellStatus, token, paramName);
                return currentCellStatus;
            }
            catch(NullPointerException incorectAction){}
        }
        return null;
    }
    
    /**
     * Set Tabs during initialization
     */
    private void checkTabInit()
    {
        for(Action token : mOprnObj.getAllActions())
        {
            for(String name : token.mParameterNames)
            {
                Parameter current = token.getParameter(name);
                Hashtable<String, String> between = current.mParameter;
                String value = between.get("value"); 
                ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.
                        soperation).getActionMeta(token.getIdentity());
                ParameterMeta limits = actionMeta.getParameterMeta(name);
                InputLimits limiter = limits.getLimits();
                //If the display is in English Units, we want to convert it to metric for the tests.
                if(MCREWConfig.getDisplayUnit() == 1) value = limits.convertToPrimaryUnits(value);
                InputLimits.TableStatus check = limiter.evaluateInput(value);
                setOutTab(check, token, name);
            }
        }
    }
    
    /**
     * Sets the cell status of a tab, which indicates an action that contributes to the
     * operation.  
     * @param status
     * @param token
     * @param check 
     */
    private void setOutTab(InputLimits.TableStatus status, Action token, String check)
    {
        Identity id = token.getIdentity();
        if(status == null) return;
        switch(status)
        {
            case WARNSAVE:
                if(outTabName.contains(check))
                {
                    outTab.remove(id);
                    outTabName.remove(check);
                }
                break;
            case NOSAVE:
                if(!outTabName.contains(check))
                {
                    outTab.add(id);
                    outTabName.add(check);
                }
                break;
            case CHOICE:
                break;
            case OKAY:
                if(outTabName.contains(check))
                {
                    outTab.remove(id);
                    outTabName.remove(check);
                }
                break;
            default:
        }
    }
    
    /**
     * Adds help, generic.
     */
    private void addHelp() {
        addCSH(Help.getHelpSet());
    } //end of addhelp()

    /**
     * Adds help based on the HelpSet Parameter inputted.
     * @param hs 
     */
    private void addCSH(HelpSet hs) {
        HelpBroker hb = hs.createHelpBroker();

        hb.enableHelpKey(getRootPane(), "operation_intro_html", hs);

        JB_help.addActionListener(new CSH.DisplayHelpAfterTracking(hs, "javax.help.Popup", null));

        //Add help ids to the components
        //CSH.setHelpIDString(JTP_main, "crop_drill_table_html");
        CSH.setHelpIDString(JTF_operationName, "operation_drill_operationname_html");
        CSH.setHelpIDString(operationNameLabel, "operation_drill_operationname_html");
        CSH.setHelpIDString(JP_toolbar, "operation_drill_toolbar_html");
        CSH.setHelpIDString(JP_upper, "operation_drill_operationparameters_html");
        CSH.setHelpIDString(JP_middle, "operation_drill_groupparameters_html");
        CSH.setHelpIDString(JP_lower, "operation_drill_processparameters_html");
        CSH.setHelpIDString(JTF_date, "operation_drill_date_html");
        CSH.setHelpIDString(JL_Date, "operation_drill_date_html");
        CSH.setHelpIDString(JLabel1, "operation_drill_list_html");
        CSH.setHelpIDString(JSP_list, "operation_drill_list_html");

        CSH.setHelpIDString(JB_cancel, "operation_toolbar_cancel_html");
        CSH.setHelpIDString(JB_saveAs, "operation_toolbar_save_html");
        CSH.setHelpIDString(JB_help, "operation_toolbar_help_html");
        CSH.setHelpIDString(JB_close, "operation_toolbar_return_html");

    }//end of addCSH

    /** If a process is selected, then this function finds the group to which
     * this program belongs to. It then sets both of them as selectedIndices.
     */
    public void setAllSelections() {
        int selections[] = new int[2]; //1- space for Selected and other for secondary identity index;

        mAdditionalIdentity = null;
        ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(mSelectedIdentity);
        if (actionMeta == null) {
            return;
        }
        Vector<Identity> groupId = actionMeta.getGroupId(); // Get the groups, this proces (if it is a processs) belongs to.

        // If selected item on is not a process, then getGroupId() returns null;
        int arrayLength = 0;
        Identity groupIdValue[] = {null, null, null, null, null, null, null, null};
        //groupIdValue.

        if (groupId != null) {
            //Highlight (grey) the first group this process belongs to
            arrayLength = groupId.size();

            for (int i = 0; i < arrayLength; i++) {
                groupIdValue[i] = groupId.get(i);
                //Identity groupIdValue = (Identity)groupId.get(0);
            }

            //Start from the currently selected index - 1 and work up the model until an applicable group is found
            for (int listItem = mSelectedIndex - 1; listItem >= 0 && mAdditionalIdentity == null; listItem--) {
                //Loop over each index of groups applicable to this process
                for (int j = 0; j < groupId.size(); j++) {
                    if (groupIdValue[j].equals(mIdListModel.get(listItem))) {
                        mAdditionalIndex = listItem;
                        mAdditionalIdentity = mIdListModel.get(listItem);
                        break;
                    }
                }
            }

            if (mAdditionalIdentity != null) {
                selections[0] = mSelectedIndex;
                selections[1] = mAdditionalIndex;

                mProcessGroupList.setSelectedIndices(selections);
            }
        }
        return;
    }

    /**
     * Basically this method display the tables in the operation dialog screen based on a
     * particular selection criteria. If a process is selectied, then the second table
     * (SelectionTable) displays the parameters of the group of the process. Third table
     * (AdditionalTable) displays the process' parameers. If the process is not associated
     * with any group, then the process' parameters are displayed in the second table
     * i.e. SelectionTable itself. When a group is directly selected from the list, then
     * the groups' parameters are displayed in SelectionTable.
     */
    public void showTables() {
        mLowerTable.clear();
        mMiddleTable.clear();

        JL_middlePanel.setText(sNoAction);
        JL_lowerPanel.setText(sNoAction);

        /* mSelectedIdentity always consists of the main selected one */
        if (mAdditionalIdentity != null) // this means a process is selected and it has a group. Group parameter 
        // values are displayed in the middle table.
        {
            Action action = mOprnObj.getAction(mAdditionalIndex + listOffsetIndex);
            mMiddleTable.setData(action);
            // mAdditionalTable.setData(action);
            JL_middlePanel.setText(sGroupParameters + mAdditionalIdentity.toString()
                    + sIdNameSeparator + action.getActionName());
            // AdditionalActionLabel.setText(mAdditionalIdentity.toString() + sIdNameSeparator + action.getActionName());

            action = mOprnObj.getAction(mSelectedIndex + listOffsetIndex);
            mLowerTable.setData(action);
            JL_lowerPanel.setText(sProcessParameters + mSelectedIdentity.toString() + sIdNameSeparator + action.getActionName());

        } else {
            if (mSelectedIdentity != null) {
                Action action = mOprnObj.getAction(mSelectedIndex + listOffsetIndex);
                mMiddleTable.setData(action);

                JL_middlePanel.setText(sSelectionParameters + mSelectedIdentity.toString()
                        + sIdNameSeparator + action.getActionName());
                //SelectionActionLabel.setText(mSelectedIdentity.toString() + sIdNameSeparator + action.getActionName());
            }
        }

        invalidate();
        repaint();
    }

    /**
     * This method is onvoked when the operation drilldown screen is closed.
     */
    @Override
    public void closeWindow_actionPerformed(java.awt.event.WindowEvent evt) {
        //Actual Implementation in the classes that inherit this class
        closeWindow();
        origin.checkData();
    }

    /**
     * Closes the window.  Fallthrough is intentional, as it removes the need for
     * replicated code.
     */
    @SuppressWarnings("fallthrough")
    public void closeWindow() {
        //Make sure every table's edits are committed.
        mOperationTable.commitEdit(true);
        mMiddleTable.commitEdit(true);
        mLowerTable.commitEdit(true);

        int option = -200;
        //System.out.println("OperationDlg : closeWindow:dataChanged:"+dataChanged+"  notesDataChanged:"+notesDataChanged);

        if (dataChanged == true || notesDataChanged == true) {
            option = JOptionPane.showConfirmDialog(this, "Save changes made to the current Operation Info? ");
            //System.out.println("OperationDlg : closeWindow -- OPTION is : " + option );
            switch (option) {
                case JOptionPane.CANCEL_OPTION:
                    break;
                case JOptionPane.YES_OPTION:
                    
                switch(allowSave)
                {
                    case NOSAVE:
                        JOptionPane.showMessageDialog(null, "Unable to save:\nSome data out of limits.",
                        mOprnObj.getOperationName(), JOptionPane.INFORMATION_MESSAGE);
        //                scrollToTab();
                        return;
                    case WARNSAVE:
                        JOptionPane.showMessageDialog(null, "Warning:\nSome data out of recommended limits.",
                        mOprnObj.getOperationName(), JOptionPane.INFORMATION_MESSAGE);
                    default:
                        mOperationTable.saveDataSource();
                        mMiddleTable.saveDataSource(); //i.e transfer the new data from mVDataSource to Action object (mAction)
                        mLowerTable.saveDataSource();
                        mOriginalOprn = mOprnObj;
                        c_manage.fireRowChanged(c_row);
                }
                    break;
                case JOptionPane.NO_OPTION:
                    break;
            }
        }

        //If neither Cancel nor close option was selected, then close the window
        if (option != JOptionPane.CANCEL_OPTION && option != JOptionPane.CLOSED_OPTION) {
            this.setVisible(false);
            dispose();
        }

    }

    @Override
    public void JBClose_actionPerformed(java.awt.event.ActionEvent event) {
        //Save any final changes made
        closeWindow();
    }

    @Override
    public void CancelButton_actionPerformed(java.awt.event.ActionEvent event) {
        this.setVisible(false);
        dispose();

    }

    @Override
    @SuppressWarnings("fallthrough")
    public void SaveAsButton_actionPerformed(java.awt.event.ActionEvent event) {
        switch(allowSave)
        {
            case NOSAVE:
                JOptionPane.showMessageDialog(null, "Unable to save:\nSome data out of limits.",
                mOprnObj.getOperationName(), JOptionPane.INFORMATION_MESSAGE);
//                scrollToTab();
                break;
            case WARNSAVE:
                JOptionPane.showMessageDialog(null, "Warning:\nSome data out of recommended limits.",
                mOprnObj.getOperationName(), JOptionPane.INFORMATION_MESSAGE);
            default:
                int option = -200;
                String options[] = {"<html>Save with current<br>crop/residue</html>",
                    "<html>Save with no<br>crop/residue</html>"
                };
                // If the operation has a crop then ask if he wants to save the 
                // operation with the crop or without the crop - Neha.
                if (mOprnObj.hasCrop()) {
                    option = JOptionPane.showOptionDialog(this, "Select an Option", "Select Save Option",
                            JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, null);
                }

                //System.out.println("OperationDlg-SaveAs-option value:"+option);
                if (option == JOptionPane.CLOSED_OPTION) {
                    return;
                }
                //Save any final changes made
                mOperationTable.saveDataSource();
                mMiddleTable.saveDataSource(); //i.e transfer the new data from mVDataSource to Action object (mAction)
                mLowerTable.saveDataSource();

                TFile oprnDir = new TFile(MCREWConfig.getDirectoryName(XMLConstants.soperation));
                String oprnDirPath = oprnDir.getAbsolutePath();
                WepsFileChooser mfc = new WepsFileChooser(WepsFileChooser.Filetype.OPERATION, oprnDirPath,
                        WepsFileChooser.SAVE);
                //set the tooltip of "home" button to "Home" instead of "Desktop"
                mfc.homeToolTip(mfc);

                mfc.setCurrentDirectory(oprnDir); //new de.schlichtherle.truezip.file.File(ConfigData.INITIAL_DIR));
                //Set the title of the file chooser dialog appropriately acc to the option - Neha
                if (option == 0) {
                    mfc.setDialogTitle("Save a new Operation (with " + mOprnObj.getCropName() + ")");
                } else {
                    if (option == 1) {
                        mfc.setDialogTitle("Save a new Operation (with no crop)");
                    }
                }
                if (mfc.showDialog(this) != JFileChooser.APPROVE_OPTION) {
                    return;
                }

                String newFileName = null;
                try {
                    newFileName = mfc.getSelectedFile().getCanonicalPath();
                } catch (java.io.IOException e) {
                    System.err.println("OprnDlg:Save As(): error " + e);
                    return;
                }
                if (!newFileName.endsWith(".oprn")) {
                    newFileName = newFileName + ".oprn";
                }
                if (option == 0) {
                    //save with current crop/residue selected
                    mOprnObj.writeXMLFile(newFileName, true, true);
                } else {
                    if (option == 1) {
                        //save with no crop/residue
                        mOprnObj.writeXMLFile(newFileName, true, false);
                    } else {
                        //save the operation that does not have any crop
                        mOprnObj.writeXMLFile(newFileName, false, false);
                    }
                }
                MCREWConfig.getOpFileList().refreshFiles();
        }

    }

    /**
     * This method adjust the components in the operation dialog so that the adjoining 
     * components are spaced uniformly w.r.t each other when a window or frame is 
     * resized.
     * @param evt The resize event that occurs on the window.
     */
    @Override
    public void OperationDlgN_componentResized(java.awt.event.ComponentEvent evt) {
        validate();
        Dimension size = evt.getComponent().getSize();

        if (size.getHeight() < MIN_HEIGHT) {
            size.height = MIN_HEIGHT;
        }
        if (size.getWidth() < MIN_WIDTH) {
            size.width = MIN_WIDTH;
        }

        this.setSize(size);
        size.height -= 50;
        size.width -= 30;
        JP_main.setSize(size);

        JP_toolbar.setSize(JP_main.getWidth() - sideOffset, 40);
        JP_toolbar.setLocation(componentOffSet, componentOffSet);

        JP_operationName.setSize(JP_main.getWidth() - sideOffset, 30);
        JP_operationName.setLocation(componentOffSet, (JP_toolbar.getHeight() + (2 * componentOffSet)));

        size.height -= (JP_operationName.getHeight() + JP_toolbar.getHeight() + (5 * componentOffSet));
        int yLocation = (JP_operationName.getHeight() + JP_toolbar.getHeight() + (3 * componentOffSet));

        JP_operDetails.setSize((((int) size.getWidth() / 3) - sideOffset), (int) size.getHeight());
        JP_operDetails.setLocation(sideOffset, yLocation);

        JSP_list.setSize((JP_operDetails.getWidth() - sideOffset), (JP_operDetails.getHeight()
                - (JL_Date.getHeight() + JLabel1.getHeight() + 5 * componentOffSet)));
        JSP_list.setLocation(componentOffSet, (JL_Date.getHeight() + JLabel1.getHeight() + 4 * componentOffSet));

        JP_upper.setSize(((((int) size.getWidth() * 2) / 3) - (2 * sideOffset)),
                (JP_operDetails.getHeight() / 3 - (3 * componentOffSet)));
        JP_upper.setLocation((JP_operDetails.getWidth() + 2 * sideOffset), yLocation);
        JSP_upperParam.setSize((JP_upper.getWidth() - sideOffset), (JP_upper.getHeight()
                - (JP_upperParams.getHeight() + componentOffSet)));

        JP_middle.setSize(JP_upper.getWidth(), JP_upper.getHeight());
        JP_middle.setLocation((JP_operDetails.getWidth() + 2 * sideOffset),
                (yLocation + JP_upper.getHeight() + componentOffSet));
        JSP_middleParam.setSize((JP_middle.getWidth() - sideOffset),
                (JP_middle.getHeight() - (JP_middleParam.getHeight() + 2 * componentOffSet)));

        JP_lower.setSize(JP_upper.getWidth(), JP_upper.getHeight());
        JP_lower.setLocation((JP_operDetails.getWidth() + 2 * sideOffset),
                (yLocation + 2 * (JP_upper.getHeight() + componentOffSet)));
        JSP_lowerParam.setSize((JP_lower.getWidth() - sideOffset),
                (JP_lower.getHeight() - (JP_lowerParam.getHeight() + 2 * componentOffSet)));

        validate();
        repaint();

    }

    class CustomCellRenderer extends JLabel implements ListCellRenderer<Identity> {

        private static final long serialVersionUID = 1L;

        /**
         * 
         * @param list
         * @param value identity value from which Actionname is to be displayed
         * @param index cell index
         * @param isSelected is the cell selected
         * @param cellHasFocus the list and the cell have the focus
         */
        @Override
        public Component getListCellRendererComponent(
                JList<? extends Identity> list,
                Identity value,
                int index,
                boolean isSelected,
                boolean cellHasFocus) {
            String actionName = "";
            ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(value);
            if (actionMeta != null) {
                actionName = actionMeta.getActionName();
            }

            setText(value + sIdNameSeparator + actionName);

            
            if(outTab.contains(value))
            {
                setBackground(Color.MAGENTA);
                setForeground(list.getForeground());
            }
            else
            {
                if (isSelected) {
                if ((value).equals(mSelectedIdentity)) {
                    setBackground(list.getSelectionBackground());
                    setForeground(list.getSelectionForeground());
                } else {
                    setBackground(Color.lightGray);
                    setForeground(list.getForeground());
                }
            } else {
                setBackground(list.getBackground());
                setForeground(list.getForeground());
            }
            }
            setEnabled(list.isEnabled());
            setFont(list.getFont());
            setOpaque(true);
            return this;
        }
    }

    class ListMouseAdapter extends MouseAdapter {

        @Override
        public void mouseClicked(MouseEvent e) {
            int SelectedIndex = mProcessGroupList.locationToIndex(e.getPoint());
            if ((SelectedIndex >= mIdListModel.getSize()) || (SelectedIndex < 0)) {
                return;
            }
            mSelectedIndex = SelectedIndex;
            mSelectedIdentity = mIdListModel.get(mSelectedIndex);
            setAllSelections();
            // Now before changing the data, the table values must be stored as the user might have changed the values.
            if (mMiddleTable.mDataChanged == true) {
                mMiddleTable.saveDataSource(); //i.e transfer the new data from mVDataSource to Action object (mAction)
            }

            if (mLowerTable.mDataChanged == true) {
                mLowerTable.saveDataSource();
            }

            showTables();
        }
    }

    static class ActionTableCSHManager implements CSH.Manager {

        private ActionJCTable c_table;

        public ActionTableCSHManager(ActionJCTable table) {
            c_table = table;
        }

        private void translateMouseEvent(MouseEvent me) {
            Object parent = me.getSource();
            Component comp = c_table;
            int x = 0;
            int y = 0;
            while (comp != parent) {
                x += comp.getX();
                y += comp.getY();
                comp = comp.getParent();
            }

            me.translatePoint(-x, -y);
        }

        @Override
        public String getHelpIDString(Object comp, AWTEvent evt) {
            if (comp != c_table) {
                return null;
            }
            try {
                if (evt instanceof MouseEvent) {
                    MouseEvent me = (MouseEvent) evt;
                    translateMouseEvent(me);
                    int row = c_table.YtoRow2(me.getY());

                    String paramName = c_table.parameterNames.elementAt(row);
                    return paramName + "_html";
                } else {
                    return null;
                }

            } catch (Exception e) {
                return null;
            }
        }

        @Override
        public HelpSet getHelpSet(java.lang.Object comp, java.awt.AWTEvent e) {
            return Help.getHelpSet();
        }
    }

    class ActionJCTable extends JCTable implements JCEditCellListener, MouseMotionListener {

        private static final long serialVersionUID = 1L;

        public int YtoRow2(int y) {
            return YtoRow(y);
        }
        public String mHeaderRow[] = {"Parameter", "Value", "Units"};
        int PROMPTCOLUMN = 0;
        int VALUECOLUMN = 1;
        int UNITSCOLUMN = 2;
        //This is used to check if theres a need for saving data from VDataSource to the action object
        boolean mDataChanged = false;
        JCEditableVectorDataSource mVDataSource;
        JCCellStyle mCellStyle, mUnHLimitCellStyle, mUnSLimitCellStyle, mValueCellStyle, mHLimitCellStyle, mSLimitCellStyle;
        Action mAction; // Specifies the action for which the data is being displyed
        JCStringCellEditor se;
        NotesOperation notes;
        OperationDlg parentDlg;

        public ActionJCTable(OperationDlg parentDlg) {
            this();
            this.parentDlg = parentDlg;
            CSH.addManager(new ActionTableCSHManager(this));
        }

        public ActionJCTable() {
            mVDataSource = new JCEditableVectorDataSource();
            setDataSource(mVDataSource);
            setTableLooks();
            mAction = null;

            addEditCellListener(this);
            addMouseMotionListener(this);

        }

        /************************************************************* neha */
        @Override
        public void mouseMoved(MouseEvent mouseEvent) {
            try {
                int row = YtoRow(mouseEvent.getY());
                String paramName = parameterNames.get(row);
                String tooltip = parentDlg.c_tooltipTable.get("OpnDrill:" + paramName);
                if (tooltip != null) {
                    setToolTipText("<html>" + tooltip + "</html>");
                } else {
                    setToolTipText("");
                }
            } catch (Exception e) {
            }
        }

        @Override
        public void mouseDragged(MouseEvent mouseEvent) {
            return;
        }

        @Override
        public void focusGained(FocusEvent ev) {
        }

        @Override
        public void focusLost(FocusEvent ev) {
            Component comp = ev.getOppositeComponent();
            //Click a button if the table loses focus to the button
            if (ev.getSource() instanceof JCTable) {
                if (comp != null && comp instanceof AbstractButton) {
                    //I don't know why, but if we don't test for the button, it clicks the save as button.
                    if (((AbstractButton) comp).getText().contains("Notes")) {
                        ((AbstractButton) comp).doClick();
                    }
                }
                //We don't want to commit unless we lose focus from a cell editor
                return;
            } else {
                if (ev.getSource() instanceof BaseCellEditor) {
                    //Don't commit combo boxes.  Their event code handles the commit
                    if (comp instanceof JComboBox) {
                        return;
                    } //Commit everything else
                    else {
                        this.commitEdit(true);
                        //System.out.println("editor Committed");
                    }
                    //If we lost focus to a button click it
                    if (comp != null && comp instanceof AbstractButton) {
                        ((AbstractButton) comp).doClick();
                    }
                }
            }
        }
        String beforeEditValue = "";
        String afterEditValue = "";

        @Override
        public void beforeEditCell(JCEditCellEvent ev) {
            // //System.out.println("beforeEditCell");
            int row = ev.getRow();
            int column = ev.getColumn();
            beforeEditValue = (String) this.getDataSource().getTableDataItem(row, column);
        }

        @Override
        public void editCell(JCEditCellEvent ev) {
            //  //System.out.println("EditCell");
        }

        @Override
        public void afterEditCell(JCEditCellEvent ev) {
            // //System.out.println("afterEditCell");
            int row = ev.getRow();
            int column = ev.getColumn();
            String paramName = getParamName(row);
            
            afterEditValue = (String) this.getDataSource().getTableDataItem(row, column);
            if (beforeEditValue != null && afterEditValue != null) {
                //System.out.print("OperationDlg : afterEditCell():Before Edit: "+beforeEditValue+"  after Edit: "+afterEditValue);
                //If there is a change in the value of the cell after the edit, then ask the user
                // if he needs to save the change - Neha
                if (beforeEditValue.equals(afterEditValue) == false) {
                    //System.out.println("Before Edit value and after edit value are NOT same");
                    mDataChanged = true;
                    dataChanged = true;
                }
            }
            
            InputLimits.TableStatus check = checkDataCell(afterEditValue, paramName);
            test(check, row);
        }

        /************************************************************* neha */
        private void setTableLooks() {
            setColumnLabelDisplay(true);
            setRowLabelDisplay(false);
            setDoubleBuffered(true);
            setAutoScroll(JCTableEnum.AUTO_SCROLL_BOTH);

            //setFocusIndicator(JCTableEnum.FOCUS_NONE);
            //setFrozenColumns(2); 
            setFrozenRows(1); // header line

            mCellStyle = (JCCellStyle) getDefaultCellStyle();
            mCellStyle.setCellBorder(new JCCellBorder(JCTableEnum.BORDER_OUT));
            mCellStyle.setEditable(false);
            mCellStyle.setBackground(Color.lightGray);

            mUnHLimitCellStyle = (JCCellStyle) getDefaultCellStyle().clone();
            mUnHLimitCellStyle.setBackground(Color.pink);
            mUnHLimitCellStyle.setEditable(false);
            
            mUnSLimitCellStyle = (JCCellStyle) getDefaultCellStyle().clone();
            mUnSLimitCellStyle.setBackground(Color.orange);
            mUnSLimitCellStyle.setEditable(false);

            mValueCellStyle = (JCCellStyle) getDefaultCellStyle().clone(); // for the column showing parameter values
            mValueCellStyle.setBackground(Color.white);
            mValueCellStyle.setEditable(true);
            
            mHLimitCellStyle = (JCCellStyle) getDefaultCellStyle().clone();
            mHLimitCellStyle.setBackground(Color.magenta);
            mHLimitCellStyle.setEditable(true);
            
            mSLimitCellStyle = (JCCellStyle) getDefaultCellStyle().clone();
            mSLimitCellStyle.setBackground(Color.yellow);
            mSLimitCellStyle.setEditable(true);
            
            setCellStyle(JCTableEnum.ALLCELLS, VALUECOLUMN, mValueCellStyle);

            if (se == null) {
                se = new JCStringCellEditor() {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public void initialize(AWTEvent ev, JCCellInfo info, Object o) {
                        super.initialize(ev, info, o);

                        SwingUtilities.invokeLater(new Runnable() {

                            @Override
                            public void run() {
                                requestFocusInWindow();
                                selectAll();
                            }
                        });
                    }
                };
                se.addFocusListener(this);
            }

            //set the cell editor for all the editable cells - neha
            mValueCellStyle.setCellEditor(se);
            se.addFocusListener(this);

            CellStyleModel labelStyleModel = getDefaultLabelStyle();
            labelStyleModel.setFont(new Font("Dialog", Font.BOLD, 12));
            labelStyleModel.setCellBorderSides(JCTableEnum.BORDERSIDE_ALL);
            //setCellStyle(-1, JCTableEnum.ALLCELLS, headerStyleModel);

            setMinWidth(JCTableEnum.ALL, 150);	// default width
            setMinWidth(0, 250);					// make param prompt wider
            setMinWidth(2, 100);
            setFocusColor(Color.red);


            /* // Not sure why setting editor and renderer this way is not working
             try{	
             setCellEditor(Class.forName("javax.swing.JComboBox"), 
             Class.forName("com.klg.jclass.cell.editors.JCComboBoxCellEditor")
             );
             setCellRenderer(Class.forName("javax.swing.JComboBox"), 
             Class.forName("com.klg.jclass.cell.renderers.JCComboBoxCellRenderer")
             );
             }catch(ClassNotFoundException e){
             System.err.println("OperationDlg:setTableLooks()"+ "Class not found exception");
             }
             */
            mVDataSource.setColumnLabels(mHeaderRow);
            mVDataSource.setNumColumns(mHeaderRow.length);
            mVDataSource.setNumRows(0);
        }

         private void test(InputLimits.TableStatus cellStatus, int row)
        {
            String paramName = getParamName(row);
            String displayAttribute = "";
            String valueAttribute = "";
            for(Action token : mOprnObj.getAllActions())
            {
                try
                {
                    ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(token.getIdentity());
                    ParameterMeta limits = actionMeta.getParameterMeta(paramName);
                    displayAttribute = limits.getGroupAttribute(token.getActionName(), XMLConstants.sdisplayattribute);
                    valueAttribute = limits.getGroupAttribute(token.getActionName(), XMLConstants.svalueattribute);
                }
                catch(NullPointerException incorectAction){}
            }
            if(!valueAttribute.equals("N")) return;
            switch(cellStatus)
            {
                case WARNSAVE:
                    setCellStyle(row, VALUECOLUMN, mSLimitCellStyle);
                    if(displayAttribute.equals("V")) setCellStyle(row, VALUECOLUMN, mUnSLimitCellStyle);
                    if(!outSoft.contains((Integer) row))
                    {
                        outSoft.add(row);
                        if(outHard.contains((Integer) row))
                        {
                            int toRemove = outHard.indexOf(row);
//                                    outTab.remove(toRemove);
                            outHard.remove(toRemove);
                            if(outHard.isEmpty())
                            {
                                allowSave = InputLimits.TableStatus.WARNSAVE;
                            }
                        }
                        if(allowSave == InputLimits.TableStatus.OKAY)
                        {
                            allowSave = InputLimits.TableStatus.WARNSAVE;
                        }
                        if(allowSave == InputLimits.TableStatus.NOSAVE
                                && outHard.isEmpty())
                        {
                            allowSave = InputLimits.TableStatus.WARNSAVE;
                        }
                    }
                    break;
                case NOSAVE:
                    setCellStyle(row, VALUECOLUMN, mHLimitCellStyle);
                    if(displayAttribute.equals("V")) setCellStyle(row, VALUECOLUMN, mUnHLimitCellStyle);
                    if(!outHard.contains((Integer) row))
                    {
                        outHard.add(row);
                        if(outSoft.contains((Integer) row))
                        {
                            int toRemove = outSoft.indexOf(row);
                            outSoft.remove(toRemove);
                        }
                        if(allowSave == InputLimits.TableStatus.OKAY ||
                                allowSave == InputLimits.TableStatus.WARNSAVE)
                        {
                            allowSave = InputLimits.TableStatus.NOSAVE;
                        }
                    }
                    break;
                case CHOICE:
                    break;
                default:
                    setCellStyle(row, VALUECOLUMN, mValueCellStyle);
                    if(displayAttribute.equals("V")) setCellStyle(row, VALUECOLUMN, mCellStyle);
                    if(outHard.contains((Integer) row))
                    {
                        int toRemove = outHard.indexOf(row);
//                                outTab.remove(toRemove);
                        outHard.remove(toRemove);
                    }
                    if(outSoft.contains((Integer) row)) 
                    {
                        int toRemove = outSoft.indexOf(row);
                        outSoft.remove(toRemove);
                    }
                    if(outHard.isEmpty() && outSoft.isEmpty())
                    {
                        allowSave = InputLimits.TableStatus.OKAY;
                    }
                    if(outHard.isEmpty() && !outSoft.isEmpty())
                    {
                        allowSave = InputLimits.TableStatus.WARNSAVE;
                    }
                    if(outSoft.isEmpty() && !outHard.isEmpty())
                    {
                        allowSave = InputLimits.TableStatus.NOSAVE;
                    }

                }
            if(!outHard.isEmpty() || !outTab.isEmpty()) allowSave = InputLimits.TableStatus.NOSAVE;
        }
        
        /* Clears the tabel data. On clearing all cells in a JCtable, the coloumn header disppears.
         * This functions just set the number of rows to 1 i.e makes an empty row so that column labels won't disappear.
         */
        public void clear() {
            mVDataSource.clearCells();
            mAction = null;
            mVDataSource.setNumRows(0);
        }
        protected Vector<String> parameterNames;
        
        public String getParamName(int row)
        {
            return parameterNames.get(row);
        }

        public void setData(Action pAction) {
            mAction = pAction;
            parameterNames = new Vector<String>(mAction.getParameterNames());
            int numParams = parameterNames.size();

            if (numParams == 0) {
                System.err.println("ParamterJCTable:setData(): " + "Action " + pAction.getIdentity() + " has no parameters");
                mVDataSource.clearCells();

                return;
            }

            ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(mAction.getIdentity());
            clearSelectedCells();
            //reset all data
            mVDataSource.clearCells();
            //reset all cell styles
            setCellStyle(JCTableEnum.ALLCELLS, JCTableEnum.ALLCELLS, mCellStyle);
            setCellStyle(JCTableEnum.ALLCELLS, VALUECOLUMN, mValueCellStyle);

            int row = 0, col = 0;

            for (int i = 0; i < parameterNames.size(); i++) {
                col = 0;
                String paramName = parameterNames.get(i);
                String paramValue;

                String paramPrompt = null;
                //String paramType = null;
                String displayAttribute = null;
                String valueAttribute = null;
                String format = null;
                //String units[] = new String[2];
                String units = null;
                Hashtable<String, String> paramChoices = null;

                ParameterMeta paramMeta = null;
                Parameter parameter = mAction.getParameter(paramName);

                //paramName = parameter.get(XMLConstants.sname);
                paramValue = parameter.get(XMLConstants.svalue);

                // Col 0 = param prompt, Col 1 = param value, Col 2 = param units
                if (actionMeta != null) {
                    paramMeta = actionMeta.getParameterMeta(paramName);
                    if (paramMeta != null) {
                        paramPrompt = paramMeta.getPrompt(); // actionMeta.getParamPrompt(paramName);
                        //paramType = paramMeta.getType(); // actionMeta.getParamType(paramName);

                        units = paramMeta.getUnit(MCREWConfig.getDisplayUnit());
                        if (units == null) {
                            units = paramMeta.getUnit(XMLConstants.kPrimaryUnit);
                        }
                        displayAttribute = paramMeta.getAttribute(XMLConstants.sdisplayattribute);
                        valueAttribute = paramMeta.getAttribute(XMLConstants.svalueattribute);
                        format = paramMeta.getAttribute(XMLConstants.sformat);

                        paramChoices = paramMeta.getChoices();
                    }
                }

                if (displayAttribute == null) /* For some reason, the attribute is not specifed in the file */ {
                    System.err.println("OperationDlg:setData(): " + "Theres no display attribute for parameter "
                            + paramName + " in the *.lang.xml file");
                    displayAttribute = XMLConstants.sViewable;
                } else {
                    if (displayAttribute.equals(XMLConstants.sHidden)) {
                        parameterNames.remove(paramName);
                        i --;
                        continue;
                    } /* Hidden parameters should not be displayed on the table */

                }

                if (valueAttribute == null) {
                    System.err.println("OperationDlg:setData(): " + "Theres no value attribute for parameter "
                            + paramName + " in the *.lang.xml file");
                    valueAttribute = XMLConstants.sint;
                }

                if ((paramPrompt == null) || (paramPrompt.length() == 0)) {
                    paramPrompt = paramName;
                }

                mVDataSource.setTableDataItem(paramPrompt, row, col++);

                /* If the parameter is choice list type, then instead of the actual value, 
                 * the various choices should go into the table.
                 */
                if (valueAttribute.equals(XMLConstants.schoice)) //(paramType.equals(XMLConstants.schoice)) )
                {
                    if (paramChoices == null) // due to reason such as parameter misspelled in lang file,...
                    {
                        System.err.println("OperationDlg:setData(); " + paramName + " has no Choices");
                        continue;
                    }

                    Enumeration<String> enumChoices = paramChoices.elements();

                    Vector<String> choiceList = new Vector<>();
                    while (enumChoices.hasMoreElements()) {
                        String choice = enumChoices.nextElement();
                        choiceList.add(choice);
                    }
                    Collections.sort(choiceList);

                    /* XXX - Not sure why this method of setting the combobox into the data source is NOT working*/
                    /*
                     choiceBox = new JComboBox(choiceList);
                     choiceBox.setSelectedItem(paramChoices.get(paramValue));
                     mVDataSource.setTableDataItem(choiceBox, row, col++);
                     //mVDataSource.setTableDataItem("HaHaHa", row, col++);
                     //System.out.println("Opr'nDlg:setData"+ "Setting data to comboBox");
                     */

                    /* XXX Temporary solution - as the above way of setting through combo box into the data source is not working
                     * In this solution, every cell has separate cell editor and cell renderer which is not a suggested way
                     */
                    JCComboBoxCellEditor comboEditor = new JCComboBoxCellEditor(choiceList.toArray());
                    JCComboBoxCellRenderer comboRenderer = new JCComboBoxCellRenderer(choiceList.toArray());
                    comboEditor.setSelectedItem(paramChoices.get(paramValue));
                    comboRenderer.setSelectedItem(paramChoices.get(paramValue));

                    JCCellStyle comboStyle = (JCCellStyle) mValueCellStyle.clone();
                    // JCCellStyle comboStyle = new JCCellStyle((JCCellStyle)getDefaultCellStyle().clone());
                    comboStyle.setCellEditor(comboEditor);
                    comboStyle.setCellRenderer(comboRenderer);
                    if ((displayAttribute != null) && (displayAttribute.equals(XMLConstants.sEditable))) {
                        comboStyle.setEditable(true);
                    } else {
                        comboStyle.setEditable(false);
                        comboStyle.setBackground(MCREWConfig.getDisabledColor());
                    }

                    setCellStyle(row, col, comboStyle);
                    @SuppressWarnings("rawtypes")
                    JComboBox comboBox = (JComboBox) ((comboStyle.getCellEditor()).getComponent());
                    comboBox.addItemListener(new ItemListener() {

                        @Override
                        public void itemStateChanged(ItemEvent ev) {
                            if (ev.getStateChange() == ItemEvent.SELECTED) {	////System.out.println("Item changed");
                                commitEdit(true);
                            }
                        }
                    });

                    mVDataSource.setTableDataItem(paramChoices.get((paramValue)), row, col++);
                    /* END TEMPORARY SOLUTION*/

                } else if (valueAttribute.equals(XMLConstants.smultiline)) {
                    //System.out.println("SetData:MultiLine Text attribute for NOTES");
                    notes = new NotesOperation("Operation File Notes", parentDlg, this, paramValue, row, col);

                    JCCellStyle buttonStyle = (JCCellStyle) mValueCellStyle.clone();
                    buttonStyle.setCellEditor(new CropDlg.ButtonEditor());

                    if ((displayAttribute != null) && (displayAttribute.equals(XMLConstants.sEditable))) {
                        buttonStyle.setEditable(true);
                    }

                    buttonStyle.setBackground(MCREWConfig.getDisabledColor());
                    buttonStyle.setForeground(Color.BLACK);
                    setCellStyle(row, col, buttonStyle);

                    JButton button = (JButton) ((buttonStyle.getCellEditor()).getComponent());
                    button.setSize(60, 8);
                    button.setPreferredSize(new Dimension(60, 8));
                    // button.setBackground(Color.RED);
                    button.setOpaque(true);

                    if (displayAttribute.equals(XMLConstants.sEditable)) {
                        button.setText("Edit Notes");
                        notes.setEditable(true);
                    } else {
                        button.setText("View Notes");
                        notes.setEditable(false);
                    }

                    buttonStyle.setCellRenderer(new CropDlg.ButtonRenderer(button.getText()));

                    button.addActionListener(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent ev) {
                            //System.out.println("setDataTab():Button pressed");
                            notesButton_clicked(ev);
                        }
                    });

                    mVDataSource.setTableDataItem(paramValue, row, col++);
                } else if (valueAttribute.equals(XMLConstants.sfuel)) {
                    FuelComboBoxEditor fuelEditor = new FuelComboBoxEditor();
                    FuelComboBoxRenderer fuelRenderer = new FuelComboBoxRenderer();

//                    fuelEditor.setSelectedItem(paramChoices.get(paramValue));
//                    fuelRenderer.setSelectedItem(paramChoices.get(paramValue));
                    JCCellStyle fuelStyle = (JCCellStyle) mValueCellStyle.clone();
                    // JCCellStyle comboStyle = new JCCellStyle((JCCellStyle)getDefaultCellStyle().clone());
                    fuelStyle.setCellEditor(fuelEditor);
                    fuelStyle.setCellRenderer(fuelRenderer);
                    if ((displayAttribute != null) && (displayAttribute.equals(XMLConstants.sEditable))) {
                        fuelStyle.setEditable(true);
                    } else {
                        fuelStyle.setEditable(false);
                        fuelStyle.setBackground(MCREWConfig.getDisabledColor());
                    }

                    setCellStyle(row, col, fuelStyle);
                    //set the value
                    mVDataSource.setTableDataItem(paramValue, row, col++);

                    final FuelChooser fuelChooser = (FuelChooser) ((fuelStyle.getCellEditor()).getComponent());
                    fuelChooser.addItemListener(new ItemListener() {

                        @Override
                        public void itemStateChanged(ItemEvent ev) {
                            if (ev.getStateChange() == ItemEvent.SELECTED) {	////System.out.println("Item changed");
                                commitEdit(true);
                            }
                        }
                    });
                } else {
                    if (displayAttribute.equals(XMLConstants.sViewable)) // Viewable attribute means not Editable
                    {
                        JCCellStyle style = (JCCellStyle) mValueCellStyle.clone();
                        style.setEditable(false);
                        style.setBackground(MCREWConfig.getDisabledColor());
                        setCellStyle(row, col, style);
                    }

                    if (format != null) {
                        JCCellStyle style = (JCCellStyle) getCellStyle(row, col);
                        setCellStyle(row, col, (JCCellStyle) style.clone());
                        getCellStyle(row, col).setCellRenderer(new MyFormattedCellRenderer(format));
                    }

                    // convert the value to alternate unit before displaying
                    if ((MCREWConfig.getDisplayUnit() == XMLConstants.kAlternateUnit) && (paramMeta != null)) {
                        paramValue = paramMeta.convertToAlternateUnits(paramValue);

                    }
                    mVDataSource.setTableDataItem(paramValue, row, col++);

                }

                mVDataSource.setTableDataItem(units, row, col++);
                InputLimits.TableStatus check = checkDataInit(row, parameterNames);
                test(check, row);
                //	mVDataSource.setTableDataItem(primaryUnit, row , col++);		
                row++;

            }

            /*
             if(numRows > 0)
             mVDataSource.setNumRows(numRows);
             else
             mVDataSource.setNumRows(1); //show atleast 1 row, else the headers disappear
             */
            mVDataSource.setNumRows(row);
            checkTabInit();

        }

        public void notesButton_clicked(java.awt.event.ActionEvent evt) {
            int row = getCurrentRow();
            int col = getCurrentColumn();
            String text = (String) getDataSource().getTableDataItem(row, col);
            notes.setText(text);
            if (notes.notesPresent == false) {
                notes.setVisible(true);
                notes.notesPresent = true;
            } else {
                if (notes.isActive() == false) {
                    notes.toFront();
                    notes.setVisible(true);
                    notes.requestFocus();
                }//end of else
            }
        }

        /* Saves the new values from the dataSource into the Action (mAction) object
         *
         */
        @SuppressWarnings("fallthrough")
        public void saveDataSource() {
            /* When the table data is commited, only the data in mVDataSource is saved. The data in the mAction object
             * isn't modified.
             * If a data values is being displayed and edited in alternate units,
             * then the value has to be converted to primary units 
             * before being saved.
             */
            if (mAction == null) {
                return;
            } // Theres no data in the table

            if (mDataChanged == false) // nothing to save
            {
                return;
            }

            dataChanged = true;
            mDataChanged = false; //reset the boolean varaible
            Vector<String> parameterNames = mAction.getParameterNames();
            int numParams = parameterNames.size();

            int row = 0; /* Note that row is != numParams as some prameters might be hidden */

            ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(mAction.getIdentity());

            // The table displays all the parameters from the this Action in the order obtained through the hashtable 
            //in setData()
            for (int i = 0; i < numParams; i++) {
                Parameter parameter = null;
                ParameterMeta paramMeta = null;

                String paramName = parameterNames.get(i);
                //System.out.println("OperationDlg : saveDataSource(): Parameter Name is :---" + paramName);
                //String paramType = null;
                //String primaryUnit = null;
                String displayAttribute = null;
                String valueAttribute = null;
                Hashtable<String, String> paramChoices = null;

                parameter = mAction.getParameter(paramName);
                if (parameter == null) {
                    System.err.println("OprnDlg:setData(): " + "Theres no parameter value for parameter " + paramName);
                    continue;
                }

                String oldValue = parameter.get(XMLConstants.svalue);
                //System.out.println("OperationDlg : saveDataSource(): " + "OLD value for parameter is :---" + oldValue);
                if (actionMeta != null) {
                    // paramType = actionMeta.getParamType(paramName);
                    // primaryUnit = actionMeta.getParamUnit(paramName, XMLConstants.kPrimaryUnit);
                    paramMeta = actionMeta.getParameterMeta(paramName);
                    if (paramMeta != null) {
                        displayAttribute = paramMeta.getAttribute(XMLConstants.sdisplayattribute);
                        valueAttribute = paramMeta.getAttribute(XMLConstants.svalueattribute);
                        paramChoices = paramMeta.getChoices();
                    }
                }

                if ((displayAttribute != null) && (displayAttribute.equals(XMLConstants.sHidden))) {
                    continue;
                } // Hidden parameters should not be displayed on the table

                String newValue = (String) mVDataSource.getTableDataItem(row, VALUECOLUMN);
                //System.out.println("OperationDlg : saveDataSource(): " + " NEW value for parameter is :---" + newValue);
                row++;
                if (newValue == null) {
                    //System.out.println("OprnDlg:saveDataSource " + "Param '" + paramName + "' is null");

                    continue;
                }

                /* choice list needs to be handled specially as the choices (strings)
                 * are displayed in the table whereas the choice values (integers) are saved.
                 */
                if ((valueAttribute != null) && (valueAttribute.equals(XMLConstants.schoice))) {

                    if (paramChoices == null) // due to reasons such as parameter misspelled in lang file,...
                    {
                        System.err.println("OprnDlg:setData(); " + paramName + " has no Choices");
                        continue;
                    }

                    //get the key corresponding to the choice displayed
                    Enumeration<String> keys = paramChoices.keys();
                    while (keys.hasMoreElements()) {
                        String keyVal = keys.nextElement();
                        String toCompare = paramChoices.get(keyVal);
                        if (toCompare.equals(newValue)) {
                            parameter.setValue(keyVal);
                            break;
                        }
                    }
                } // end if 
                else //all other types
                {
                    String valueToSet = newValue;

                    if (MCREWConfig.getDisplayUnit() != XMLConstants.kPrimaryUnit) // Conversions needed
                    {
                        if (paramMeta != null) {
                            valueToSet = paramMeta.convertToPrimaryUnits(newValue);
                        }

                        //System.out.println("OprnDlg:saveDataSource() " + "Converted new value " +
                        //newValue + " to " + valueToSet);
                    }

                    if (!(oldValue.equals(valueToSet))) {
                        /* Values should be written out in proper type i,e if user types in 5.00 for an integer value, 
                         * then it should be converted to 5 before putting the into the parameter
                         */

                        ////System.out.println("saveDataSource" + " Saving value " + paramName + " " + valueToSet);
                        String properTypeValue = valueToSet;
                        if (paramMeta != null) {
                            properTypeValue = paramMeta.convertToProperType(properTypeValue);
                        }
                        //System.out.println("OprnDlg:saveDataSource() " + "Proper Type Value is : " + properTypeValue);
                        parameter.setValue(properTypeValue);
                    }
                } // else all other types

            } // end of for
        }
    }

    static class NotesOperation extends usda.weru.mcrew.gui.NotesMan_n {

        private static final long serialVersionUID = 1L;

        public String title;
        //This tells us if the Notes frame is presently instantiated.
        public boolean notesPresent = false;
        public ActionJCTable tableRef;
        private final int row;
        private final int col;
        private String paramValue = "";

        /** Creates a new instance of NotesCrop */
        public NotesOperation(String t, java.awt.Dialog parent, Component tableParent,
                String paramValue, int row, int col) {
            super(parent, true);
            setSize(500, 300);
            setTitle(t);
            tableRef = (ActionJCTable) tableParent;
            this.paramValue = paramValue;
            this.row = row;
            this.col = col;
            JTA_Notes.setText(paramValue);
            tableRef.parentDlg.notesDataChanged = false;
        }

        @Override
        public void JBSave_actionPerformed(java.awt.event.ActionEvent evt) {
            paramValue = JTA_Notes.getText();
            //   //System.out.println("NotesCrop:JBSave_actionPerformed:newValue:"+paramValue);
            //tableRef.mVDataSource.setTableDataItem(paramValue, row , tableRef.VALUECOLUMN);
            tableRef.mVDataSource.setTableDataItem(paramValue, row, col);
            tableRef.mDataChanged = true;
            tableRef.parentDlg.dataChanged = true;
            tableRef.parentDlg.notesDataChanged = true;
            notesPresent = false;

            this.dispose();
        }

        @Override
        public void JBCancel_actionPerformed(java.awt.event.ActionEvent evt) {
            notesPresent = false;
            tableRef.parentDlg.notesDataChanged = false;
            this.dispose();
        }

        public void setText(String text) {
            JTA_Notes.setText(text);
        }

        public void setEditable(boolean editable) {
            JB_Save.setVisible(editable);
            JTA_Notes.setEditable(editable);
            JB_Cancel.setText(editable ? "Cancel" : "Close");
        }
    }
}
