package usda.weru.mcrew;

/**
 *
 * @author -ihaas-
 * 
 * Extends CropObject so that UPGM is a crop. UPGM records are written the same
 * way as Operations, so this inheritance is a bit messy. It allows operations
 * to deal with crops and UPGMs the same way; for the most part 
 */

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; 
import org.openide.util.Exceptions;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;

import java.util.Hashtable;

import usda.weru.util.WepsMessage;
import usda.weru.util.WepsMessageDialog;
import usda.weru.util.WepsMessageLog;
import usda.weru.util.wepsFileChooser2.WepsFileTypes2;

public class UpgmObject extends CropObject implements Cloneable {
    

    private static final Logger LOGGER = LogManager.getLogger(UpgmObject.class);
    private List<Action> mActions; //Holds as many Actions (with data values) as required

    public String upgmName; // Name of this particular UPGM record


    /** This List stores the identities of all actions for quick reference.
     * Also,  the vector is used to maintain the order of actions in this UpgmObject. Note that Hashtables
     * do not maintain the order */
    List<Identity> mActionIdVec;
    
    /**
     * Instance of UpgmMeta to store limits and datatypes.
     */
    UpgmMeta upgmMeta = (UpgmMeta) MCREWConfig.getObjectMeta(XMLConstants.sUPGM);
    /**
     * Stores the various identities that have out of range values;
     */
    Hashtable<Identity, InputLimits.TableStatus> actLim = new Hashtable<Identity, InputLimits.TableStatus>();

    /**
     * Returned if the file is read successfully.
     */
    public static final int kSuccess = 1;

    /**
     * When the errors are not defined or exceptions are not caught specifically then this
     * value is returned.
     */
    public static final int kUnknown_Error = -1;

    /**
     * If the file is missing or doesn't exist in that path then this value is returned.
     */
    public static final int kFile_NotFound = -2;

    /**
     * The default constructor that instantiates the various data structures to 
     * store the UPGM related meta data.
     */
    public UpgmObject() {
        mActions = new ArrayList<Action>();
        mObjectName = XMLConstants.sUPGM;
        upgmName = XMLConstants.sNoName;
        mActionIdVec = new ArrayList<>();
    }

    /**
     * Single argument constructor that instantiates the various data structures to 
     * store the UPGM related meta data.
     * @param pObjectName The name of the object which is being created.
     */
    public UpgmObject(String pObjectName) {
        mActions = new ArrayList<Action>();
        mObjectName = pObjectName;
        mActionIdVec = new ArrayList<>();
    }

    /**
     * Two argument constructor that instantiates the various data structures to 
     * store the UPGM related meta data.
     * @param pObjectName The name of the object which is being created.
     * @param pUpgmName The name of the UPGM record for which this UPGM 
     * object is being created.
     */
    public UpgmObject(String pObjectName, String pUpgmName) {
        mActions = new ArrayList<Action>();
        mObjectName = pObjectName;
        upgmName = pUpgmName;
        mActionIdVec = new ArrayList<>();
    }

    /**
     * Two argument constructor that instantiates the various data structures to 
     * store the UPGM related meta data.
     * @param pActions The vector of action objects that holds this UPGM object.
     * @param pObjectName The name of the object which is being created.
     */
    public UpgmObject(List<Action> pActions, String pObjectName) {
        mActions = pActions;
        mObjectName = pObjectName;
        mActionIdVec = new ArrayList<>();
    }

    /**
     *  Sets the UPGM name of this UPGM object to the value passed as argument.
     * @param pUpgmName The new name to be set as UPGM name.
     */
    public void setUpgmName(String pUpgmName) {
        upgmName = pUpgmName;
    }
    
    /**
     *  Sets the UPGM name of this UPGM object to the value passed as argument.
     * @param pUpgmName The new name to be set as UPGM name.
     */
    public void setCropName(String pUpgmName) {
        setUpgmName(pUpgmName);
    }

    /**
     * This method add the to the existing vector of actions for an UPGM.
     * @param pAction The action object to be added.
     */
    public void addAction(Action pAction) {
        if (mActions == null) {
            mActions = new ArrayList<Action>();
        }

        mActions.add(pAction);
        mActionIdVec.add(pAction.getIdentity());
    }

    /**
     * Fetches the action object from the vector sitting at index pIndex.
     * @param pIndex The index of the object in the vector.
     * @return The actin object being sought for data retrieval or updating.
     */
    public Action getAction(int pIndex) {
        return mActions.get(pIndex);
    }

