package usda.weru.mcrew;

import com.klg.jclass.cell.JCCellInfo;
import com.klg.jclass.cell.editors.BaseCellEditor;
import com.klg.jclass.cell.editors.JCComboBoxCellEditor;
import com.klg.jclass.cell.editors.JCStringCellEditor;
import com.klg.jclass.cell.renderers.JCComboBoxCellRenderer;
import com.klg.jclass.table.CellStyleModel;
import com.klg.jclass.table.JCCellBorder;
import com.klg.jclass.table.JCCellStyle;
import com.klg.jclass.table.JCEditCellEvent;
import com.klg.jclass.table.JCEditCellListener;
import com.klg.jclass.table.JCTable;
import com.klg.jclass.table.JCTableEnum;
import com.klg.jclass.table.data.JCEditableVectorDataSource;

import de.schlichtherle.truezip.file.TFile;

import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import javax.help.CSH;
import javax.help.HelpBroker;
import javax.help.HelpSet;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import usda.weru.util.ConfigData;

import usda.weru.util.Help;
import usda.weru.util.Util;
import usda.weru.util.wepsFileChooser2.WepsFileChooser2;
import usda.weru.util.wepsFileChooser2.WepsFileTypes2;
import usda.weru.weps.fuel.FuelChooser;

/**
 * @author -ihaas-
 * UpgmDlg screen displays the values of all parameters of the selected UPGM.
 * Parameter values can also be modified from here. Also, modified values can be saved as
 * a new UPGM.
 */
