/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.xpath.functions;

import java.io.StringReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;

import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.SourceLocator;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;

import org.apache.xalan.templates.AVT;
import org.apache.xalan.templates.Constants;
import org.apache.xalan.templates.ElemAccept;
import org.apache.xalan.templates.ElemExpose;
import org.apache.xalan.templates.ElemFunction;
import org.apache.xalan.templates.ElemParam;
import org.apache.xalan.templates.ElemTemplate;
import org.apache.xalan.templates.ElemTemplateElement;
import org.apache.xalan.templates.ElemUsePackage;
import org.apache.xalan.templates.Stylesheet;
import org.apache.xalan.templates.StylesheetRoot;
import org.apache.xalan.templates.TemplateList;
import org.apache.xalan.templates.XMLNSDecl;
import org.apache.xalan.transformer.TransformerImpl;
import org.apache.xalan.xslt.util.XslTransformEvaluationHelper;
import org.apache.xerces.dom.DOMInputImpl;
import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
import org.apache.xerces.impl.dv.xs.XSSimpleTypeDecl;
import org.apache.xerces.impl.xs.XSLoaderImpl;
import org.apache.xerces.xs.XSModel;
import org.apache.xerces.xs.XSTypeDefinition;
import org.apache.xml.utils.DefaultErrorHandler;
import org.apache.xml.utils.QName;
import org.apache.xpath.Expression;
import org.apache.xpath.ExpressionNode;
import org.apache.xpath.XPath;
import org.apache.xpath.XPathContext;
import org.apache.xpath.XPathStaticContext;
import org.apache.xpath.axes.SelfIteratorNoPredicate;
import org.apache.xpath.compiler.FunctionTable;
import org.apache.xpath.compiler.Keywords;
import org.apache.xpath.composite.SequenceTypeData;
import org.apache.xpath.composite.SequenceTypeSupport;
import org.apache.xpath.composite.XPathExprFuncCallExtendedArg;
import org.apache.xpath.composite.XPathNamedFunctionReference;
import org.apache.xpath.functions.string.FuncConcat;
import org.apache.xpath.objects.InlineFunctionParameter;
import org.apache.xpath.objects.ResultSequence;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.objects.XPathInlineFunction;
import org.apache.xpath.types.XSBase64Binary;
import org.apache.xpath.types.XSByte;
import org.apache.xpath.types.XSGDay;
import org.apache.xpath.types.XSGMonth;
import org.apache.xpath.types.XSGMonthDay;
import org.apache.xpath.types.XSGYear;
import org.apache.xpath.types.XSGYearMonth;
import org.apache.xpath.types.XSHexBinary;
import org.apache.xpath.types.XSID;
import org.apache.xpath.types.XSIdRef;
import org.apache.xpath.types.XSLanguage;
import org.apache.xpath.types.XSNCName;
import org.apache.xpath.types.XSName;
import org.apache.xpath.types.XSNegativeInteger;
import org.apache.xpath.types.XSNmToken;
import org.apache.xpath.types.XSNonNegativeInteger;
import org.apache.xpath.types.XSNonPositiveInteger;
import org.apache.xpath.types.XSPositiveInteger;
import org.apache.xpath.types.XSShort;
import org.apache.xpath.types.XSUnsignedByte;
import org.apache.xpath.types.XSUnsignedInt;
import org.apache.xpath.types.XSUnsignedLong;
import org.apache.xpath.types.XSUnsignedShort;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;

import xml.xpath31.processor.types.XSAnyURI;
import xml.xpath31.processor.types.XSBoolean;
import xml.xpath31.processor.types.XSDate;
import xml.xpath31.processor.types.XSDateTime;
import xml.xpath31.processor.types.XSDayTimeDuration;
import xml.xpath31.processor.types.XSDecimal;
import xml.xpath31.processor.types.XSDouble;
import xml.xpath31.processor.types.XSDuration;
import xml.xpath31.processor.types.XSFloat;
import xml.xpath31.processor.types.XSInt;
import xml.xpath31.processor.types.XSInteger;
import xml.xpath31.processor.types.XSLong;
import xml.xpath31.processor.types.XSNormalizedString;
import xml.xpath31.processor.types.XSQName;
import xml.xpath31.processor.types.XSString;
import xml.xpath31.processor.types.XSTime;
import xml.xpath31.processor.types.XSToken;
import xml.xpath31.processor.types.XSUntypedAtomic;
import xml.xpath31.processor.types.XSYearMonthDuration;

/**
 * This class definition, provides support to evaluate XPath schema 
 * constructor function calls, evaluating XPath named function references, 
 * and evaluating XSL stylesheet xsl:function calls.
 * 
 * @author Mukul Gandhi <mukulg@apache.org>
 * 
 * @xsl.usage advanced
 */
public class XSL3FunctionService {
	
	/**
	 * Class field declarations, specifying constant values used by this
	 * implementation.
	 */
	
	public static final String UTF_8 = "UTF-8";
	
	public static final String UTF_16 = "UTF-16";
	
	public static final String XML_DOM_FORMAT_PRETTY_PRINT = "format-pretty-print";
	
	public static final String XS_VALID_TRUE = "XS_VALID_TRUE";
    