    /**
     * Fetches the object that stores all the actions for an UPGM or a crop.
     * @return A vector object that stores all the action objects for the UPGM
     * being referred. 
     */
    public List<Action> getAllActions() {
        return mActions;
    }

    /**
     * Method unused presently.
     * Fetches the operation action. There is only one operation action in any operation object. 
     * All other actions are process or group actions
     * @return The sole action object associated with the operation.
     */
    /*public Action getOperationAction() {
        for (Action action : mActions) {
            if (action.isOperation() == true) {
                return action;
            }
        }
        return null;
    }*/
    
    /**
     * This method fetches the UpgmMeta object itself
     * @return upgmMeta
     */
    public UpgmMeta getMeta()
    {
        return upgmMeta;
    }
    
    public Hashtable<Identity, InputLimits.TableStatus> getActLim()
    {
        return actLim;
    }

    /**
     * Fetches the name of the object ("UPGM")
     * @return The object name.
     */
    @Override
    public String getObjectName() {
        return mObjectName;
    }

    /**
     * Fetches the name of the current UPGM object being referred
     * @return The UPGM name.
     */
    public String getUpgmName() {
        return upgmName;
    }

    /**
     * Fetches the datastructure that stores all the identity objects.
     * @return The vector that sores these identities associated with the
     * UPGM object.
     */
    public List<Identity> getAllIds() {
        return mActionIdVec;
    }

    /**
     * This method initializes the data or helps to acquire the required data for
     * initializing the various class level variables.
     * @param pNode The node whose data needs to be initialized.
     */
    @Override
    public void initialize(Node pNode) {
        DocumentTraversal traversable;

        if (pNode.getOwnerDocument() == null) {
            traversable = (DocumentTraversal) pNode;
        } else {
            traversable = (DocumentTraversal) pNode.getOwnerDocument();
        }

        TreeWalker walker = traversable.createTreeWalker(pNode, NodeFilter.SHOW_ALL, null, false);

        String nodeName = pNode.getNodeName();

        if (nodeName.equals(XMLConstants.soperationDB)) //upgm files are written in the operation form
        {
            Node nodeChild = walker.firstChild(); // the node is one of the action (operationdefn) or paramdefn (crop_defn) from 
            while (nodeChild != null) {
                String nodeChildName = nodeChild.getNodeName();
                if (nodeChildName.equals(XMLConstants.soperationname)) {
                    String upgmName = XMLDoc.getTextData(nodeChild);
                    setUpgmName(upgmName);
                } else if (nodeChildName.equals(XMLConstants.sactionvalue)) {
                    Action action = new Action();
                    action.initialize(nodeChild);

                    addAction(action);
                }
                nodeChild = walker.nextSibling();
            }
        }//end if nodeName.equals("operationDB")

    }


    /**
     * The method that fetches the name of this UPGM (crop)
     * @return The name of this UPGM.
     */
    public String getCropName() {
        return upgmName;
    }

    /** 
     * This function is called when a new crop is inserted. then the action G:03 needs to be changed
     * @param pCrop The new crop that is to be assigned.
     */
    public void changeCrop(CropObject pCrop) {
        /* Search for the action G:03, change the crop name
         * The Action after action G03 would be the one with all the parameter values which are needed to be changed
         * It's not good to depned upon the order of action, but presently the data in operation and management files are 
         * in this manner. Theres no other way to identiy the crop with its action and parameter values
         */
        boolean ActionIsCropData = false; // to check if next action's parameters needs to be changed

        for (int i = 0; i < mActionIdVec.size(); i++) {
            Action cropAction = mActions.get(i);
            if (cropAction.isCrop()) {
                // parameter to be changed is crop name
                cropAction.changeParameterValue(XMLConstants.sgcropname, pCrop.getCropName());
                // Change all the parameter values of actions until the next action with a crop

                for (int j = i + 1; j < mActionIdVec.size(); j++) {
                    Action processAction = mActions.get(j);

                    if (processAction.isCrop()) {
                        break;
                    }
                    processAction.changeAllParameterValues(pCrop);
                }

                return;
            }
        }
    }