public class UpgmDlg extends usda.weru.mcrew.gui.UpgmDlg_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;
    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.
    List<Action> mActions;
    int mSelectedIndex, mAdditionalIndex, listOffsetIndex;
    Identity mSelectedIdentity, mAdditionalIdentity;
    UpgmObject mUpgmObj; // holds a copy (clone) of Operation Object passed to the constructor4
    UpgmObject mOriginalUpgmObj; // Holds the operation object passed. This is updated only if user clicks OK.
    String mUpgmActionName;
    //ActionJCTable mUpgmTable, mMiddleTable, mLowerTable;
    ActionJCTable mMiddleTable;
    /**
     * Variables to store whether the Drill down can save, and offending cells
     */
    private InputLimits.TableStatus allowSave = InputLimits.TableStatus.OKAY;
    ArrayList<Integer> outHard = new ArrayList<>();
    ArrayList<Integer> outSoft = new ArrayList<>();
    //An array list of parameter names corresponding to outTab, for stacking outlimits.
    ArrayList<String> outTabName = new ArrayList<>();
    
    private Table origin; //This is just so we can activate checkData upon exit.
    
    /**
     * This is the default group that is selected when the operation dialog screen appears.
     */
    public static final int kDefaultSelection = 0;
    /**
     * 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 UpgmDlg(Table tab, UpgmObject pUpgmObj, String pDate, ManageData manage, RowInfo row) {
        super(Util.getParentJFrame(tab));
        origin = tab;
        outTab = new ArrayList<Identity>();
        c_manage = manage;
        c_row = row;

        mOriginalUpgmObj = pUpgmObj;
        mUpgmObj = mOriginalUpgmObj;

        mIdListModel = new myListModel<Identity>();
        JTF_upgmName.setText(pUpgmObj.getUpgmName());
        JTF_date.setText(pDate);

        //mUpgmTable = new ActionJCTable(this);
        mMiddleTable = new ActionJCTable(this);
        //mLowerTable = new ActionJCTable(this);

        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);

        //JSP_upperParam.getViewport().setView(mUpgmTable);
        JSP_middleParam.getViewport().setView(mMiddleTable);
        //JSP_lowerParam.getViewport().setView(mLowerTable);
        showTables();
        Util.loadToolTips((Container) this, new TFile("mcrew_cfg", "mcrewtooltips.cfg"));
    }
    
    /**
     * This method initializes the operation table data with the meta data that is 
     * associated with identities as keys to the respective objects e:g Action objects 
     * or data structures that hold these objects.
     */
    public void initialize() {
        int ListModelIndex = 0;

        mActions = mUpgmObj.getAllActions();
        List<Identity> mActionIdVec = mUpgmObj.getAllIds();

        for (int i = 0; i < mActionIdVec.size(); i++) {
            Identity identity = mActionIdVec.get(i);
            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.
     */
    private InputLimits.TableStatus checkDataInit(int row, List<String> catParams)
    {
        String paramName = catParams.get(row);
        for(Action token : mUpgmObj.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(mUpgmObj.getCrop().getParameter("idc") != null)
                    {   
                        if(mUpgmObj.getCrop().getParameter("idc").getValue().equals("0") 
                                && !mUpgmObj.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.
     */
    private InputLimits.TableStatus checkDataCell(String value, String paramName)
    {
        for(Action token : mUpgmObj.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(mUpgmObj.getCrop().getParameter("idc") != null)
                    {
                        if(mUpgmObj.getCrop().getParameter("idc").getValue().equals("0") 
                                && !mUpgmObj.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 : mUpgmObj.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);
                // -ihaas- fix for old unneccessary parameters.
                if (limits == null) {
                    continue;
                }
                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.  
     */
    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(), "upgm_intro_html", hs);

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

        //Add help ids to the components
        CSH.setHelpIDString(JTF_upgmName, "upgm_drill_upgmname_html");
        CSH.setHelpIDString(upgmNameLabel, "upgm_drill_upgmname_html");
        CSH.setHelpIDString(JP_toolbar, "upgm_drill_toolbar_html");
        CSH.setHelpIDString(JP_middle, "upgm_drill_groupparameters_html");
        CSH.setHelpIDString(JTF_date, "upgm_drill_date_html");
        CSH.setHelpIDString(JL_Date, "upgm_drill_date_html");
        CSH.setHelpIDString(JLabel1, "upgm_drill_list_html");
        CSH.setHelpIDString(JSP_list, "upgm_drill_list_html");

        CSH.setHelpIDString(JB_cancel, "upgm_toolbar_cancel_html");
        CSH.setHelpIDString(JB_saveAs, "upgm_toolbar_save_html");
        CSH.setHelpIDString(JB_help, "upgm_toolbar_help_html");
        CSH.setHelpIDString(JB_close, "upgm_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;
        }
        List<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);
            }

            //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 upgm dialog screen based on a
     * particular selection criteria. If a process is selected, 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() {
        mMiddleTable.clear();

        JL_middlePanel.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 = mUpgmObj.getAction(mAdditionalIndex + listOffsetIndex);
            mMiddleTable.setData(action);
            // mAdditionalTable.setData(action);
            JL_middlePanel.setText(sGroupParameters + mAdditionalIdentity.toString()
                    + sIdNameSeparator + action.getActionName());

        } else if (mSelectedIdentity != null) {
            Action action = mUpgmObj.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 invoked when the upgm 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.
        mMiddleTable.commitEdit(true);

        int option = -200;

        if (dataChanged == true || notesDataChanged == true) {
            option = JOptionPane.showConfirmDialog(this, "update the current upgm info into the current management record?");
            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.",
                        mUpgmObj.getUpgmName(), JOptionPane.INFORMATION_MESSAGE);
                        return;
                    case WARNSAVE:
                        JOptionPane.showMessageDialog(null, "Warning:\nSome data out of recommended limits.",
                        mUpgmObj.getUpgmName(), JOptionPane.INFORMATION_MESSAGE);
                    default:
                        mMiddleTable.saveDataSource(); //i.e transfer the new data from mVDataSource to Action object (mAction)
                        mOriginalUpgmObj = mUpgmObj;
                        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.",
                mUpgmObj.getUpgmName(), JOptionPane.INFORMATION_MESSAGE);
                break;
            case WARNSAVE:
                JOptionPane.showMessageDialog(null, "Warning:\nSome data out of recommended limits.",
                mUpgmObj.getUpgmName(), JOptionPane.INFORMATION_MESSAGE);
            default:
                int option = -200;
                if (dataChanged == true || notesDataChanged == true) {
                    option = JOptionPane.showConfirmDialog(this, "Save changes made to the current upgm info into a new upgm file? ");
                    switch (option) {
                        case JOptionPane.CANCEL_OPTION:
                            return;
                        case JOptionPane.NO_OPTION:
                            return;
                    }
                }
                
                if (option == JOptionPane.CLOSED_OPTION) {
                    return;
                }
                //Save any final changes made
                mMiddleTable.saveDataSource(); //i.e transfer the new data from mVDataSource to Action object (mAction)
                dataChanged = false; //Reset changed flag after updating

                // distinct save as dir.
                TFile oprnDir = new TFile(ConfigData.getDefault().getDataParsed("CD-local_oper_folder"));
                String upgmDirPath = oprnDir.getAbsolutePath();
                WepsFileChooser2 mfc = new WepsFileChooser2(WepsFileTypes2.Upgm, upgmDirPath,
                        WepsFileChooser2.Action.Save);
                //set the tooltip of "home" button to "Home" instead of "Desktop"
                mfc.homeToolTip(mfc);
                mfc.setOperationChooser();
                mfc.enableFolderButtonsSave();
                mfc.setCurrentDirectory(upgmDirPath); //new de.schlichtherle.truezip.file.File(ConfigData.INITIAL_DIR));
                mfc.setSelectedFile(new File (mUpgmObj.getUpgmName() + WepsFileTypes2.Upgm.getExtension()));
                //Set the title of the file chooser dialog appropriately acc to the option - Neha
                if (option == 0) {
                    mfc.setDialogTitle("Save a new upgm");
                }
                if (mfc.showDialog(this) != WepsFileChooser2.APPROVE_OPTION) {
                    return;
                }

                String newFileName = null;
                try {
                    newFileName = mfc.getSelectedFile().getCanonicalPath();
                } catch (java.io.IOException e) {
                    System.err.println("UpgmDlg:Save As(): error " + e);
                    return;
                }
                if (newFileName.endsWith("." + WepsFileTypes2.Upgm.getExtension())) {
                    newFileName = newFileName.substring(0, newFileName.indexOf("." + WepsFileTypes2.Upgm.getExtension()));
                }
                if (!newFileName.toLowerCase().endsWith(WepsFileTypes2.Upgm.getExtension())) {
                    newFileName = newFileName + WepsFileTypes2.Upgm.getExtension();
                }
                mUpgmObj.writeXMLFile(newFileName);
          
                MCREWConfig.getOpFileList().refreshFiles();
        }
    }

    /**
     * This method adjust the components in the upgm 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 UpgmDlgN_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));
        
        int detWidth = ((int) size.getWidth() / 3) - sideOffset;
        if(detWidth > 300) {
            detWidth = 300;
        }
        
        JP_operDetails.setSize(detWidth, (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));
        
        int midWidth = (((int) size.getWidth() - detWidth)) - (3 * sideOffset);
        int midHeight = (JP_operDetails.getHeight());
        JP_middle.setSize(midWidth, midHeight);
        
        JP_middle.setLocation((JP_operDetails.getWidth() + 2 * sideOffset),
                (yLocation + componentOffSet));
        
        JSP_middleParam.setSize((JP_middle.getWidth() - sideOffset),
                (JP_middle.getHeight() - (JP_middleParam.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.tableDataChanged == true) {
                mMiddleTable.saveDataSource(); //i.e transfer the new data from mVDataSource to Action object (mAction)
            }

            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.get(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 tableDataChanged = false;
        JCEditableVectorDataSource mVDataSource;
        JCCellStyle mCellStyle, mUnHLimitCellStyle, mUnSLimitCellStyle, mValueCellStyle, mHLimitCellStyle, mSLimitCellStyle;
        Action mAction; // Specifies the action for which the data is being displyed
        JCStringCellEditor se;
        List<NotesOperation> notes = new ArrayList<NotesOperation>();
        List<Integer> noteMap = new ArrayList<Integer>();
        UpgmDlg parentDlg;

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

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

            addEditCellListener(this);
            addMouseMotionListener(this);

        }

        @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;
            }
        }
        String beforeEditValue = "";
        String afterEditValue = "";

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

        @Override
        public void editCell(JCEditCellEvent ev) {
        }

        @Override
        public void afterEditCell(JCEditCellEvent ev) {
            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) {
                    tableDataChanged = true;
                    dataChanged = true;
                }
            }
            
            InputLimits.TableStatus check = checkDataCell(afterEditValue, paramName);
            test(check, row);
        }

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

            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);

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

            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 : mUpgmObj.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);
                            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);
                        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 List<String> parameterNames;
        
        public String getParamName(int row)
        {
            return parameterNames.get(row);
        }

        public void setData(Action pAction) {
            mAction = pAction;
            parameterNames = new ArrayList<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 displayAttribute = null;
                String valueAttribute = null;
                String format = null;
                String units = null;
                Hashtable<String, String> paramChoices = null;

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

                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);

                        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("UpgmDlg: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("UpgmDlg: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();

                    List<String> choiceList = new ArrayList<>();
                    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");
                    int index = notes.size();
                    notes.add(new NotesOperation("Operation File Notes", parentDlg, this, paramValue, row, col));
                    noteMap.add(row);

                    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.get(index).setEditable(true);
                    } else {
                        button.setText("View Notes");
                        notes.get(index).setEditable(false);
                    }

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

                    button.addActionListener(new ActionListener() {

                        @Override
                        public void actionPerformed(ActionEvent ev) {
                            notesButton_clicked(ev);
                        }
                    });

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

                    JCCellStyle fuelStyle = (JCCellStyle) mValueCellStyle.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) {
                                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++;

            }

            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);
            NotesOperation note = notes.get(noteMap.indexOf(row));
            note.setText(text);
            if (note.notesPresent == false) {
                note.setVisible(true);
                note.notesPresent = true;
            } else {
                if (note.isActive() == false) {
                    note.toFront();
                    note.setVisible(true);
                    note.requestFocus();
                }
            }
        }

        /* 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 (tableDataChanged == false) {
                return;
            }

            tableDataChanged = false; //reset the boolean varaible
            List<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);
                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);
                if (actionMeta != null) {
                    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);
                row++;
                if (newValue == 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);
                        }
                    }

                    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
                         */
                        String properTypeValue = valueToSet;
                        if (paramMeta != null) {
                            properTypeValue = paramMeta.convertToProperType(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);
        }

        @Override
        public void JBSave_actionPerformed(java.awt.event.ActionEvent evt) {
            paramValue = JTA_Notes.getText();
            tableRef.mVDataSource.setTableDataItem(paramValue, row, col);
            notesPresent = false;

            this.dispose();
        }

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

        public void setText(String text) {
            JTA_Notes.setText(text);
            tableRef.parentDlg.notesDataChanged = true;
        }

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