/* Title:		CropMeta
 * Version	
 * Author		Sada, Manmohan
 * Company: USDA-ARS
 * Date:    July, 2003
 * 
 */

package usda.weru.mcrew;

import java.util.Collections;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.apache.log4j.Logger;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.w3c.dom.traversal.TreeWalker;



/**
 * This class defines a crop. It holds information ABOUT the parameters of a particular
 * crop as obtained from crop_defn.xml, crop_display.xml, crop_lang.xml.
 */
public class CropMeta extends ObjectMeta
{
    private final static Logger logger = Logger.getLogger(CropMeta.class);

        Map <String, ParameterMeta> mParameters; // holds all parameter Metas. Node: Crops does'bnt have nay actions, only parameters
	List <String> mParameterNames; //List of parameter names
                
        Map <String, String> cropDisCatAndVal;
        Map <String, List<String>> cropCatAndParams;
        List <String> CategoryNamesVec;
        List <String> catParamsVec;
 
        /**
         * Constructor that defines the objects/datastructure that stores the meta
         * data for each crop object declared in the crop_defn.xml, crop_display.xml,
         * crop_lang.xml
         */        
	public CropMeta()
	{
            mParameters = new Hashtable<String, ParameterMeta>();
            mParameterNames = new Vector<String>();                
            cropDisCatAndVal = new Hashtable<String, String>();
            cropCatAndParams = new Hashtable<String, List<String>>();
            CategoryNamesVec = new Vector<String>();
            catParamsVec = new Vector<String>();
	}
 
    /**
     * Constructor that defines the objects/datastructure that stores the meta
     * data for each crop object with name pObjectName declared in the 
     * crop_defn.xml, crop_display.xml, crop_lang.xml
     * @param pObjectName The name of the cropObject whose meta data needs to be
     * stored here in this object
     */    
	public CropMeta(String pObjectName)
	{
            this();
            mObjectName = pObjectName;
	}
	
    /**
     * Initialization of the crop meta data happens here. Even though crops are part
     * of the operations' data the Meta's are made independent for simplicity sake.
     * @param pNode The node which needs to be initialized with the data from the 
     * particular crop file containing the data.
     */    
	public void initialize(Node pNode)
	{
		DocumentTraversal traversable;
		Node node;

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

		TreeWalker walker = traversable.createTreeWalker(pNode, NodeFilter.SHOW_ALL, null, false);
		
		node = walker.firstChild(); // the node is one of the action (operationdefn) or paramdefn (crop_defn) from 
			
		while(node != null)
		{
			String nodeName = node.getNodeName();
			if (mParameters == null)
				mParameters = new Hashtable();
				
			if(nodeName.equals(XMLConstants.sparamdefn)) //e.g. cropdefnxml has not actions
			{
				/* Note: Crop object are part of operation objects. Buyt just for simplicity, the Metas are made independent.
				 * The crop data objects though are part of Operation data objects
				 */
				ParameterMeta parameterMeta = new ParameterMeta();
				parameterMeta.initialize(node);
				String paramname = parameterMeta.get(XMLConstants.sparamname);			
				mParameters.put(paramname, parameterMeta); // parameters are stored according to their names
				mParameterNames.add(paramname);
			}
            if(nodeName.equals(XMLConstants.scategoryname)) //e.g. crop_display.xml have these elements
			{
                 //System.out.println("Crop_display.XML : Category Name found in crop_display.xml file");
                        
            }
                        
			node = walker.nextSibling();
		} // end while( node != null )
	}
	