    /** 
     * This function constructs a cropObjct from the crop values (Action G:03 and P50 or P51)
     * Can call this function, when the crop values has to be copied from one OperationObject
     * to other or is needed for cross reference.
     * @return The orop object associated with an opration object.
     */
    public CropObject getCrop() {
        CropObject cropObj = new CropObject();

        String cropName = getCropName();
        cropObj.setCropName(cropName);

        /* Copy all the parameter values from P50 /P51 to the new CropObject
         */
        for (int i = 0; i < mActionIdVec.size(); i++) {
            Action action = mActions.get(i);
            if (action.isCrop()) {
                // get all the parameter values of next action which can be P510 or P51
                Action processAction = mActions.get(i + 1);

                cropObj.setCropParameters(processAction);

                return cropObj;
            }
        }

        return null;
    }

    /**
     *
     * @param pParamName
     * @param pUnit
     * @return
     */
    public String[] getValues(String pParamName, int pUnit) {
        if (pParamName.equals(XMLConstants.soperationname)) {
            return new String[]{upgmName};
        }

        List<String> temp = new ArrayList<String>();

        //Loop over each action added the value of the parameter if it exists
        for (Action action : mActions) {
            Parameter parameter = action.getParameter(pParamName);
            if (parameter != null) {
                String value = parameter.get(XMLConstants.svalue);

                //Convert units if needed.
                if (value != null && pUnit == XMLConstants.kAlternateUnit) {
                    ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(action.getIdentity());
                    if (actionMeta != null) {
                        ParameterMeta paramMeta = actionMeta.getParameterMeta(pParamName);
                        value = paramMeta.convertToAlternateUnits(value);
                    }
                }

                //Add the value to the temp list
                temp.add(value);
            }
        }

        //return as an array of Strings
        return temp.toArray(new String[temp.size()]);
    }

    /**
     *
     * @param pParamName
     * @param values
     * @param pUnit
     */
    public void setValues(String pParamName, String[] values, int pUnit) {
        //Loop over each action set the value of the parameter if it exists
        int i = 0;
        for (Action action : mActions) {
            Parameter parameter = action.getParameter(pParamName);
            if (parameter != null) {
                String value = values[i];
                //Next value
                i++;

                ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(action.getIdentity());
                if (actionMeta != null) {
                    ParameterMeta paramMeta = actionMeta.getParameterMeta(pParamName);
                    //Convert units if needed.
                    if (value != null && pUnit == XMLConstants.kAlternateUnit) {
                        value = paramMeta.convertToPrimaryUnits(value);
                    }
                    value = paramMeta.convertToProperType(value);
                }
                parameter.setValue(value);

                if (i == values.length) {
                    break;
                }
            }
        }
    }

    /**
     * Fetches the value of an operation parameter with name pParamName.
     * @param pParamName The name of the parameter whose value is being sought.
     * @return The string value being returned.
     */
    public String getValue(String pParamName) {
        if (pParamName.equals(XMLConstants.soperationname)) {
            return upgmName;
        }
        for (Action action : mActions) {
            String colValue = action.getValue(pParamName);
            if (colValue != null) {
                return colValue;
            }
        }
        return null;
    }

    /**
     * Fetches the value of an operation parameter with name pParamName.
     * @param pParamName The name of the parameter whose value is being sought.
     * @param pUnit The units in which the parameter is supposed to hold its value.
     * @return The string value being returned.
     */
    @Override
    public String getValue(String pParamName, int pUnit) {
        if (pParamName.equals(XMLConstants.soperationname)) {
            return upgmName;
        }
	
	/* If pColName is not operation name, then its one of the parameters in one of the Actions
         * Search all the actions until you get the first parameterwith name = pColName */
        String returnValue = null;
        Identity actionId = null;
        for (Action action : mActions) {
            String colValue = action.getValue(pParamName);
            if (colValue != null) {
                returnValue = colValue;
                actionId = action.getIdentity();
                break;
            }
        }

        if ((returnValue != null) && (pUnit == XMLConstants.kAlternateUnit)) // i.e conversion is required
        {
            ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(actionId);
            if (actionMeta != null) {
                ParameterMeta paramMeta = actionMeta.getParameterMeta(pParamName);

                returnValue = paramMeta.convertToAlternateUnits(returnValue);

            }
        }
        return returnValue;
    }

