/* ======================================================================
   Parts Copyright 2006 University of Leeds, Oxford University, University of the Highlands and Islands.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

====================================================================== */

package org.bodington.xml;

/**
 * @author Colin Tatham
 *
 */

import java.util.StringTokenizer;

import javax.xml.transform.TransformerException;

import org.w3c.dom.Node;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.apache.log4j.Logger;
import org.apache.xpath.CachedXPathAPI;
import org.bodington.util.TextUtils;

public class XMLMetadataUtils
{    
    private static Logger log = Logger.getLogger(XMLMetadataUtils.class);
    
    /**
     * Extracts comma delimited words from a string.
     * Used by code creating metadata keywords from user input.
     * @param keywords String containing delimited words
     * @return String array of separated words or null
     */
    public static String[] extractKeywordsFromString( String keywords )
    {
        if ( keywords != null )
        {
            StringTokenizer tokens = new StringTokenizer(keywords, ",");
            String[] keywordArray = new String[tokens.countTokens()];
            int n = 0;
            while (tokens.hasMoreTokens())
            {
                keywordArray[n] = tokens.nextToken().trim();
                n++;
            }
            return keywordArray;
        }
        
        return null;
    }
    
    /**
     * Produces comma separated list of keywords from keyword array.
     * Each array entry can be multiple words
     * @param fields Array of keywords.
     * @return StringBuffer of comma separated keywords
     */
    public static String getKeywordStringFromArray( String[] fields ) 
    {
        return TextUtils.join(fields, ", ");
    }
    
    /**
     * Gets value/s of the specified metadata field.
     * (Current fields in use are: title, description, author, date and keywords.)
     * @param doc Metadata document for the resource in scope
     * @param elementName name of metadata field
     * @return String array of value/s of field.
     */
    public static String[] getMetadataFieldValues( Document doc, String elementName )
    {
        if ( elementName.equals( "title" )) 
            return getTitleFieldValues( doc );
        
        if ( elementName.equals( "description" )) 
            return getDescriptionFieldValues( doc );
        
        if ( elementName.equals( "author" )) 
            return getAuthorFieldValues( doc );
        
        if ( elementName.equals( "date" )) 
            return getDateFieldValues( doc );
        
        if ( elementName.equals( "keywords" )) 
            return getKeywordsFieldValues( doc );
        
        return new String[0];
    }
    
    private static String[] getTitleFieldValues( Document doc )
    {
        String[] array = getRepeatingNodeValues( doc, "record/general/title", "/langstring/text()" );
        return array;
    }
    
    private static String[] getDescriptionFieldValues( Document doc )
    {        
        return getRepeatingNodeValues( doc, "record/general/description", "/langstring/text()" );
    }
    
    private static String[] getAuthorFieldValues( Document doc )
    {        
        return getRepeatingNodeValues( doc, "record/lifecycle/contribute", "/centity/vcard/text()" );
    }
    
    private static String[] getDateFieldValues( Document doc )
    {        
        return getRepeatingNodeValues( doc, "record/lifecycle/contribute", "/centity/date/datetime/text()" );
    }
    
    private static String[] getKeywordsFieldValues( Document doc )
    {   return getRepeatingNodeValues( doc, "record/classification/keywords", "/langstring/text()" );
    }
    
    private static String[] getRepeatingNodeValues( Node contextNode, String repeatingFieldXPath, String childXPath )
    {
        NodeList repeatableNode;
        String predicate;
        String[] data;
        
        CachedXPathAPI cachedXPath = new CachedXPathAPI();
        
        try
        {
            repeatableNode = cachedXPath.selectNodeList( contextNode, repeatingFieldXPath );
            
            if (repeatableNode.getLength() > 0)
            {
                data = new String[repeatableNode.getLength()];
                
                for (int i=1; i<=repeatableNode.getLength(); i++)
                {
                    predicate = repeatingFieldXPath + "["+ i +"]";
                    data[i-1] = getNodeValue(cachedXPath, contextNode, predicate + childXPath);
                }
                
                return data;
            }
        }
        catch (TransformerException e)
        {
            log.debug( "Error retrieving metadata nodes." );
        }
        
        return new String[0];
    }
    
    private static String getNodeValue(CachedXPathAPI cachedXPath, Node contextNode, String xpath)
    throws TransformerException
    {
        Node node = cachedXPath.selectSingleNode(contextNode, xpath);
        String data = node.getNodeValue();
        return data;
    }
}