    /**
     * This method allows the updation of crop meta data stored in the corresponding
     * data structure
     * @param pNode The crop node whose meta data is being updated from the crop_dlg screen
     * depending on its category or the OperationDlg screens which allows modification and
     * updation of data for analysis purpose.
     * 
     */    
	public void update(Node pNode)
	{
		DocumentTraversal traversable;
		Node nodeChild;

		if(pNode.getOwnerDocument() == null)
		{
			traversable = (DocumentTraversal)pNode;
		}
		else
			traversable = (DocumentTraversal)pNode.getOwnerDocument();
			
		TreeWalker walker = traversable.createTreeWalker(pNode, NodeFilter.SHOW_ALL, null, false);
		
		nodeChild = walker.firstChild(); // The node is one of the  or paramlang (croplang) 
																		// or categoryname (cropdisplay)
			
		while(nodeChild != null)
		{
			String nodeName = nodeChild.getNodeName();
			
			if( (nodeName.equals(XMLConstants.sparamlang)) || (nodeName.equals(XMLConstants.sparamdisplay)) )
			{
				Node langORdisplayNode = nodeChild;
				
				Node paramnameNode = walker.firstChild();
				String paramname = XMLDoc.getTextData(paramnameNode);
                                                                			
				ParameterMeta parameterMeta  = (ParameterMeta)mParameters.get(paramname);
				if(parameterMeta != null) {
					parameterMeta.update(langORdisplayNode);
                                }
				else{
                                    logger.warn("Prameter " + paramname +" is missing in croplang/display");
                                }
												
				walker.parentNode(); // back to paramlang/ paramdisplay level

			}
			else if( nodeName.equals(XMLConstants.scategory)) //from crop_display.xml
			{
                            populateCropDisplayDataStructure(nodeChild);
                            updateCropDisplay(nodeChild);
			
			}
			nodeChild = walker.nextSibling();
		} // end while(node != null)
	}

    /**
     * This methods populates the data structures involved in pulling the data
     * for various tabs shown in crop dialog screen from the crop file taken 
     * from the soil database.
     * @param pNode The crop node whose data is being populated.
     */    
        public void populateCropDisplayDataStructure(Node pNode)
	{
        DocumentTraversal traversable;
		Node nodeChild;

		if(pNode.getOwnerDocument() == null)
		{
			traversable = (DocumentTraversal)pNode;
		}
		else
			traversable = (DocumentTraversal)pNode.getOwnerDocument();
			
		TreeWalker walker = traversable.createTreeWalker(pNode, NodeFilter.SHOW_ALL, null, false);
		nodeChild = walker.firstChild(); // The node is one of the categoryname or paramdisplay

		while(nodeChild != null)
		{
			String categoryName ="";
			String categoryChildName = nodeChild.getNodeName();
			
			if(categoryChildName.equals(XMLConstants.scategoryname)) //for cropdefn
			{
				categoryName = XMLDoc.getTextData(nodeChild);
                               if(categoryName != null && !categoryName.equals("")){
                                    CategoryNamesVec.add(categoryName);
                                    String catDisplayVal = getCategoryDisplayValue(walker);
                                    cropDisCatAndVal.put(categoryName, catDisplayVal);
                                    //System.out.println("========populateCropDisplayDataStructure ===== Category Name : === " + categoryName + " === Category Display Value is : == " + catDisplayVal );
                                
                                    //catParamsVec = getCatParamsVec(walker);
                                    catParamsVec = getCatParamsVec(nodeChild);
                                    if(catParamsVec.isEmpty()){
                                        //System.out.println("=============================populateCropDisplayDataStructure VECTOR catParamsVec is EMPTY ==========================");
                                    }
                                    cropCatAndParams.put(categoryName, catParamsVec);
                               }
                                
//                                //System.out.println("CropMeta: updateCropDisplay(), " + "Category Name: "  + categoryName  );
				//categoryName = walker.firstChild().getNodeValue();
				//walker.parentNode(); //back to category name level
                                walker.parentNode();
			}
			/*else if( categoryChildName.equals(XMLConstants.sparamdisplay) )  
			{
				Node displayNode = nodeChild;
			
				Node paramnameNode = walker.firstChild();
				String paramname = XMLDoc.getTextData(paramnameNode);
                                
                                // Manmohan has added on 5th May, 2004
                                Node dispAttrNode = walker.nextSibling();
				String dispAttr = XMLDoc.getTextData(dispAttrNode);
                                
                                Node valAttrNode = walker.nextSibling();
				String valAttr = XMLDoc.getTextData(valAttrNode);
                                
				//System.out.println("CropMeta:updateCropDisplay(), " + "Parameter:- "  + paramname + " Display Attribute :- " +  dispAttr + " Value Attribute :- " + valAttr );
				
				ParameterMeta parameterMeta = (ParameterMeta)mParameters.get(paramname);
				if(parameterMeta != null)
				{
					parameterMeta.update(displayNode);
					parameterMeta.setDisplayCategory(categoryName);
				}
				else
				{
					System.err.println("Parameter " + paramname + " is missing in parameterMeta"+ " @CropMeta:updateCropDisplay()");
				}
				walker.parentNode();
			}*/
					
			nodeChild = walker.nextSibling();
		}// end of while
	}
        