    /**
     * This method sets the value of the operation object's parameter for a specific
     * action object to values passed as argument
     * @param pParamName The name of the parameter whose value is to be changed 
     * private set to a new value.
     * @param pNewValue The new value to be assigned.
     * @param pUnit The units in which the new value will be stored.
     */
    @Override
    public void setValue(String pParamName, String pNewValue, int pUnit) {
        Identity actionId = null;
        Action action = null;
        String oldValue = null;

        for (Iterator<Action> it = mActions.iterator(); it.hasNext();) {
            action = it.next();
            oldValue = action.getValue(pParamName);
            if (oldValue != null) {
                /* First, get to know which action is it */
                actionId = action.getIdentity();
                break;
            }
        }

        String valueToSet = pNewValue;
        if (actionId != null) {
            Parameter parameter = action.getParameter(pParamName);
            oldValue = parameter.get(XMLConstants.svalue);

            ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.soperation).getActionMeta(actionId);
            if (actionMeta != null) {
                ParameterMeta paramMeta = actionMeta.getParameterMeta(pParamName);
                if (paramMeta != null) {
                    /* Values are always stored in Primary unit, convert it if displayed values are in Alternate unit */
                    if (pUnit == XMLConstants.kAlternateUnit) {
                        valueToSet = paramMeta.convertToPrimaryUnits(pNewValue);

                    }

                    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;
                        properTypeValue = paramMeta.convertToProperType(properTypeValue);

                        parameter.setValue(properTypeValue);
                    }
                } // if(parameterMeta != null)
            } else {
                LOGGER.error("Could not find the actionMeta or parameterMeta. Setting new value anyway");

                parameter.setValue(pNewValue);
            }
        } else {
            //LOGGER.error("Could not find the action to which this parameter belongs. Discarding new value");
        }

    }

    /**
     * This method checks for parameter consistency and validity of the each action
     * based on its parameters validity to XML's well-formedness etc. 
     * @return List that holds all the invalid and inconsistent actions & parameters.
     */
    public List<Action> checkParameterConsistency() {
        List<Action> invalidActions = null;
        for (Action action : mActions) {
            List<String> invalidParams = action.checkParameterConsistency();

            if (invalidParams != null) {
                if (invalidActions == null) {
                    invalidActions = new ArrayList<>();
                }

                invalidActions.add(action);
            }
        }

        return invalidActions;
    }

    /** 
     * Fetches an operationDB node.
     * @param doc The document from where the node data or the node object is being retrieved. 
     * @return The node object that holds or will hold the reformatted data.
     */
    @Override
    public Node getNode(Document doc) {
        /**
         * Only this class knows the structure of an operationDB node and
         * so both reading from a (operaitonDB)Node and creating
         * new node are done in this class
         */

        Node operationDBNode = doc.createElement(XMLConstants.soperationDB);

        setNodeContents(operationDBNode, doc);

        return operationDBNode;
    }

    /* sets a given operationDBNode with the present Object contents
     */
    private void setNodeContents(Node pNode, Document pDoc) {
        Node operationNameNode = pDoc.createElement(XMLConstants.soperationname);
        XMLDoc.setTextData(operationNameNode, upgmName, pDoc);

        pNode.appendChild(operationNameNode);

        for (int i = 0; i < mActionIdVec.size(); i++) {
            Action action = mActions.get(i);
            Node actionvalueNode = action.getNode(pDoc);

            pNode.appendChild(actionvalueNode);
        }
    }

    private void setNodeContents(Node pNode, Document pDoc, String newFileName) {
        Node operationNameNode = pDoc.createElement(XMLConstants.soperationname);

        if (XMLConstants.soperationname.equals(operationNameNode.getNodeName())
                && (!operationNameNode.getNodeName().equals(newFileName))) {
            XMLDoc.setTextData(operationNameNode, newFileName, pDoc);
        }

        pNode.appendChild(operationNameNode);

        for (int i = 0; i < mActionIdVec.size(); i++) {
            Action action = mActions.get(i);
            Node actionvalueNode = action.getNode(pDoc);
            pNode.appendChild(actionvalueNode);

        }

    }

    /**
     * Makes a copy of the current object.
     * @return The new copy of the existing object.
     */
    @Override
    public Object clone() {
        UpgmObject copy = (UpgmObject) super.clone();

        copy.upgmName = upgmName;

        copy.mActions = new ArrayList<>();
        for (Action action : mActions) {
            Action actionCopy = (Action) action.clone();
            copy.mActions.add(actionCopy);
        }

        // Now clone the mActionIdVec also
        // Direct cloning of a vector will only give a shallow copy
        copy.mActionIdVec = new ArrayList<>();
        for (Identity id : mActionIdVec) {
            Identity idCopy = (Identity) id.clone();
            copy.mActionIdVec.add(idCopy);
        }

        return copy;
    }

    /** Read new operation xml file (*.upgm). Note that initialize() is called directly when reading from management
     * files. This function is called to read from upgm files while adding new upgm records in place of crops.
     * @param pFileName The XML file from which we get the data in a particular format.
     * @return positive integer if success else negative error code
     */
    @Override
    public int readXMLFile(String pFileName) {
        DataObject dataObject = null;
        Node root, node;
        Document doc;
        RowInfo row;
        doc = XMLDoc.getDocument(pFileName);
        if (doc == null) {
            return kUnknown_Error;
        }

        doc.normalize();
        initialize(doc.getDocumentElement());

        //handle the fix up of the ofuel from older versions
        //-ihaas- This shouldn't be necessary for upgm
        /*Action action = getOperationAction();
        if (action.getParameter("ofuel") == null) {
            if (action.getIdentity().id == 3 || action.getIdentity().id == 4) {
                action.addParameter(new Parameter("ofuel", " "));
            }
        }*/

        if (checkForRequiredGroups(true)) {
            return kUnknown_Error;
        } else {
            return kSuccess;
        }
    }

    /**  -ihaas- still need to fix
     * Writes a new operation xml file. This function is called when user selects to save a new upgm from UpgmDlg.
     * @param pFileName The name of the file to which the data will be written.
     * @return Returns a positive integer if the file was written successfully else
     * negative.
     */
    public int writeXMLFile(String pFileName) {
        String newUpgmFileName = null;
        if (!pFileName.toLowerCase().endsWith(WepsFileTypes2.Upgm.getExtension())) {
            pFileName = pFileName + WepsFileTypes2.Upgm.getExtension();
        }
        int index = pFileName.lastIndexOf("\\");
        if(index != -1) {
            newUpgmFileName = pFileName.substring(index + 1, pFileName.lastIndexOf("."));
        }
        else {
            newUpgmFileName = pFileName.substring(pFileName.lastIndexOf("/") + 1, pFileName.lastIndexOf("."));
        }

        Node root;
        String nonEscapingElements[] = {XMLConstants.soperationname, XMLConstants.sname};

        try {

            /* createDocument function cretes a new Document with appropriate Doctype and stylesheet attached */
            Document operationDoc = XMLDoc.createDocument(XMLConstants.soperation);
            if (operationDoc == null) {
                System.err.println("UpgmObject:writerXMLFile(): " + "operationDoc is null");
                return kUnknown_Error;
            }

            root = operationDoc.getDocumentElement();
            setNodeContents(root, operationDoc, newUpgmFileName);

        
            //BufferedWriter bw = new BufferedWriter(new FileWriter(pFileName));
            DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
            DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
            if (impl == null) {
                System.out.println("No DOMImplementation found !");
                return kUnknown_Error;
            }
            LSSerializer serializer = impl.createLSSerializer();
            serializer.getDomConfig().setParameter("format-pretty-print", true);
            LSOutput output = impl.createLSOutput();
            output.setEncoding(XMLConstants.sEncoding);
            output.setCharacterStream(new java.io.FileWriter(pFileName));
            serializer.write(operationDoc, output);
            

        } catch (DOMException e) {
            System.err.println("DomException");
        } catch (java.io.IOException e) {
            e.printStackTrace();
        } catch (InstantiationException | IllegalAccessException | ClassCastException | ClassNotFoundException ex) {
            Exceptions.printStackTrace(ex);
        }
        return kSuccess;
    }

    /**
     *
     * @param obj
     * @return
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final UpgmObject other = (UpgmObject) obj;
        if (this.mActions != other.mActions && (this.mActions == null || !this.mActions.equals(other.mActions))) {
            return false;
        }
        if (this.upgmName != other.upgmName && (this.upgmName == null
                || !this.upgmName.equals(other.upgmName))) {
            return false;
        }
        if (this.mActionIdVec != other.mActionIdVec && (this.mActionIdVec == null
                || !this.mActionIdVec.equals(other.mActionIdVec))) {
            return false;
        }
        return true;
    }

    /**
     *
     * @return
     */
    @Override
    public int hashCode() {
        int hash = 3;
        hash = 37 * hash + (this.upgmName != null ? this.upgmName.hashCode() : 0);
        return hash;
    }

    /**
     * Checks the loaded operation processes for required groups.
     * @param showMessage Indicates if a WepsMessageDialog box should be shown with any errors
     * found.  The dialog is not displayed if there are no errors.
     * @return True when there were errors.  Returns false when there are no missing
     * groups.
     */
    public boolean checkForRequiredGroups(boolean showMessage) {
        WepsMessageLog log = new WepsMessageLog();
        boolean firstError = true;
        for (Object o : getAllActions()) {
            Action action = (Action) o;
            Identity id = action.getIdentity();
            ActionMeta actionMeta = MCREWConfig.getObjectMeta(XMLConstants.sUPGM).getActionMeta(id);
            List<Identity> applicableGroupIds = actionMeta.getGroupId();
            String applicableGroupList = "";

            if (applicableGroupIds != null) {
                for (Object q : applicableGroupIds) {
                    Identity qId = (Identity) q;
                    if (applicableGroupList.length() == 0) {
                        applicableGroupList = "Groups: [" + qId.toString() + "]";
                    } else {
                        applicableGroupList = applicableGroupList + ", [" + qId.toString() + "]";
                    }
                }

                //This action requires a group                    
                //Start at the current action and work our way up the list.
                boolean foundGroup = false;
                for (int actionIndex = getAllActions().indexOf(action); actionIndex >= 0 && !foundGroup; actionIndex--) {
                    Action testAction = this.getAction(actionIndex);
                    Identity testId = testAction.getIdentity();
                    for (Object p : applicableGroupIds) {
                        Identity testGroup = (Identity) p;
                        if (testGroup.equals(testId)) {
                            foundGroup = true;
                            break;
                        }
                    }
                }

                if (!foundGroup) {
                    if (firstError) {
                        log.logMessage(WepsMessage.errorMessage("Errors were found in the operation file.\n"));
                        firstError = false;
                    }
                    log.logMessage(WepsMessage.errorMessage(action.getActionName() + " [" + id.toString()
                            + "] requires a group. " + applicableGroupList));
                }
            }
        }

        if (log.hasMessage()) {
            if (showMessage) {
                //Show a warning message.                   
                WepsMessageDialog.showMessageList(null, "Missing Groups", MCREWConfig.getConfigDir(), log.getMessages());
            }
            return true;
        } else {
            return false;
        }

    }
    
    /**
     * Checks all of the data contained within the object.
     * @return tableStatus
     */
    @Override
    public InputLimits.TableStatus checkData()
    {
        InputLimits.TableStatus overall = InputLimits.TableStatus.OKAY;
        for(Action act : mActions)
        {
            InputLimits.TableStatus actVal = InputLimits.TableStatus.OKAY;
            for(String paramName : act.getParameterNames())
            {
                Parameter param = act.getParameter(paramName);
                String value = param.get("value");
                if(value == null) continue;
                ActionMeta actionMeta = upgmMeta.getActionMeta(act.getIdentity());
                ParameterMeta limits = actionMeta.getParameterMeta(paramName);
                if(limits == null) continue;
                if(limits.getGroupAttribute(paramName, XMLConstants.svalueattribute).
                        equals(XMLConstants.schoice))
                {
                    lim.put(paramName, InputLimits.TableStatus.CHOICE);
                    continue;
                }
                if(limits.getGroupAttribute(paramName, XMLConstants.svalueattribute).
                        equals(XMLConstants.smultiline))
                {
                    lim.put(paramName, InputLimits.TableStatus.CHOICE);
                    continue;
                }
                InputLimits limiter = limits.getLimits();
                InputLimits.TableStatus currentCellStatus = limiter.evaluateInput(value);
                // -ihaas- This is not needed for upgm objects because there is no G3
                /*if(act.getIdentity().equals(new Identity(3, "G")))
                {
                    CropObject tempCrop = getCrop();
                    currentCellStatus = tempCrop.checkData();
                }*/
                lim.put(paramName, currentCellStatus);
                if(overall.lessThan(currentCellStatus))
                {
                    overall = currentCellStatus;
                }
                if(actVal.lessThan(currentCellStatus))
                {
                    actVal = currentCellStatus;
                }
            }
            actLim.put(act.getIdentity(), actVal);
        }
        return overall;
    }
    
    public ParameterMeta getParameterMeta(String paramName)
    {
        for(Action act : mActions)
        {
            ActionMeta actionMeta = upgmMeta.getActionMeta(act.getIdentity());
            ParameterMeta parm = actionMeta.getParameterMeta(paramName);
            if(parm != null)
            {
                return parm;
            }
        }
        return null;
    }
            
    /**
     * This method fetches the the parameter object associated with the name pName
     * in this UPGM's list of actions.
     * @param pName The name of the parameter object requested.
     * @return The parameter object associated with pName
     */
    public Parameter getParameter(String pName) {
        Parameter parameter;
        for (Action a : mActions){
            parameter = a.getParameter(pName);
            if (parameter != null) {
                return parameter;
            }
        }
        return null;
    }
    
}