	/**
	 * Method definition, to evaluate a function call referred within an 
	 * XPath expression, excluding XPath built-in function calls which 
	 * are handled by their respective classes.
	 * 
	 * @param xpathExpr                   An XPath expression object
	 * @param transformerImpl             An XSL transformation TransformerImpl object
	 * @param xctxt                       An XPath context object
	 * @return                            An XPath function call result for functions
	 *                                    handled by this method.
	 * @throws TransformerException
	 */
    public XObject callFunction(XSL3ConstructorOrExtensionFunction xpathExpr,
    		                    TransformerImpl transformerImpl,
    		                    XPathContext xctxt) throws TransformerException {        
    	
    	XObject evalResult = null;

    	SourceLocator srcLocator = xctxt.getSAXLocator();
    	
    	final int sourceNode = xctxt.getCurrentNode();

    	try {        
    		XSL3ConstructorOrExtensionFunction funcObj = xpathExpr;
    		
    		String funcName = funcObj.getFunctionName();
    		String funcNamespace = funcObj.getNamespace();
    		
    		if (!((Constants.S_EXTENSIONS_JAVA_URL).equals(funcNamespace) || (Constants.S_EXTENSIONS_XALANLIB_URL).equals(funcNamespace))) {
    			/**
    			 * XPath constructor (prefix:typeName) and XSL stylesheet function
    			 * calls (xsl:function), are syntactically similar to Xalan-J XPath
    			 * extension function calls (prefix:functionName). The implementation
    			 * here need not run when an XSL stylesheet specifies Xalan-J XPath
    			 * extension function call.
    			 */    			
    			
    			StylesheetRoot stylesheetRoot = XslTransformEvaluationHelper.getXslStylesheetRootFromXslElementRef(
    					                                                                                   (ElemTemplateElement)xpathExpr.getExpressionOwner());

    			if (stylesheetRoot != null) {
    				if (transformerImpl == null) {
    					transformerImpl = stylesheetRoot.getTransformerImpl();  
    				}

    				TemplateList templateList = stylesheetRoot.getTemplateListComposed();

    				Vector argVector = funcObj.getArgVector();
    				int xslFuncArgCount = 0;
    				ResultSequence xslFuncArgSequence = new ResultSequence();
    				List<String> funcExtArgStrList = null;
    				int argCount = argVector.size();
    				for (int idx = 0; idx < argCount; idx++) {
    					Expression argExpr = (Expression)(argVector.elementAt(idx));
    					if (argExpr instanceof XPathExprFuncCallExtendedArg) {    						    						
    						XPathExprFuncCallExtendedArg xpathExprFuncCallExtendedArg = (XPathExprFuncCallExtendedArg)argExpr;
    						funcExtArgStrList = xpathExprFuncCallExtendedArg.getFunctionArgXPathExprStrList();
    					}
    					else {    						    						
    						XObject xslFuncArgVal = null;
    						if (argExpr instanceof XPathNamedFunctionReference) {     							
    							xslFuncArgVal = (XPathNamedFunctionReference)argExpr;
    						}
    						else if ((argExpr instanceof SelfIteratorNoPredicate) && (xctxt.getXPath3ContextItem() != null)) {
    							xslFuncArgVal = xctxt.getXPath3ContextItem(); 
    						}
    						else {
    							xslFuncArgVal = argExpr.execute(xctxt); 	
    						}
    						
    						xslFuncArgSequence.add(xslFuncArgVal);
    						xslFuncArgCount++;
    					}
    				}

    				ElemTemplate elemTemplate = templateList.getXslFunction(new QName(funcNamespace, funcName), xslFuncArgCount);
    				
    				if (elemTemplate == null) { 
    					elemTemplate = getXslFunctionDeclUsingXslPackage(transformerImpl, funcNamespace, 
    							                                                                      funcName, xslFuncArgCount);
    			    }

    				if ((elemTemplate != null) && (elemTemplate instanceof ElemFunction)) {
    					// Evaluate an XSL stylesheet function call
    					
    					ElemFunction elemFunction = (ElemFunction)elemTemplate;
    					    					
    					XPath useWhenExpr = elemFunction.getUseWhen();
                        if (useWhenExpr != null) {
                        	XObject xObj = useWhenExpr.execute(xctxt, sourceNode, xctxt.getNamespaceContext());
                        	if (xObj.bool()) {
                        	   evalResult = elemFunction.evaluateXslFunction(transformerImpl, xslFuncArgSequence);
                        	}                        	
                        }
                        else {
                        	Stylesheet stylesheet3 = elemTemplate.getStylesheet();
                        	if (stylesheet3 != null) {
                        	   StylesheetRoot stylesheetRoot2 = stylesheet3.getStylesheetRoot();
                        	   transformerImpl = stylesheetRoot2.getTransformerImpl();
                        	   if (transformerImpl == null) {
                        	      transformerImpl = new TransformerImpl(stylesheetRoot2);
                        	   }
                        	}
                        	
    					    evalResult = elemFunction.evaluateXslFunction(transformerImpl, xslFuncArgSequence);
                        }

    					if ((evalResult instanceof XPathNamedFunctionReference) && (funcExtArgStrList != null)) {
    						XPathNamedFunctionReference xpathNamedFunctionReference = (XPathNamedFunctionReference)evalResult;    					   
    						String localName = xpathNamedFunctionReference.getFuncName();
    						String namespace = xpathNamedFunctionReference.getFuncNamespace();
    						Short arity = xpathNamedFunctionReference.getArity();    					   
    						if ((int)arity == funcExtArgStrList.size()) {
    							if ((XPathStaticContext.XPATH_BUILT_IN_FUNCS_NS_URI).equals(namespace) || (XPathStaticContext.XPATH_BUILT_IN_MATH_FUNCS_NS_URI).equals(namespace) ||
    									                                                                   (XPathStaticContext.XPATH_BUILT_IN_MAP_FUNCS_NS_URI).equals(namespace) || 
    									                                                                   (XPathStaticContext.XPATH_BUILT_IN_ARRAY_FUNCS_NS_URI).equals(namespace)) {
    								FunctionTable funcTable = xctxt.getFunctionTable();
    								Object funcId = funcTable.getFunctionId(localName);
    								if (funcId != null) {
    									Function function = funcTable.getFunction(Integer.valueOf(funcId.toString()));
    									List<Short> funcDefinedArity = Arrays.asList(function.getDefinedArity());
    									if (funcDefinedArity.contains(arity)) {
    										int argCount2 = funcExtArgStrList.size();
    										for (int idx = 0; idx < argCount2; idx++) {
    											String xpathExprStr = funcExtArgStrList.get(idx);
    											XPath argXPath = new XPath(xpathExprStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);    									   
    											try {
    												function.setArg(argXPath.getExpression(), idx);
    											} 
    											catch (WrongNumberArgsException ex) {
    												// no op
    											}    									
    										}

    										evalResult = function.execute(xctxt);
    									}
    									else {
    										throw new TransformerException("XPTY0004 : The function arity value specified in an XPath named "
									    												+ "function reference is " + arity + ", but the corresponding "
									    												+ "XPath function {" + namespace + "}" + localName + " doesn't allow this arity.", srcLocator);  
    									}
    								}
    								else {
    									throw new TransformerException("XPTY0004 : The function {" + namespace + "}" + localName + " referred "
    																					+ "within an XPath expression is not found.", srcLocator); 
    								}
    							}
    						}
    						else {
    							throw new TransformerException("XPTY0004 : The number of arguments provided during an XPath function call {" + namespace + "}" + localName 
												    									+ " is " + funcExtArgStrList.size() + ", but the corresponding XPath named function "
												    									+ "reference specifies the function arity value as " + arity + ".", srcLocator); 
    						}
    					}
    					else if ((evalResult instanceof XPathInlineFunction) && (funcExtArgStrList != null)) {
    						int paramIdx = 0;    						
    						Map<QName, XObject> xpathVarMap = xctxt.getXPathVarMap();    						
    						for (ElemTemplateElement elem = elemFunction.getFirstChildElem(); elem != null; 
    								elem = elem.getNextSiblingElem()) {
    							if (elem.getXSLToken() == Constants.ELEMNAME_PARAMVARIABLE) {
    								ElemParam elemParam = (ElemParam)elem;
    								QName paramName = elemParam.getName();
    								XObject argValue = xslFuncArgSequence.item(paramIdx);
    								xpathVarMap.put(paramName, argValue);
    								paramIdx++;
    							}
    							else {
    								break; 
    							}
    						}

    						XPathInlineFunction xpathInlineFunction = (XPathInlineFunction)evalResult;

    						List<String> xpathInlineFuncArgList = new ArrayList<String>(); 
    						int argCount2 = funcExtArgStrList.size();
    						for (int idx = 0; idx < argCount2; idx++) {
    							String xpathExprStr = funcExtArgStrList.get(idx);								
    							xpathInlineFuncArgList.add(xpathExprStr);    							
    						}

    						List<XMLNSDecl> prefixTable = null;
    						ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();

    						if (elemTemplateElement != null) {
    							prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
    						}

    						evalResult = evaluateXPathInlineFunction(xpathInlineFunction, xpathInlineFuncArgList, 
    								                                                      xctxt, prefixTable, null, 0, 
    								                                                      ((Expression)xpathExpr).getXPathVarList(), null);    						
    					}

    					return evalResult;
    			    }    				
    			}

    			if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(funcNamespace)) {                
    				// Evaluate XPath constructor function call, for schema types 
    				// within XML Schema namespace.

    				ResultSequence argSequence = new ResultSequence();
    				ResultSequence evalResultSequence = null;

    				try {
    					switch (funcName) {
    					case Keywords.XS_STRING :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSString.class, xctxt);
    						break;
    					case Keywords.XS_NORMALIZED_STRING :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSNormalizedString.class, xctxt);
    						break;
    					case Keywords.XS_TOKEN :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSToken.class, xctxt);
    						break;
    					case Keywords.XS_DECIMAL :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSDecimal.class, xctxt);
    						break;
    					case Keywords.XS_FLOAT :  					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSFloat.class, xctxt);
    						break;
    					case Keywords.XS_DOUBLE :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSDouble.class, xctxt);    						
    						Expression argExpr = funcObj.getArg(0);    						
    						String argStr1 = getXPathBuiltInConstructorFunctionArgStr(argExpr, xctxt);
    						evalResult.setConsFuncArgStr(argStr1);
    						break;
    					case Keywords.XS_INTEGER :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSInteger.class, xctxt);    					
    						break;
    					case Keywords.XS_NON_POSITIVE_INTEGER :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSNonPositiveInteger.class, xctxt);
    						break;
    					case Keywords.XS_NEGATIVE_INTEGER :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSNegativeInteger.class, xctxt);
    						break;
    					case Keywords.XS_NON_NEGATIVE_INTEGER :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSNonNegativeInteger.class, xctxt);
    						break;
    					case Keywords.XS_POSITIVE_INTEGER :    					 
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSPositiveInteger.class, xctxt);
    						break;
    					case Keywords.XS_LONG :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSLong.class, xctxt);
    						break;
    					case Keywords.XS_INT :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSInt.class, xctxt);
    						break;
    					case Keywords.XS_SHORT :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSShort.class, xctxt);
    						break;
    					case Keywords.XS_BYTE :
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSByte.class, xctxt);
    						break;
    					case Keywords.XS_UNSIGNED_LONG :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSUnsignedLong.class, xctxt);
    						break;
    					case Keywords.XS_UNSIGNED_INT :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSUnsignedInt.class, xctxt);
    						break;
    					case Keywords.XS_UNSIGNED_SHORT :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSUnsignedShort.class, xctxt);
    						break;
    					case Keywords.XS_UNSIGNED_BYTE :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSUnsignedByte.class, xctxt);
    						break;
    					case Keywords.XS_GYEAR_MONTH :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSGYearMonth.class, xctxt);
    						break;
    					case Keywords.XS_GYEAR :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSGYear.class, xctxt);
    						break;
    					case Keywords.XS_GMONTH_DAY :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSGMonthDay.class, xctxt);
    						break;
    					case Keywords.XS_GDAY :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSGDay.class, xctxt);
    						break;
    					case Keywords.XS_GMONTH :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSGMonth.class, xctxt);
    						break;
    					case Keywords.XS_BASE64BINARY :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSBase64Binary.class, xctxt);
    						break;
    					case Keywords.XS_HEXBINARY :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSHexBinary.class, xctxt);
    						break;
    					case Keywords.XS_LANGUAGE :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSLanguage.class, xctxt);
    						break;
    					case Keywords.XS_NAME :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSName.class, xctxt);
    						break;
    					case Keywords.XS_NCNAME :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSNCName.class, xctxt);
    						break;
    					case Keywords.XS_NMTOKEN :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSNmToken.class, xctxt);
    						break;
    					case Keywords.XS_ID :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSID.class, xctxt);
    						break;
    					case Keywords.XS_IDREF :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSIdRef.class, xctxt);
    						break;
    					case Keywords.FUNC_BOOLEAN_STRING :    					
    						for (int idx = 0; idx < funcObj.getArgCount(); idx++) {
    							Expression funcArg = funcObj.getArg(idx);    						
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							Boolean boolVal = Boolean.valueOf(("0".equals(argStr) || "false".equals(argStr)) ? "false" : "true");
    							argSequence.add(new XSBoolean(boolVal));
    						}
    						evalResultSequence = (new XSBoolean()).constructor(argSequence);
    						evalResult = evalResultSequence.item(0);

    						break;
    					case Keywords.XS_DATE :
    						for (int idx = 0; idx < funcObj.getArgCount(); idx++) {
    							Expression funcArg = funcObj.getArg(idx);    						
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							
    							argSequence.add(XSDate.parseDate(argStr));
    						}
    						evalResultSequence = (new XSDate()).constructor(argSequence); 
    						evalResult = evalResultSequence.item(0);

    						break;
    					case Keywords.XS_DATETIME :
    						for (int idx = 0; idx < funcObj.getArgCount(); idx++) {
    							Expression funcArg = funcObj.getArg(idx);    						
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							
    							argSequence.add(XSDateTime.parseDateTime(argStr));
    						}
    						evalResultSequence = (new XSDateTime()).constructor(argSequence); 
    						evalResult = evalResultSequence.item(0);

    						break;
    					case Keywords.XS_DURATION :
    						for (int idx = 0; idx < funcObj.getArgCount(); idx++) {
    							Expression funcArg = funcObj.getArg(idx);    						
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							XSDuration xsDuration = XSDuration.parseDuration(argStr);
    							if (xsDuration != null) {
    								argSequence.add(xsDuration);
    								evalResultSequence = (new XSDuration()).constructor(argSequence); 
    								evalResult = evalResultSequence.item(0);
    							}
    							else {
    								throw new TransformerException("FORG0001 : An incorrectly formatted xs:duration value '" + 
    																									argStr + "' is present in the input.", srcLocator); 
    							}
    						}

    						break;
    					case Keywords.XS_YEAR_MONTH_DURATION :                   
    						for (int idx = 0; idx < funcObj.getArgCount(); idx++) {
    							Expression funcArg = funcObj.getArg(idx);    						
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							XSDuration xsDuration = XSYearMonthDuration.parseYearMonthDuration(argStr);
    							if (xsDuration != null) {
    								argSequence.add(xsDuration);
    								evalResultSequence = (new XSYearMonthDuration()).constructor(argSequence); 
    								evalResult = evalResultSequence.item(0);
    							}
    							else {
    								throw new TransformerException("FORG0001 : An incorrectly formatted xs:yearMonthDuration value '" + 
    																									argStr + "' is present in the input.", srcLocator); 
    							}
    						}

    						break;
    					case Keywords.XS_DAY_TIME_DURATION :                 
    						for (int idx = 0; idx < funcObj.getArgCount(); idx++) {
    							Expression funcArg = funcObj.getArg(idx);    						
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							XSDuration xsDuration = XSDayTimeDuration.parseDayTimeDuration(argStr);
    							if (xsDuration != null) {
    								argSequence.add(xsDuration);
    								evalResultSequence = (new XSDayTimeDuration()).constructor(argSequence); 
    								evalResult = evalResultSequence.item(0);
    							}
    							else {
    								throw new TransformerException("FORG0001 : An incorrectly formatted xs:dayTimeDuration value '" + 
    																									argStr + "' is present in the input.", srcLocator); 
    							}                            
    						}

    						break;
    					case Keywords.XS_TIME :                 
    						for (int idx = 0; idx < funcObj.getArgCount(); idx++) {
    							Expression funcArg = funcObj.getArg(idx);    						
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							XSTime xsTime = XSTime.parseTime(argStr);
    							if (xsTime != null) {
    								argSequence.add(xsTime);
    								evalResultSequence = (new XSTime()).constructor(argSequence); 
    								evalResult = evalResultSequence.item(0);
    							}
    							else {
    								throw new TransformerException("FORG0001 : An incorrectly formatted xs:time value '" + 
    																									argStr + "' is present in the input.", srcLocator); 
    							}                            
    						}

    						break;
    					case Keywords.XS_ANY_URI :    					
    						evalResult = evaluateXPathBuiltInConstructorFunctionCall(funcObj, XSAnyURI.class, xctxt);
    						break;
    					case Keywords.XS_QNAME :		    					
    						int argCount = funcObj.getArgCount();		    					
    						if (argCount == 1) {
    							Expression funcArg = funcObj.getArg(0);
    							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    							int colonIdx = argStr.indexOf(':');
    							String prefix = null;
    							String localName = null;
    							String namespaceUri = null;
    							if (colonIdx > -1) {
    								prefix = argStr.substring(0, colonIdx);
    								localName = argStr.substring(colonIdx + 1);
    							}
    							else {
    								localName = argStr; 
    							}

    							if (prefix != null) {
    								List<XMLNSDecl> prefixTable = null;
    								ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();

    								if (elemTemplateElement != null) {
    									prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
    								}

    								if (prefixTable != null) {
    									int prefixTableSize = prefixTable.size();
    									for (int idx = 0; idx < prefixTableSize; idx++) {
    										XMLNSDecl xmlNSDecl = prefixTable.get(idx);
    										String prefix1 = xmlNSDecl.getPrefix();
    										String uri1 = xmlNSDecl.getURI();
    										if (prefix1.equals(prefix)) {
    											namespaceUri = uri1;		    					    				
    											break;
    										}
    									}
    								}
    							}

    							evalResult = new XSQName(prefix, localName, namespaceUri);
    						}
    						else if (argCount == 2) {		    					    		    					    
    							String prefix = getXPathBuiltInConstructorFunctionArgStr(funcObj.getArg(0), xctxt);
    							String localName = getXPathBuiltInConstructorFunctionArgStr(funcObj.getArg(1), xctxt);

    							List<XMLNSDecl> prefixTable = null;
    							ElemTemplateElement elemTemplateElement = (ElemTemplateElement)xctxt.getNamespaceContext();

    							if (elemTemplateElement != null) {
    								prefixTable = (List<XMLNSDecl>)elemTemplateElement.getPrefixTable();
    							}

    							String namespaceUri = null;
    							if (prefixTable != null) {
    								int prefixTableSize = prefixTable.size();
    								for (int idx = 0; idx < prefixTableSize; idx++) {
    									XMLNSDecl xmlNSDecl = prefixTable.get(idx);
    									String prefix1 = xmlNSDecl.getPrefix();
    									String uri1 = xmlNSDecl.getURI();
    									if (prefix1.equals(prefix)) {
    										namespaceUri = uri1;		    					    				
    										break;
    									}
    								}
    							}

    							evalResult = new XSQName(prefix, localName, namespaceUri);
    						}
    						else if (argCount == 3) {
    							String prefix = getXPathBuiltInConstructorFunctionArgStr(funcObj.getArg(0), xctxt);
    							String localName = getXPathBuiltInConstructorFunctionArgStr(funcObj.getArg(1), xctxt);
    							String namespaceUri = getXPathBuiltInConstructorFunctionArgStr(funcObj.getArg(2), xctxt);
    							evalResult = new XSQName(prefix, localName, namespaceUri);
    						}

    						break;
    					case Keywords.XS_UNTYPED_ATOMIC :
    						Expression funcArg = funcObj.getArg(0);    						
							String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
    						
    						evalResult = new XSUntypedAtomic(argStr);
    					default:
    						// no op
    					}
    				}
    				catch (Exception ex) {
    					String exceptionMesgStr = null;
    					if (ex instanceof InvocationTargetException) {
    						Throwable throwable = ((InvocationTargetException)ex).getTargetException();
    						exceptionMesgStr = throwable.getMessage();
    					}
    					else {
    						exceptionMesgStr = (ex.getMessage() != null) ? ex.getMessage() : "";
    					}

    					exceptionMesgStr = exceptionMesgStr.equals("") ? "" : (exceptionMesgStr + ".");
    					if (exceptionMesgStr.endsWith("..")) {
    						exceptionMesgStr = exceptionMesgStr.substring(0, exceptionMesgStr.length() - 1); 
    					}

    					String errMesgStrTrailingSuffix = ((exceptionMesgStr != null) && (exceptionMesgStr.length() > 0)) ? " "+ exceptionMesgStr : ""; 

    					throw new TransformerException("FODC0005 : An XPath dynamic error has occured, evaluating "
																	    							+ "constructor function call for xs:" + funcName + "." + 
																	    							errMesgStrTrailingSuffix, srcLocator);
    				}
    			}
    			else {
    				// We check and evaluate below, XPath constructor function calls to 
    				// XML Schema user-defined simple types.

    				Node elemTemplateElem = stylesheetRoot.getFirstChildElem();

    				while (elemTemplateElem != null && !(Constants.ELEMNAME_IMPORT_SCHEMA_STRING).equals(elemTemplateElem.getLocalName())) {   
    					elemTemplateElem = elemTemplateElem.getNextSibling();
    				}

    				if (elemTemplateElem != null) {
    					NodeList nodeList = elemTemplateElem.getChildNodes();
    					Node xsSchemaTopMostNode = nodeList.item(0);    					

    					if (xsSchemaTopMostNode != null) {    						
    						// xsl:import-schema instruction's child contents, has 
    						// XML Schema document available as string value.

    						String xmlSchemaDocumentStr = null;

    						XSModel xsModel = null;        		   
    						XSLoaderImpl xsLoader = new XSLoaderImpl();

    						try {
    							DOMImplementationLS domImplLS = (DOMImplementationLS)((DOMImplementationRegistry.newInstance()).getDOMImplementation("LS"));
    							LSSerializer lsSerializer = domImplLS.createLSSerializer();
    							DOMConfiguration domConfig = lsSerializer.getDomConfig();
    							domConfig.setParameter(XML_DOM_FORMAT_PRETTY_PRINT, Boolean.TRUE);
    							xmlSchemaDocumentStr = lsSerializer.writeToString((Document)xsSchemaTopMostNode);
    							xmlSchemaDocumentStr = xmlSchemaDocumentStr.replaceFirst(UTF_16, UTF_8);
    							xmlSchemaDocumentStr = xmlSchemaDocumentStr.replaceFirst("schema", "schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\"");

    							DOMInputImpl lsInput = new DOMInputImpl();
    							lsInput.setCharacterStream(new StringReader(xmlSchemaDocumentStr));

    							xsModel = xsLoader.load(lsInput);    						

    							if (xsModel != null) {
    								XSTypeDefinition xsTypeDefinition = xsModel.getTypeDefinition(funcName, funcNamespace);
    								if (xsTypeDefinition != null) {
    									XSSimpleTypeDecl xsSimpleTypeDecl = (XSSimpleTypeDecl)xsTypeDefinition;
    									XObject xsSimpleTypeInpObj = (funcObj.getArg(0)).execute(xctxt);
    									String argStrVal = XslTransformEvaluationHelper.getStrVal(xsSimpleTypeInpObj);
    									xsSimpleTypeDecl.validate(argStrVal, null, null);
    									evalResult = new XSString(XS_VALID_TRUE);
    									evalResult.setObject(argStrVal);
    									evalResult.setXsTypeDefinition(xsTypeDefinition);    								}
    								else {
    									throw new javax.xml.transform.TransformerException("FODC0005 : There's no in-scope schema type definition available "
    																													+ "with name {" + funcNamespace + "}:" 
    											                                                                        + funcName + ".", srcLocator);							
    								}	    							    						
    							}
    							else {
    								throw new javax.xml.transform.TransformerException("FODC0005 : While processing XSL import-schema instruction, a compiled "
    										                                                                            + "representation of an XML Schema document "
    										                                                                            + "could not be built.", srcLocator);
    							}
    						}
    						catch (InvalidDatatypeValueException ex) {
    							throw new TransformerException(ex.getMessage(), srcLocator); 
    						}
    						catch (Exception ex) {
    							throw new TransformerException(ex.getMessage(), srcLocator);
    						} 
    					}
    					else {
    						// Use an XML Schema document available, at the uri specified by xsl:import-schema 
    						// element's attribute 'schema-location'.

    						XSModel xsModel = null;        		   
    						XSLoaderImpl xsLoader = new XSLoaderImpl();

    						NamedNodeMap importSchemaNodeAttributes = ((Element)elemTemplateElem).getAttributes();        			   

    						if (importSchemaNodeAttributes != null) {
    							Node attrNode1 = importSchemaNodeAttributes.item(0);
    							Node attrNode2 = importSchemaNodeAttributes.item(1);	        			   	        			   	        			   

    							try {
    								if (attrNode1 != null) {
    									URI inpUri = new URI(attrNode1.getNodeValue());
    									String stylesheetSystemId = srcLocator.getSystemId();

    									if (!inpUri.isAbsolute() && (stylesheetSystemId != null)) {
    										URI resolvedUri = (new URI(stylesheetSystemId)).resolve(inpUri);
    										URL url = resolvedUri.toURL(); 
    										if (!"namespace".equals(attrNode1.getNodeName())) {
    											xsModel = xsLoader.loadURI(url.toString());
    										}
    									}
    								}

    								if (attrNode2 != null && xsModel == null) {
    									URI inpUri = new URI(attrNode2.getNodeValue());
    									String stylesheetSystemId = srcLocator.getSystemId();

    									if (!inpUri.isAbsolute() && (stylesheetSystemId != null)) {
    										URI resolvedUri = (new URI(stylesheetSystemId)).resolve(inpUri);
    										URL url = resolvedUri.toURL();
    										if ("schema-location".equals(attrNode2.getNodeName())) {
    											xsModel = xsLoader.loadURI(url.toString());
    										}
    									}	        				  
    								}

    								if (xsModel != null) {
    									XSTypeDefinition xsTypeDefinition = xsModel.getTypeDefinition(funcName, funcNamespace);
    									if (xsTypeDefinition != null) {
    										XSSimpleTypeDecl xsSimpleTypeDecl = (XSSimpleTypeDecl)xsTypeDefinition;
    										XObject xsSimpleTypeInpObj = (funcObj.getArg(0)).execute(xctxt);
    										String argStrVal = XslTransformEvaluationHelper.getStrVal(xsSimpleTypeInpObj);
    										xsSimpleTypeDecl.validate(argStrVal, null, null);
    										evalResult = new XSString(XS_VALID_TRUE);
    										evalResult.setObject(argStrVal);
    										evalResult.setXsTypeDefinition(xsTypeDefinition);
    									}
    									else {
    										throw new javax.xml.transform.TransformerException("FODC0005 : There's no in-scope schema type definition available "
    																														+ "with name {" + funcNamespace + "}:" 
    												                                                                        + funcName + ".", srcLocator);							
    									}
    								}
    								else {
    									throw new javax.xml.transform.TransformerException("FODC0005 : While processing XSL import-schema instruction, a compiled "
    											                                                                            + "representation of an XML Schema document "
    											                                                                            + "could not be built.", srcLocator);
    								}
    							}
    							catch (URISyntaxException ex) {
    								throw new javax.xml.transform.TransformerException("FODC0005 : The schema uri specified with XSL import-schema instruction "
    										                                                                                + "is not a valid absolute uri, or cannot "
    										                                                                                + "be resolved to an absolute uri.", srcLocator);   
    							}
    							catch (MalformedURLException ex) {
    								throw new javax.xml.transform.TransformerException("FODC0005 : The schema uri specified with XSL import-schema instruction "
    										                                                                                + "is not a valid absolute uri, or cannot be "
    										                                                                                + "resolved to an absolute uri.", srcLocator); 
    							}
    							catch (InvalidDatatypeValueException ex) {
    								throw new TransformerException(ex.getMessage(), srcLocator);
    							}
    						}	            				 
    					}	            			
    				}
    			}
    		}
    	}
    	catch (TransformerException ex) {
    		String errMesg = ex.getMessage();
    		SourceLocator srcLocatorTemp = ex.getLocator();
    		if (srcLocatorTemp == null) {
    			srcLocatorTemp = srcLocator; 	
    		}
    		
    		throw new TransformerException(errMesg, srcLocatorTemp);
    	}

    	return evalResult;        
    }
    
    /**
     * Method definition to check, whether function arity of the function 
     * to be called is well-formed, for named function references specified 
     * with syntax functionNameString#integerLiteral.
     */
    public boolean isFuncArityWellFormed(String funcRefStr) {	      	
    	boolean isFuncArityWellFormed = true;

    	int idx = funcRefStr.indexOf('#');
    	String intStr = funcRefStr.substring(idx + 1);
    	Integer intVal = null;
    	try {
    		intVal = Integer.valueOf(intStr);
    		if (intVal < 0) {
    			isFuncArityWellFormed = false;
    		}
    	}
    	catch (NumberFormatException ex) {
    		isFuncArityWellFormed = false; 
    	}

    	return isFuncArityWellFormed;
    }
    
    /**
     * Method definition to evaluate an XPath named function reference.
     * 
     * @param xpathNamedFuncRef                 An XPath compiled named function reference object
     * @param argList                           List of argument XPath expressions for the function call
     * @param argSeq                            List of compiled function argument object instances
     * @param prefixTable                       An XML prefix table list object reference containing
     *                                          an XSL context namespace binding information.
     * @param varVecor                          Variable name declaration vector
     * @param varGlobalsSize                    Variable declaration count information                     
     * @param xctxt							    An XPath context object                                          
     * @return									The result of evaluation of an XPath named function
     *                                          reference.
     * @throws TransformerException
     */
    public XObject evaluateXPathNamedFunctionReference(XPathNamedFunctionReference xpathNamedFuncRef, 
    		                                           List<String> argList, ResultSequence argSeq, List<XMLNSDecl> prefixTable, 
    		                                           Vector varVecor, int varGlobalsSize, ExpressionNode expressionNode, 
    		                                           XPathContext xctxt) throws TransformerException {
    	
    	XObject evalResult = null;

    	SourceLocator srcLocator = xctxt.getSAXLocator();

    	int contextNode = xctxt.getCurrentNode(); 

    	String funcNamespace = xpathNamedFuncRef.getFuncNamespace();
    	String funcLocalName = xpathNamedFuncRef.getFuncName();
    	int funcArity = 0;           
    	if ((XPathStaticContext.XPATH_BUILT_IN_FUNCS_NS_URI).equals(funcNamespace) && 
    																		     (Keywords.FUNC_CONCAT_STRING).equals(funcLocalName)) {
    		funcArity = xpathNamedFuncRef.getConcatArity();
    	}
    	else {
    		funcArity = xpathNamedFuncRef.getArity(); 
    	}

    	String funcQualifiedName = "{" + funcNamespace + "}" + funcLocalName; 

    	FunctionTable funcTable = xctxt.getFunctionTable();

    	Object funcIdObj = null;
    	if (XPathStaticContext.XPATH_BUILT_IN_FUNCS_NS_URI.equals(funcNamespace)) {
    		funcIdObj = funcTable.getFunctionId(funcLocalName);
    	}
    	else if (XPathStaticContext.XPATH_BUILT_IN_MATH_FUNCS_NS_URI.equals(funcNamespace)) {
    		funcIdObj = funcTable.getFunctionIdForXPathBuiltinMathFuncs(funcLocalName);
    	}
    	else if (XPathStaticContext.XPATH_BUILT_IN_MAP_FUNCS_NS_URI.equals(funcNamespace)) {
    		funcIdObj = funcTable.getFunctionIdForXPathBuiltinMapFuncs(funcLocalName);
    	}
    	else if (XPathStaticContext.XPATH_BUILT_IN_ARRAY_FUNCS_NS_URI.equals(funcNamespace)) {
    		funcIdObj = funcTable.getFunctionIdForXPathBuiltinArrayFuncs(funcLocalName);
    	}

    	if (funcIdObj != null) {
    		// Evaluate an XPath built-in function reference
    		
    		String funcIdStr = funcIdObj.toString();
    		Function function = funcTable.getFunction(Integer.valueOf(funcIdStr));
    		function.setLocalName(funcLocalName);
    		function.setNamespace(funcNamespace);
    		if (function instanceof FuncConcat) {
    		    ((FuncConcat)function).setActualArity(funcArity);
    		}
    		else {
    			function.setDefinedArity(new Short[] { (short)funcArity });
    		}

    		int argCount = 0;
    		if (argList != null) {
    		   argCount = argList.size();
    		}
    		else if (argSeq != null) {
    		   argCount = argSeq.size();	
    		}
    		
    		for (int idx = 0; idx < argCount; idx++) {
    			try {
    				if (argList != null) {
    					String argXPathStr = argList.get(idx);
    					if (prefixTable != null) {
    						argXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(argXPathStr, prefixTable);
    					}

    					XPath argXPath = new XPath(argXPathStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
    					if (varVecor != null) {
    						argXPath.fixupVariables(varVecor, varGlobalsSize);
    					}

    					function.setArg(argXPath.getExpression(), idx);
    				}
    				else {
    					XObject arg1 = argSeq.item(idx);
    					function.setArg(arg1, idx);
    				}
    			}
    			catch (WrongNumberArgsException ex) {
    				String funcName = "{" + funcNamespace + "}" + funcLocalName; 
    				throw new TransformerException("FODC0005 : Wrong number of arguments, provided during function call for " + funcName + ".", srcLocator);
    			}
    		}

    		evalResult = function.execute(xctxt);
    	}
    	else if (xpathNamedFuncRef.getXslStylesheetFunction() != null) {
    		// Evaluate an XSL stylesheet function reference
    		
    		ElemFunction elemFunction = xpathNamedFuncRef.getXslStylesheetFunction();

    		ResultSequence argSequence = new ResultSequence();
    		int argCount = argList.size();
    		for (int idx = 0; idx < argCount; idx++) {
    			String argXPathStr = argList.get(idx);
    			if (prefixTable != null) {
    				argXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(argXPathStr, prefixTable);
    			}

    			XPath argXPath = new XPath(argXPathStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
    			if (varVecor != null) {
    				argXPath.fixupVariables(varVecor, varGlobalsSize);
    			}

    			try {
    				XObject argValue = argXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
    				argSequence.add(argValue);
    			} 
    			catch (TransformerException ex) {							
    				throw new TransformerException(ex.getMessage(), srcLocator);
    			}
    		}

    		ExpressionNode stylesheetRootNode = null;    		
    		while (expressionNode != null) {
    			stylesheetRootNode = expressionNode;
    			expressionNode = expressionNode.exprGetParent();                     
    		}

    		StylesheetRoot stylesheetRoot = (StylesheetRoot)stylesheetRootNode;

    		if (stylesheetRoot != null) {
    			TransformerImpl transformerImpl = stylesheetRoot.getTransformerImpl();

    			evalResult = elemFunction.evaluateXslFunction(transformerImpl, argSequence);
    		}
    		else {
    			evalResult = new ResultSequence();  
    		}
    	}
    	else if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(funcNamespace)) {
    		// Evaluate an XPath schema type constructor function call reference
    		
    		XSL3ConstructorOrExtensionFunction funcObj = new XSL3ConstructorOrExtensionFunction(funcNamespace, funcLocalName, null);
    		funcObj.setDefinedArity(new Short[] { (short)funcArity });

    		int argCount = argList.size();
    		for (int idx = 0; idx < argCount; idx++) {
    			String argXPathStr = argList.get(idx);
    			if (prefixTable != null) {
    				argXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(argXPathStr, prefixTable);
    			}

    			XPath argXPath = new XPath(argXPathStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
    			if (varVecor != null) {
    				argXPath.fixupVariables(varVecor, varGlobalsSize);
    			}

    			try {
    				funcObj.setArg(argXPath.getExpression(), idx);
    			} 
    			catch (WrongNumberArgsException ex) {							
    				String funcName = "{" + funcNamespace + "}" + funcLocalName; 
    				throw new TransformerException("FODC0005 : Wrong number of arguments, provided during function call for " + funcName + ".", srcLocator);
    			}
    		}

    		evalResult = funcObj.execute(xctxt);        		  
    	}
    	else {
    		throw new TransformerException("FODC0005 : An XSL function definition for named function reference " + funcQualifiedName + 
    				                                                                                 " doesn't exist.", srcLocator);
    	}
    	
    	return evalResult;
	}
    
    /**
     * Method definition to get an object instance of XPath built-in function.
     * 
     * @param funcName								Function name's string value
     * @param funcNamespace							Function's XML namespace string value	
     * @param xctxt									An XPath context object
     * @return										Function object instance 
     * @throws TransformerException
     */
    public Function getXPathBuiltInFunction(String funcName, String funcNamespace, XPathContext xctxt) throws TransformerException {
        
    	Function result = null;
        
        FunctionTable funcTable = xctxt.getFunctionTable();
        
        if ((XPathStaticContext.XPATH_BUILT_IN_FUNCS_NS_URI).equals(funcNamespace)) {
           Object funcId = funcTable.getFunctionIdForXPathBuiltinFuncs(funcName);
           int funcIdValue = (int)Integer.valueOf(funcId.toString());
           result = funcTable.getFunction(funcIdValue);
        }
        else if ((XPathStaticContext.XPATH_BUILT_IN_MATH_FUNCS_NS_URI).equals(funcNamespace)) {
           Object funcId = funcTable.getFunctionIdForXPathBuiltinMathFuncs(funcName);
           int funcIdValue = (int)Integer.valueOf(funcId.toString());
           result = funcTable.getFunction(funcIdValue);
        }
        else if ((XPathStaticContext.XPATH_BUILT_IN_MAP_FUNCS_NS_URI).equals(funcNamespace)) {
           Object funcId = funcTable.getFunctionIdForXPathBuiltinMapFuncs(funcName);
           int funcIdValue = (int)Integer.valueOf(funcId.toString());
           result = funcTable.getFunction(funcIdValue);
        }
        else if ((XPathStaticContext.XPATH_BUILT_IN_ARRAY_FUNCS_NS_URI).equals(funcNamespace)) {
           Object funcId = funcTable.getFunctionIdForXPathBuiltinArrayFuncs(funcName);
           int funcIdValue = (int)Integer.valueOf(funcId.toString());
           result = funcTable.getFunction(funcIdValue);
        }  
        
        return result;
    }
    
    /**
     * Method definition to check, whether the supplied string
     * value is an XML Schema built-in atomic type name.
     * 
     * @param xsTypeNameStr				  The supplied string value
     * @return							  Boolean value true or false
     */
    public boolean isXmlSchemaBuiltInAtomicTypeName(String xsTypeNameStr) {
       
       boolean result = false;
       
       switch (xsTypeNameStr) {
          case Keywords.XS_STRING :
        	  result = true;        	  
        	  break;
          case Keywords.XS_NORMALIZED_STRING :
        	  result = true;        	  
        	  break;
          case Keywords.XS_TOKEN :
        	  result = true;
        	  break;
          case Keywords.XS_DECIMAL :
        	  result = true;
        	  break;
          case Keywords.XS_FLOAT :
        	  result = true;
        	  break;
          case Keywords.XS_DOUBLE :
        	  result = true;
        	  break;
          case Keywords.XS_INTEGER :
        	  result = true;
        	  break;
          case Keywords.XS_NON_POSITIVE_INTEGER :
        	  result = true;
        	  break;
          case Keywords.XS_NEGATIVE_INTEGER :
        	  result = true;
        	  break;
          case Keywords.XS_NON_NEGATIVE_INTEGER :
        	  result = true;
        	  break;
          case Keywords.XS_POSITIVE_INTEGER :
        	  result = true;
        	  break;
          case Keywords.XS_LONG :
        	  result = true;
        	  break;
          case Keywords.XS_INT :
        	  result = true;
        	  break;
          case Keywords.XS_SHORT :
        	  result = true;
        	  break;
          case Keywords.XS_BYTE :
        	  result = true;
        	  break;
          case Keywords.XS_UNSIGNED_LONG :
        	  result = true;
        	  break;
          case Keywords.XS_UNSIGNED_INT :
        	  result = true;
        	  break;
          case Keywords.XS_UNSIGNED_SHORT :
        	  result = true;
        	  break;
          case Keywords.XS_UNSIGNED_BYTE :
        	  result = true;
        	  break;
          case Keywords.XS_DATE :
        	  result = true;
        	  break;
          case Keywords.XS_DATETIME :
        	  result = true;
        	  break;
          case Keywords.XS_DURATION :
        	  result = true;
        	  break;
          case Keywords.XS_YEAR_MONTH_DURATION :
        	  result = true;
        	  break;
          case Keywords.XS_DAY_TIME_DURATION :
        	  result = true;
        	  break;
          case Keywords.XS_TIME :
        	  result = true;
        	  break;
          case Keywords.XS_GYEAR_MONTH :
        	  result = true;
        	  break;
          case Keywords.XS_GYEAR :
        	  result = true;
        	  break;
          case Keywords.XS_GMONTH_DAY :
        	  result = true;
        	  break;
          case Keywords.XS_GDAY :
        	  result = true;
        	  break;
          case Keywords.XS_GMONTH :
        	  result = true;
        	  break;
          case Keywords.XS_ANY_URI :
        	  result = true;
        	  break;   	  
          case Keywords.XS_QNAME :
        	  result = true;
        	  break;
          case Keywords.XS_BASE64BINARY :
        	  result = true;
        	  break;
          case Keywords.XS_HEXBINARY :
        	  result = true;
        	  break;
          case Keywords.XS_LANGUAGE :
        	  result = true;
        	  break;
          case Keywords.XS_NAME :
        	  result = true;
        	  break;
          case Keywords.XS_NCNAME :
        	  result = true;
        	  break;
          case Keywords.XS_NMTOKEN :
        	  result = true;
        	  break;
          case Keywords.XS_ID :
        	  result = true;
        	  break;
          case Keywords.XS_IDREF :
        	  result = true;
        	  break;
          default:
        	  // no op
       }
       
       return result;
    }
    
    /**
     * Method definition to evaluate an XPath inline function expression.
     * 
     * @param xpathInlineFunction			        An XPath compiled inline function reference object		
     * @param argList                               A list of XPath string values for argument information of 
     *                                              inline function reference.
     * @param xctxt									An XPath context object                                              
     * @param prefixTable                           An XML prefix table list object reference containing
     *                                              an XSL context namespace binding information.
     * @param varVector                             Collection of variable names within an XSL current evaluation 
     *                                              context.                                              
     * @param varGlobalSize                         An integer value to resolve variable names within an XSL
     *                                              current evaluation context. 
     * @param xpathVarList                          List of variable names to support resolving XSL run-time
     *                                              XPath expression evaluation.
     * @param xslDynFuncCallVarName                 If this method is called to evaluate an XPath dynamic 
     *                                              function call, this argument contains name of the variable
     *                                              referring to an XPath function that will be called.
     * 
     * @return									    The result of evaluation of an XPath inline function expression.
     * @throws TransformerException
     */
    public XObject evaluateXPathInlineFunction(XPathInlineFunction xpathInlineFunction, List<String> argList, 
    		                                   XPathContext xctxt, List<XMLNSDecl> prefixTable, Vector varVector, 
    		                                   int varGlobalSize, List<QName> xpathVarList, String xslDynFuncCallVarName) throws TransformerException {
    	
    	XObject evalResult = null;
    	
    	Map<QName, XObject> inlineFunctionVarMap = xctxt.getXPathVarMap();

    	SourceLocator srcLocator = xctxt.getSAXLocator();

    	final int contextNode = xctxt.getCurrentNode(); 

    	String inlineFnXPathStr = xpathInlineFunction.getFuncBodyXPathExprStr();
    	
    	if (Constants.FN_XALAN_RNG_PERMUTE.equals(inlineFnXPathStr)) {
    		String arg1XPathStr = argList.get(0);
    		if (prefixTable != null) {
    			arg1XPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(arg1XPathStr, prefixTable);
    		}
    		
    		XPath argXPath = new XPath(arg1XPathStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
    		if (varVector != null) {
				argXPath.fixupVariables(varVector, varGlobalSize);
			}
    		
    		XObject argValue = argXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
    		
    		evalResult = XslTransformEvaluationHelper.permute((ResultSequence)argValue);
    		
    		return evalResult; 
    	}
    	
    	List<InlineFunctionParameter> funcParamList = xpathInlineFunction.getFuncParamList();
    	
    	String xpathFuncBodyStr = xpathInlineFunction.getFuncBodyXPathExprStr();

    	int argCount1 = argList.size();

    	if (!(Keywords.FUNC_RANDOM_NUMBER_GENERATOR + "()").equals(xpathFuncBodyStr) && (argCount1 != funcParamList.size())) {
    	   throw new javax.xml.transform.TransformerException("XPTY0004 : Number of arguments required for "
																		    				 + "XPath dynamic function call is " + funcParamList.size() + ". "
																		    				 + "Arguments provided : " + argCount1 + ".", srcLocator);    
            																		    				
    	}

    	Map<QName, XObject> functionParamAndArgMap = new HashMap<QName, XObject>();

    	int argCount = funcParamList.size();
    	
    	for (int idx = 0; idx < argCount; idx++) {
    		InlineFunctionParameter funcParam = funcParamList.get(idx);                                                         

    		String argXPathStr = argList.get(idx);

    		if (prefixTable != null) {
    			argXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(argXPathStr, prefixTable);
    		}

    		XPath argXPath = new XPath(argXPathStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
    		
    		Expression argExpr = argXPath.getExpression();
    		XObject argValue = null;    		
    		if ((argExpr instanceof SelfIteratorNoPredicate) && (xctxt.getXPath3ContextItem() != null)) {
    			argValue = xctxt.getXPath3ContextItem(); 	
    		}
            else if (argExpr instanceof FuncArgPlaceholder) {
    			argValue = XObject.create((FuncArgPlaceholder)argExpr); 
    		}
    		else {
    			if (varVector != null) {
    				argXPath.fixupVariables(varVector, varGlobalSize);
    			}

    			argValue = argXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());
    		}

    		String funcParamName = funcParam.getParamName();
    		SequenceTypeData paramType = funcParam.getParamType();

    		if (paramType != null) {
    			try {
    				argValue = SequenceTypeSupport.castXdmValueToAnotherType(argValue, null, paramType, null);                     
    				if (argValue == null) {
    					if (xslDynFuncCallVarName != null) {
    					    throw new TransformerException("XTTE0505 : An item type of argument at position " + (idx + 1) + " of XPath dynamic "
			    							                                              + "function call $" + xslDynFuncCallVarName + ", "
			    							                                              + "doesn't match an expected type.", srcLocator);
    					}
    					else {
    						throw new TransformerException("XTTE0505 : An item type of argument at position " + (idx + 1) + " of an XPath "
                                                                                          + "function call, doesn't match an expected type.", srcLocator);
    					}
    				}
    			}
    			catch (TransformerException ex) {
    				if (xslDynFuncCallVarName != null) {
					    throw new TransformerException("XTTE0505 : An item type of argument at position " + (idx + 1) + " of XPath dynamic "
		    							                                              + "function call $" + xslDynFuncCallVarName + ", "
		    							                                              + "doesn't match an expected type.", srcLocator);
					}
					else {
						throw new TransformerException("XTTE0505 : An item type of argument at position " + (idx + 1) + " of an XPath "
                                                                                      + "function call, doesn't match an expected type.", srcLocator);
					} 
    			}
    		}

    		xpathVarList.add(new QName(funcParamName));

    		functionParamAndArgMap.put(new QName(funcParamName), argValue);
    	}

    	inlineFunctionVarMap.putAll(functionParamAndArgMap);

    	if (prefixTable != null) {
    		inlineFnXPathStr = XslTransformEvaluationHelper.replaceNsUrisWithPrefixesOnXPathStr(inlineFnXPathStr, prefixTable);
    	}

    	XPath inlineFnXPath = new XPath(inlineFnXPathStr, srcLocator, xctxt.getNamespaceContext(), XPath.SELECT, null);
    	if (varVector != null) {
    		inlineFnXPath.fixupVariables(varVector, varGlobalSize);
    	}

    	evalResult = inlineFnXPath.execute(xctxt, contextNode, xctxt.getNamespaceContext());

    	SequenceTypeData funcReturnType = xpathInlineFunction.getReturnType();
    	if (funcReturnType != null) {
    		try {
    			evalResult = SequenceTypeSupport.castXdmValueToAnotherType(evalResult, null, funcReturnType, null);
    			if (evalResult == null) {
    				if (xslDynFuncCallVarName != null) {
    				    throw new TransformerException("XTTE0505 : An item type of result of dynamic function call $"+ xslDynFuncCallVarName + ", "
    						                                                                         + "doesn't match an expected type.", srcLocator);
    				}
    				else {
    					throw new TransformerException("XTTE0505 : An item type of result of an XPath function call, doesn't match "
    							                                                                     + "an expected type.", srcLocator);
    				}
    			}
    		}
    		catch (TransformerException ex) {
    			if (xslDynFuncCallVarName != null) {
				    throw new TransformerException("XTTE0505 : An item type of result of dynamic function call $"+ xslDynFuncCallVarName + ", "
						                                                                             + "doesn't match an expected type.", srcLocator);
				}
				else {
					throw new TransformerException("XTTE0505 : An item type of result of an XPath function call, doesn't match "
							                                                                         + "an expected type.", srcLocator);
				}  
    		}
    	}

    	Set<QName> keysOfArgVariables = functionParamAndArgMap.keySet();    	
    	Iterator<QName> iter = keysOfArgVariables.iterator();    	
    	while (iter.hasNext()) {
    		QName key = iter.next();
    		inlineFunctionVarMap.remove(key);
    	}
    	
    	return evalResult;
	}
    
    /**
     * Evaluate the XPath built-in constructor function call.
     */
    private XObject evaluateXPathBuiltInConstructorFunctionCall(XSL3ConstructorOrExtensionFunction funcObj, 
    		                                                    Class dataType, XPathContext xctxt) throws TransformerException, 
		                                                                                                   InstantiationException, IllegalAccessException, 
		                                                                                                   NoSuchMethodException, SecurityException, 
		                                                                                                   IllegalArgumentException, InvocationTargetException {
    	XObject evalResult = null;
    	
    	ResultSequence evalResultSequence = null;
    	ResultSequence argSequence = new ResultSequence();
    	
    	int funcArgCount = funcObj.getArgCount();    	
    	for (int idx = 0; idx < funcArgCount; idx++) {
			Expression funcArg = funcObj.getArg(idx);    						
			String argStr = getXPathBuiltInConstructorFunctionArgStr(funcArg, xctxt);
			Constructor cons = dataType.getConstructor(new Class[] {String.class});
			Object obj = cons.newInstance(new Object[] {argStr});
			argSequence.add((XObject)obj);
		}
    	
    	Object obj = dataType.newInstance();
    	
    	Method method = dataType.getMethod("constructor", new Class[] {ResultSequence.class});
    	evalResultSequence = (ResultSequence)(method.invoke(obj, new Object[] {argSequence}));

		evalResult = evalResultSequence.item(0);
    	
    	return evalResult;
    }

    /**
     * Get the effective value of XPath built-in constructor function call's argument.
     */
    private String getXPathBuiltInConstructorFunctionArgStr(Expression funcArg, XPathContext xctxt) 
    		                                                                              throws TransformerException {
    	String argStr = null;
    	
    	if (funcArg instanceof SelfIteratorNoPredicate) {
    		XObject contextItem = xctxt.getXPath3ContextItem();
    		if (contextItem != null) {
    		   argStr = XslTransformEvaluationHelper.getStrVal(contextItem);
    		}
    		else {
    		   XObject argVal = funcArg.execute(xctxt);
        	   argStr = XslTransformEvaluationHelper.getStrVal(argVal);
    		}
    	}
    	else {
    		XObject argVal = funcArg.execute(xctxt);
    		argStr = XslTransformEvaluationHelper.getStrVal(argVal); 
    	}
    	
    	return argStr;
    }
    
    /**
     * Method definition, to check whether the supplied xsl:function object,
     * can be used to resolve the function call.
     * 
     * @param elemFunction                      The supplied xsl:function object reference
     * @param componentNames					The allowed Vector information for
     *                                          xsl:function names.
     * @param funcCallNs                        xsl:function name's namespace from
     *                                          function call reference.
     * @param funcCallName                      xsl:function name's local-name from
     *                                          function call reference.
     * @param funcCallArgCount                  The function arity information, from
     *                                          function call reference.
     *                                          
     * @return                                  Boolean value true or false
     */
    private boolean isElemFunctionEligible(ElemFunction elemFunction, Vector componentNames, 
    		                                                          String funcCallNs, String funcCallName, 
    		                                                          int funcCallArgCount) throws TransformerException {
        
    	boolean result = false;
        
        Enumeration enum1 = componentNames.elements();
        
        QName fqName = elemFunction.getName();
        String fLocalName = fqName.getLocalName();
        String fUri = fqName.getNamespace();
        int fArity = elemFunction.getArity();
        
        XPath useWhenExpr = elemFunction.getUseWhen();
        if (useWhenExpr != null) {
           boolean result1 = ((ElemTemplateElement)elemFunction).isXPathExpressionStatic(useWhenExpr.getExpression());
           if (!result1) {
        	   throw new TransformerException("XPST0008 : XSL variables other than XSLT static variables/parameters, cannot be "
                       																										  + "used within XPath static expression.", elemFunction); 
           }
        }
        
        while (enum1.hasMoreElements()) {
			QName qName2 = (QName)(enum1.nextElement());
			String localName2 = qName2.getLocalName();
			String namespace2 = qName2.getNamespace();
			if (localName2.indexOf('#') != -1) {
				int arity = Integer.valueOf(localName2.substring(localName2.indexOf('#') + 1));
				String localName = localName2.substring(0, localName2.indexOf('#')); 
				if (fLocalName.equals(localName) && fUri.equals(namespace2) && fUri.equals(funcCallNs) 
						                         && (fArity == arity) && (arity == funcCallArgCount)) {
					result = true;

					break;
				}				
			}    														
		}
        
        return result;
    }
    
    /**
     * Method definition, to get xsl:function declaration object, for the supplied
     * xsl:function call reference information.
     * 
     * @param transformerImpl                                      An XSL run-time TransformerImpl 
     *                                                             object instance. 
     * @param funcNamespace                                        An xsl:function declaration's desired 
     *                                                             XML namespace value.
     * @param funcName                                             An xsl:function declaration's desired
     *                                                             local name.
     * @param xslFuncExpectedArity                                 An xsl:function declaration's desired
     *                                                             arity.
     * @return                                                     An xsl:function declaration object,
     *                                                             or null.
     * @throws TransformerException
     * @throws TransformerFactoryConfigurationError
     */
    private ElemTemplate getXslFunctionDeclUsingXslPackage(TransformerImpl transformerImpl, String funcNamespace, 
    		                                                                                     String funcName, 
    		                                                                                     int xslFuncExpectedArity) throws TransformerException, 
                                                                                                                     TransformerFactoryConfigurationError {
    	ElemTemplate result = null;
    	    	    	
    	XPathContext xctxt = transformerImpl.getXPathContext();
    	    	    	
    	SourceLocator srcLocator = xctxt.getSAXLocator();
    	
    	final int sourceNode = xctxt.getCurrentNode();
    	
    	Stylesheet sroot = transformerImpl.getStylesheet();
    	
    	ElemTemplateElement elemTemplateElement1 = sroot.getFirstChildElem();
    	
    	Stylesheet stylesheet2 = null;
		
		while (elemTemplateElement1 != null) {
			if (elemTemplateElement1 instanceof ElemUsePackage) {
				// Resolve function call reference				
				ElemUsePackage elemUsePackage2 = (ElemUsePackage)elemTemplateElement1;
				XPath useWhenExpr = elemUsePackage2.getUseWhen();
				if (useWhenExpr != null) {
					XObject xObj = useWhenExpr.execute(xctxt, sourceNode, xctxt.getNamespaceContext());
					if (!xObj.bool()) {
						elemTemplateElement1 = elemTemplateElement1.getNextSiblingElem();

						continue;
					}
				}
				
				System.setProperty(Constants.XSL_TRANSFORM_FACTORY_KEY, Constants.XSL_TRANSFORM_FACTORY_VALUE);

				try {
					TransformerFactory tfactory = TransformerFactory.newInstance();
					tfactory.setErrorListener(new DefaultErrorHandler(true));

					ElemUsePackage elemUsePackage = (ElemUsePackage)elemTemplateElement1;
					AVT packageAvt = elemUsePackage.getName();
					String packageName = packageAvt.evaluate(xctxt, sourceNode, xctxt.getNamespaceContext());

					DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
					dfactory.setNamespaceAware(true);
					dfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
					DocumentBuilder docBuilder = dfactory.newDocumentBuilder();    							    							

					URL resolvedUrl = null;
					URI uri = new URI(packageName);
					if (uri.isAbsolute()) {
						resolvedUrl = new URL(packageName); 
					}
					else {
						String stylesheetSystemId = srcLocator.getSystemId();    				            	
						if (stylesheetSystemId != null) {
							URI resolvedUriArg = (new URI(stylesheetSystemId)).resolve(packageName);
							resolvedUrl = resolvedUriArg.toURL();
						}
						else {
							resolvedUrl = new URL(packageName);
						}
					}

					String xslResolverUrlStr = resolvedUrl.toString();

					InputSource inpSrc = new InputSource(xslResolverUrlStr);

					Document xslDocument = docBuilder.parse(inpSrc);

					Templates templates = tfactory.newTemplates(new DOMSource(xslDocument, xslResolverUrlStr));

					/**
					 * This shall provide to us XSL expanded component definitions.
					 * We need to verify, that which of these components to use,
					 * using xsl:accept instruction, information from xsl:use-package.
					 */
					stylesheet2 = (Stylesheet)templates;

					ElemTemplateElement elem1 = elemUsePackage.getFirstChildElem();
					while ((elem1 != null) && (elem1 instanceof ElemAccept)) {
						ElemAccept elemAccept = (ElemAccept)elem1;
						String component = elemAccept.getComponent();    								
						if ("function".equals(component)) {
							Vector componentNames = elemAccept.getNames();
							String compVisibilityValue = elemAccept.getVisibility();
							if ("public".equals(compVisibilityValue)) {    								    
								int xslTemplateCount = stylesheet2.getTemplateCount();
								for (int idx = 0; idx < xslTemplateCount; idx++) {
									ElemTemplate template = stylesheet2.getTemplate(idx);
									if (template instanceof ElemFunction) {
										ElemFunction elemFunction = (ElemFunction)template;
										if (isElemFunctionEligible(elemFunction, componentNames, 
												                                 funcNamespace, funcName, xslFuncExpectedArity)) {
										   result = elemFunction;
										   
										   break;
										}    													
									}
								}
								
								if (result != null) {
								   break;	
								}
							}
						}
						
						if (result != null) {
						    break;	
					    }

						elem1 = elem1.getNextSiblingElem();
				    }
				}	
				catch (Exception ex) {
					// no op	
				}
			}

			if (result != null) {
				break;	
			}

			elemTemplateElement1 = elemTemplateElement1.getNextSiblingElem();
		}
		
		if (result != null) {
			// Verify xsl:function declaration object found via xsl:use-package 
			// instruction, with xsl:expose instruction.

			ElemTemplateElement elemTemplateElem = stylesheet2.getFirstChildElem();
			boolean isXslExposeAllows = false;
									
			while (elemTemplateElem != null) {
				if (elemTemplateElem instanceof ElemExpose) {
					ElemExpose elemExpose = (ElemExpose)elemTemplateElem;					
					String componentType = elemExpose.getComponent();
					Vector nameVector = elemExpose.getNames();
					String visibility = elemExpose.getVisibility();
					if ("public".equals(visibility) && ("function".equals(componentType) || "*".equals(componentType))) {
						Enumeration enum1 = nameVector.elements();
						while (enum1.hasMoreElements()) {
							QName qNameExposeValue1 = (QName)(enum1.nextElement());
																					
							String ns1 =  qNameExposeValue1.getNamespace();
							String localName1 = qNameExposeValue1.getLocalName();
							int arity = -1;
							if (localName1.contains("#")) {
							   int idx = localName1.indexOf('#');
							   arity = Integer.valueOf(localName1.substring(idx + 1));
							   localName1 = localName1.substring(0, idx);
							   qNameExposeValue1 = new QName(ns1, localName1);							   
							}
							
							QName qNameFuncDeclValue1 = result.getName();
							String ns2 = qNameFuncDeclValue1.getNamespace();
							String localName2 = qNameFuncDeclValue1.getLocalName();
	
							isXslExposeAllows = (new QName(ns2, localName2)).equals(new QName(ns1, localName1));
							if (isXslExposeAllows) {
								ElemFunction elemFunc = (ElemFunction)result;
								if ((arity != -1) && !(arity == elemFunc.getArity())) {
									isXslExposeAllows = false;
								}
							}
							
							if (isXslExposeAllows) {
								break; 
							}
						}						
					}

					if (isXslExposeAllows) {
						break;	
					}
				}

				elemTemplateElem = elemTemplateElem.getNextSiblingElem();
			}

			if (!isXslExposeAllows) {
				result = null; 
			}			
		}
		
		if ((result != null) && (stylesheet2 != null)) {
			StylesheetRoot stylesheetRoot = (StylesheetRoot)stylesheet2;
			result.setStylesheet(stylesheetRoot);
		}
		
		return result;
    }
    
}