        /**
         * Getter method that gets the value of the category that will be displayed
         * when the tabs in cropDlg are populated category-wise.
         * @param w Tree of nodes that contain the data in a categorized form where the
         * category display value will be cross checked sequentially.
         * @return The display value for the category
         */        
     public String getCategoryDisplayValue(TreeWalker w){
           
        String display = "true";
        Node n = w.nextSibling();        
        String categoryDisplayVal = "";        
            
         do{
            categoryDisplayVal = n.getNodeName();
           // //System.out.println(" CropMeta : getCategoryDisplayValue() Ln 223 : Value of categoryDisplayVal is : "+ categoryDisplayVal );
               if( categoryDisplayVal.equals(XMLConstants.scatDisplayValue) ){
                     display = n.getNodeValue();
                     break;
                }else{
                    display = "true";
                
                }

            n = w.nextSibling();
            
         }while( n != null);
           
       ////System.out.println(" CropMeta : getCategoryDisplayValue() Ln 260 : Value of DISPLAY : "+ display );
       return display;
     }
     
    
     //public Vector getCatParamsVec(TreeWalker w){
     /**
      * Getter method that returns the vector containing parameters in a category
      * of crops
      * @param n1 - The Node whose soil parameters are to be found out under a particular
      * category tag. For e:g, can be found out from crop_display.xml file.
      * @return The vector containing all the crop parameters falling under
      * the mentioned category.
      */     
     public List <String> getCatParamsVec(Node n1){
        List <String> paramList = new Vector <String>();
        //Node n = w.nextSibling();
        //String name = n1.getNodeName();
        String paramdisplay = "";
        
     
        while( n1 != null ){
            paramdisplay = n1.getNodeName(); //XMLDoc.getTextData(n1);
            ////System.out.println("================== getCatParamsVec() : paramdisplay value is: " + paramdisplay + "======================");
                if( paramdisplay.equals(XMLConstants.sparamdisplay) ){
                        n1 = n1.getFirstChild();
                        String nodename = XMLDoc.getTextData(n1);
                        ////System.out.println("================== getCatParamsVec() : Adding Node Name to paramList " + nodename + "======================");
                        paramList.add(nodename);
                        n1 = n1.getParentNode();
                }
                // n = w.nextSibling();
                n1 = n1.getNextSibling();
        }
        if(paramList.isEmpty()){
            //System.out.println("================== getCatParamsVec() : paramList Vector is EMPTY ======================");
            return null;
        }else
            return paramList;
     }
     
     /**
      * This is a getter method that returns the crop categories and parameters.
      * @return The hashtable containing the crop's categories and corresponding 
      * parameters associated with that category.
      */     
     public Map <String, List<String>> getCropCatAndParams(){       
         if (cropCatAndParams != null){
             return Collections.unmodifiableMap(cropCatAndParams);
         }
         else{
             return Collections.emptyMap();
         }
     }
         
     /**
      * This is a getter method that returns the category names contained in each
      * category under which the parameternames are specified.
      * @return The Vector containing these category names
      */      
      public List <String> getCategoryNamesVec(){
        
          return CategoryNamesVec;
      }
     
