//
// XslLiteralElement.cs
//
// Authors:
//	Ben Maurer (bmaurer@users.sourceforge.net)
//	Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
//	
// (C) 2003 Ben Maurer
// (C) 2003 Atsushi Enomoto
//

using System;
using System.Collections;
using System.Xml;
using System.Xml.XPath;
using System.Xml.Xsl;

namespace Mono.Xml.Xsl.Operations {	
	public class XslLiteralElement : XslCompiledElement {
		XslOperation children;
		string localname, prefix, nsUri;
		bool isEmptyElement;
		ArrayList attrs;
		XmlQualifiedName [] useAttributeSets;
		Hashtable nsDecls;
		string excludeResultPrefixes;
		string extensionElementPrefixes;
		ArrayList excludedPrefixes;
		bool requireNameFix;
		XPathNavigator stylesheetNode;
		XslStylesheet stylesheet;

		public XslLiteralElement (Compiler c) : base (c) {}
			
		class XslLiteralAttribute {
			string localname, prefix, nsUri;
			XslAvt val;
			
			public XslLiteralAttribute (Compiler c)
			{
				this.prefix = c.Input.Prefix;
				this.nsUri = c.Input.NamespaceURI;
				this.localname = c.Input.LocalName;
				this.val = new XslAvt (c.Input.Value, c);
			}
			
			public void Evaluate (XslTransformProcessor p)
			{
				p.Out.WriteAttributeString (prefix, localname, nsUri, val.Evaluate (p));
			}
		}
		
		protected override void Compile (Compiler c)
		{
			requireNameFix = true;
			stylesheetNode = c.Input.Clone ();
			stylesheet = c.CurrentStylesheet;

			this.localname = c.Input.LocalName;
			this.useAttributeSets = c.ParseQNameListAttribute ("use-attribute-sets", XsltNamespace);
			this.nsDecls = c.GetNamespacesToCopy ();
			if (nsDecls.Count == 0) nsDecls = null;
			this.isEmptyElement = c.Input.IsEmptyElement;
			this.excludeResultPrefixes = c.Input.GetAttribute ("exclude-result-prefixes", XsltNamespace);
			this.extensionElementPrefixes = c.Input.GetAttribute ("extension-element-prefixes", XsltNamespace);
			excludedPrefixes = new ArrayList (excludeResultPrefixes.Split (XmlChar.WhitespaceChars));
			excludedPrefixes.AddRange (extensionElementPrefixes.Split (XmlChar.WhitespaceChars));

			if (c.Input.MoveToFirstAttribute ())
			{
				attrs = new ArrayList ();
				do {
					if (c.Input.NamespaceURI == XsltNamespace)
						continue; //already handled
					attrs.Add (new XslLiteralAttribute (c));
				} while (c.Input.MoveToNextAttribute());
				c.Input.MoveToParent ();
			}
			
			if (!c.Input.MoveToFirstChild ()) return;
			children = c.CompileTemplateContent ();
			c.Input.MoveToParent ();
		}

		private void GetCorrectNames ()
		{
			requireNameFix = false;
			prefix = stylesheetNode.Prefix;
			string alias = stylesheet.PrefixInEffect (prefix, null);
			if (alias != stylesheetNode.Prefix) {
				nsUri = stylesheetNode.GetNamespace (alias);
				if (alias != null)
					prefix = alias;
			}
			else
				nsUri = stylesheetNode.NamespaceURI;

		}
		
		public override void Evaluate (XslTransformProcessor p)
		{
			// Since namespace-alias might be determined after compilation
			// of import-ing stylesheets, this must be determined later.
			if (requireNameFix)
				GetCorrectNames ();

			bool isCData = p.InsideCDataElement;
			p.PushElementState (localname, nsUri, true);
			p.Out.WriteStartElement (prefix, localname, nsUri);

			if (useAttributeSets != null)
				foreach (XmlQualifiedName s in useAttributeSets)
					p.ResolveAttributeSet (s).Evaluate (p);
						
			if (attrs != null) {
				int len = attrs.Count;
				for (int i = 0; i < len; i++)
					((XslLiteralAttribute)attrs [i]).Evaluate (p);
			}

			p.TryStylesheetNamespaceOutput (excludedPrefixes);
			if (nsDecls != null) {
				foreach (DictionaryEntry de in nsDecls) {
					string actualPrefix = p.CompiledStyle.Style.PrefixInEffect (de.Key as String, excludedPrefixes);
					if (actualPrefix != null)
						p.Out.WriteNamespaceDecl (actualPrefix, (string)de.Value);
				}
			}
			
			if (children != null) children.Evaluate (p);

			if (isEmptyElement)
				p.Out.WriteEndElement ();
			else
				p.Out.WriteFullEndElement ();

			p.PopCDataState (isCData);
		}
	}
}
