using System;
using System.Reflection;
using System.Xml;
using System.Xml.Xsl;
using System.IO;
using System.Text;


namespace MapReuser
{
	/// 
	/// Преобразует XML документы с помощью XSLT
	/// 
	public class BizTalkMap
	{
		/// 
		/// Кэш XSLT.
		/// 
		private Stream xsltStream;

		/// 
		/// Кэш XSLT аргументов.
		/// 
		private Stream xsltArguments;
		

		/// 
		/// Кэш XslTransform.
		/// 
		private XslTransform     xslTransform;

		/// 
		/// Кэш XSltArgumentList.
		/// 
		private XsltArgumentList xslArgumentList;




		/// 
		/// Constructor.
		/// 
		/// Поток XSLT в виде XML.
		/// Поток Extension Objects в виде XML.
		public BizTalkMap(Stream XsltStream, Stream XsltArguments)
		{
			xsltStream    = XsltStream;
			xsltArguments = XsltArguments;
		}

		/// 
		/// Преобразует документ и возвращает результат в виде потока.
		/// 
		/// Поток преобразуемых данных (XML).
		/// Поток преобразованных данных (XML).
		public Stream TransformInstance(Stream inXml)
		{
			XslTransform transform   = Transform;
			XmlDocument  xmlInputDoc = new XmlDocument();

			xmlInputDoc.Load(inXml);

			// Создаем поток в памяти для хранения преобразованных данных
			MemoryStream  outStream = new MemoryStream();
			XmlTextWriter xmlWriter = new XmlTextWriter(outStream, System.Text.Encoding.UTF8);

			// Опции форматирования XML
			xmlWriter.Formatting  = Formatting.Indented;
			xmlWriter.Indentation = 2;
			
			// Преобразуем
			transform.Transform(xmlInputDoc, TransformArgs, xmlWriter, null);
			// Устанавливаем курсор на начало потока
			outStream.Seek(0, SeekOrigin.Begin);

			return outStream;
		}

		/// 
		/// Возвращает экземпляр класса XslTransform.
		/// 
		private XslTransform Transform
		{
			get
			{
				if (xslTransform == null)
				{
					// Инициализируем XslTransform
					XmlTextReader xsltReader = new XmlTextReader(xsltStream);
					XslTransform transformTemp = new XslTransform();
					transformTemp.Load(xsltReader, (XmlResolver) null, GetType().Assembly.Evidence);
					
					// Кэшируем объект XslTransform
					xslTransform = transformTemp;
				}
				return xslTransform;
			}
		}

		/// 
		/// Возвращает объект XsltArgumentList, сформированный из Extension Object XML.
		/// 
		private XsltArgumentList TransformArgs
		{
			get
			{
				if (xslArgumentList == null)
				{
					XmlDocument      xmlExtension = new XmlDocument();
					XsltArgumentList xslArgList   = new XsltArgumentList();

					if (xsltArguments != null)
					{
						// Загружаем список XSLT аргументов и создаем все необходимые экземпляры классов
						xmlExtension.Load(xsltArguments);
						XmlNodeList xmlExtensionNodes = xmlExtension.SelectNodes(«//ExtensionObjects/ExtensionObject»);
						foreach (XmlNode extObjNode in xmlExtensionNodes)
						{
							XmlAttributeCollection extAttributes = extObjNode.Attributes;

							XmlNode  namespaceNode = extAttributes.GetNamedItem(«Namespace»);
							XmlNode  assemblyNode  = extAttributes.GetNamedItem(«AssemblyName»);
							XmlNode  classNode     = extAttributes.GetNamedItem(«ClassName»);
							Assembly extAssembly   = Assembly.Load(assemblyNode.Value);
							object   extObj        = extAssembly.CreateInstance(classNode.Value);
							xslArgList.AddExtensionObject(namespaceNode.Value, extObj);
						}
					}
					// Кэшируем список
					xslArgumentList = xslArgList;
				}
				return xslArgumentList;
			}
		}
	}
}