      /**
       * This method updates the crop display screen with the most recent data
       * that was fed in its various text fields or options updated in its choice
       * lists returns the category names contained in each category under which
       * the parameternames are specified.
       * @param pNode The crop node parameters whose data got modified in the crop
       * dialog screen.
       */      
     public void updateCropDisplay(Node pNode)
     {
		DocumentTraversal traversable;
		Node nodeChild;

		if(pNode.getOwnerDocument() == null)
		{
			traversable = (DocumentTraversal)pNode;
		}
		else
			traversable = (DocumentTraversal)pNode.getOwnerDocument();
			
		TreeWalker walker = traversable.createTreeWalker(pNode, NodeFilter.SHOW_ALL, null, false);
		
		nodeChild = walker.firstChild(); // The node is one of the categoryname or paramdisplay

	
		while(nodeChild != null)
		{
			String categoryName ="";
			String categoryChildName = nodeChild.getNodeName();
			
			logger.debug("Nodechild Name: "  + categoryChildName);
			if(categoryChildName.equals(XMLConstants.scategoryname)) //for cropdefn
			{
				categoryName = XMLDoc.getTextData(nodeChild);
                                logger.debug("Category Name: "  + categoryName  );
				//categoryName = walker.firstChild().getNodeValue();
				//walker.parentNode(); //back to category name level
			}
			else if(categoryChildName.equals(XMLConstants.sparamdisplay) )  
			{
				Node displayNode = nodeChild;
			
				Node paramnameNode = walker.firstChild();
				String paramname = XMLDoc.getTextData(paramnameNode);
                                
                                // Manmohan has added on 5th May, 2004
                                Node dispAttrNode = walker.nextSibling();
				String dispAttr = XMLDoc.getTextData(dispAttrNode);
                                
                                Node valAttrNode = walker.nextSibling();
				String valAttr = XMLDoc.getTextData(valAttrNode);
                                
				logger.debug("Parameter:- "  + paramname + " Display Attribute :- " +  dispAttr + " Value Attribute :- " + valAttr );
				
				ParameterMeta parameterMeta = (ParameterMeta)mParameters.get(paramname);
				if(parameterMeta != null)
				{
					parameterMeta.update(displayNode);
					parameterMeta.setDisplayCategory(categoryName);
				}
				else{
                                    logger.warn("Parameter " + paramname + " is missing in parameterMeta.");
                                }
					

				walker.parentNode();
			}
					
			nodeChild = walker.nextSibling();
		}// end of while
	}

     /**
      * Getter method that returns the name of the object the crop is associated
      * with.
      * @return The name of the object
      */     
	public String getObjectName()
	{
            return mObjectName;
	}
	
	/* This function is just for completion sake as the Meta class has this function.
	 * CropMeta does'nt have any actions
	 */
    /**
     * Getter method that returns the Meta objects for an action which are
     * visible in an operation_defn, operation_display, operation_lang, XML
     * files.
     * @param pIdentity Identity of the action object whose meta data is being
     * requested. The identity object is classified by CODE and ID
     * part.
     *
     * @return Returns the ActionMeta object that contains the meta data such
     * as parameter names, types, units that data is in etc. Also the
     * actionname could be retrieved which is again a part of that
     * meta data.
     */    
	public ActionMeta getActionMeta(Identity pIdentity)
	{
		return null;
	}


    /**
     * This is a getter method that fetches the vector containing the parameter
     * names for the crop.
     * @return The vector containing the parameter names.
     */    
	public List <String> getParameterNames()	
	{
		return mParameterNames;	
	}
    
	
    /**
     * This method fetches the ParameterMeta objects associated with a crop
     * having a parameter with name pParamName
     * @param pParamName The name of the parameter whose meta data is being requested.
     *
     * @return The object that consists the meta data for that parameter.
     */    
	public ParameterMeta getParameterMeta(String pParamName)
	{
		ParameterMeta paramMeta = (ParameterMeta)mParameters.get(pParamName);
		return paramMeta;
	} 	 

    /**
     * This method fetches the values held by parameter meta object in a crop 
     * meta object having parameter name pParamName and value name as pValueName
     * @param pParamName Name of the parameter whose value value is sought
     * @param pValueName The name of the value parameter whose data is being 
     * requested
     * @return The value part of the value parameter.
     */    
	public String getValue(String pParamName, String pValueName)
	{
		if(pParamName.equals(XMLConstants.sobjectname))
			return mObjectName;
		
		String value =null;
		
		ParameterMeta paramMeta = (ParameterMeta)mParameters.get(pParamName);
		if(paramMeta != null) {
			value = paramMeta.get(pValueName);
                }
		else{
                    logger.info("There is no parameter meta for parameter " + pParamName);
                }						

		return value;
	}
		
}
