context: // HtmlAgilityPack V1.0 - Simon Mourier <simon underscore mourier at hotmail dot com>
  using System;
  using System.IO;
  using System.Text;
  
  namespace HtmlAgilityPack
  {
  	/// <summary>
  	/// Represents a document with mixed code and text. ASP, ASPX, JSP, are good example of such documents.
  	/// </summary>
  	public class MixedCodeDocument
  	{
  		#region Fields
  
  		private int _c;
  		internal MixedCodeDocumentFragmentList _codefragments;
  		private MixedCodeDocumentFragment _currentfragment;
  		internal MixedCodeDocumentFragmentList _fragments;
  		private int _index;
  		private int _line;
  		private int _lineposition;
  		private ParseState _state;
  		private Encoding _streamencoding;
  		internal string _text;
  		internal MixedCodeDocumentFragmentList _textfragments;
  
  		/// <summary>
  		/// Gets or sets the token representing code end.
  		/// </summary>
  		public string TokenCodeEnd = "%>";
  
  		/// <summary>
  		/// Gets or sets the token representing code start.
  		/// </summary>
  		public string TokenCodeStart = "<%";
  
  		/// <summary>
  		/// Gets or sets the token representing code directive.
  		/// </summary>
  		public string TokenDirective = "@";
  
  		/// <summary>
  		/// Gets or sets the token representing response write directive.
  		/// </summary>
  		public string TokenResponseWrite = "Response.Write ";
  
  
  		private string TokenTextBlock = "TextBlock({0})";
  
  		#endregion
  
  		#region Constructors
  
  		/// <summary>
  		/// Creates a mixed code document instance.
  		/// </summary>
  		public MixedCodeDocument()
  		{
  			_codefragments = new MixedCodeDocumentFragmentList(this);
  			_textfragments = new MixedCodeDocumentFragmentList(this);
  			_fragments = new MixedCodeDocumentFragmentList(this);
  		}
  
  		#endregion
  
  		#region Properties
  
  		/// <summary>
  		/// Gets the code represented by the mixed code document seen as a template.
  		/// </summary>
  		public string Code
  		{
  			get
  			{
  				string s = "";
  				int i = 0;
  				foreach (MixedCodeDocumentFragment frag in _fragments)
  				{
  					switch (frag._type)
  					{
  						case MixedCodeDocumentFragmentType.Text:
  							s += TokenResponseWrite + string.Format(TokenTextBlock, i) + "\n";
  							i++;
  							break;
  
  						case MixedCodeDocumentFragmentType.Code:
  							s += ((MixedCodeDocumentCodeFragment) frag).Code + "\n";
  							break;
  					}
  				}
  				return s;
  			}
  		}
  
  		/// <summary>
  		/// Gets the list of code fragments in the document.
  		/// </summary>
  		public MixedCodeDocumentFragmentList CodeFragments
  		{
  			get { return _codefragments; }
  		}
  
  		/// <summary>
  		/// Gets the list of all fragments in the document.
  		/// </summary>
  		public MixedCodeDocumentFragmentList Fragments
  		{
  			get { return _fragments; }
  		}
  
  		/// <summary>
  		/// Gets the encoding of the stream used to read the document.
  		/// </summary>
  		public Encoding StreamEncoding
  		{
  			get { return _streamencoding; }
  		}
  
  		/// <summary>
  		/// Gets the list of text fragments in the document.
  		/// </summary>
  		public MixedCodeDocumentFragmentList TextFragments
  		{
  			get { return _textfragments; }
  		}
  
  		#endregion
  
  		#region Public Methods
  
  		/// <summary>
  		/// Create a code fragment instances.
  		/// </summary>
  		/// <returns>The newly created code fragment instance.</returns>
  		public MixedCodeDocumentCodeFragment CreateCodeFragment()
  		{
  			return (MixedCodeDocumentCodeFragment) CreateFragment(MixedCodeDocumentFragmentType.Code);
  		}
  
  		/// <summary>
  		/// Create a text fragment instances.
  		/// </summary>
  		/// <returns>The newly created text fragment instance.</returns>
  		public MixedCodeDocumentTextFragment CreateTextFragment()
  		{
  			return (MixedCodeDocumentTextFragment) CreateFragment(MixedCodeDocumentFragmentType.Text);
  		}
  
  		/// <summary>
  		/// Loads a mixed code document from a stream.
  		/// </summary>
  		/// <param name="stream">The input stream.</param>
  		public void Load(Stream stream)
  		{
  			Load(new StreamReader(stream));
  		}
  
  		/// <summary>
  		/// Loads a mixed code document from a stream.
  		/// </summary>
  		/// <param name="stream">The input stream.</param>
  		/// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>
  		public void Load(Stream stream, bool detectEncodingFromByteOrderMarks)
  		{
  			Load(new StreamReader(stream, detectEncodingFromByteOrderMarks));
  		}
  
  		/// <summary>
  		/// Loads a mixed code document from a stream.
  		/// </summary>
  		/// <param name="stream">The input stream.</param>
  		/// <param name="encoding">The character encoding to use.</param>
  		public void Load(Stream stream, Encoding encoding)
  		{
  			Load(new StreamReader(stream, encoding));
  		}
  
  		/// <summary>
  		/// Loads a mixed code document from a stream.
  		/// </summary>
  		/// <param name="stream">The input stream.</param>
  		/// <param name="encoding">The character encoding to use.</param>
  		/// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>
  		public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
  		{
  			Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks));
  		}
  
  		/// <summary>
  		/// Loads a mixed code document from a stream.
  		/// </summary>
  		/// <param name="stream">The input stream.</param>
  		/// <param name="encoding">The character encoding to use.</param>
  		/// <param name="detectEncodingFromByteOrderMarks">Indicates whether to look for byte order marks at the beginning of the file.</param>
  		/// <param name="buffersize">The minimum buffer size.</param>
  		public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)
  		{
  			Load(new StreamReader(stream, encoding, detectEncodingFromByteOrderMarks, buffersize));
  		}
  
  		/// <summary>
  		/// Loads the mixed code document from the specified TextReader.
  		/// </summary>
  		/// <param name="reader">The TextReader used to feed the HTML data into the document.</param>
  		public void Load(TextReader reader)
  		{
  			_codefragments.Clear();
  			_textfragments.Clear();
  
  			// all pseudo constructors get down to this one
  			StreamReader sr = reader as StreamReader;
  			if (sr != null)
  			{
  				_streamencoding = sr.CurrentEncoding;
  			}
  
  			_text = reader.ReadToEnd();
  			reader.Dispose();
  			Parse();
  		}
  
  		/// <summary>
  		/// Loads a mixed document from a text
  		/// </summary>
  		/// <param name="html">The text to load.</param>
  		public void LoadHtml(string html)
  		{
  			Load(new StringReader(html));
  		}
  
  		/// <summary>
  		/// Saves the mixed document to the specified stream.
  		/// </summary>
  		/// <param name="outStream">The stream to which you want to save.</param>
  		public void Save(Stream outStream)
  		{
  			StreamWriter sw = new StreamWriter(outStream, GetOutEncoding());
  			Save(sw);
  		}
  
  		/// <summary>
  		/// Saves the mixed document to the specified stream.
  		/// </summary>
  		/// <param name="outStream">The stream to which you want to save.</param>
  		/// <param name="encoding">The character encoding to use.</param>
  		public void Save(Stream outStream, Encoding encoding)
  		{
  			StreamWriter sw = new StreamWriter(outStream, encoding);
  			Save(sw);
  		}
  
  		/// <summary>
  		/// Saves the mixed document to the specified StreamWriter.
  		/// </summary>
  		/// <param name="writer">The StreamWriter to which you want to save.</param>
  		public void Save(StreamWriter writer)
  		{
  			Save((TextWriter) writer);
  		}
  
  		/// <summary>
  		/// Saves the mixed document to the specified TextWriter.
  		/// </summary>
  		/// <param name="writer">The TextWriter to which you want to save.</param>
  		public void Save(TextWriter writer)
  		{
  			writer.Flush();
  		}
  
  		#endregion
  
  		#region Internal Methods
  
  		internal MixedCodeDocumentFragment CreateFragment(MixedCodeDocumentFragmentType type)
  		{
  			switch (type)
  			{
  				case MixedCodeDocumentFragmentType.Text:
  					return new MixedCodeDocumentTextFragment(this);
  
  				case MixedCodeDocumentFragmentType.Code:
  					return new MixedCodeDocumentCodeFragment(this);
  
  				default:
  					throw new NotSupportedException();
  			}
  		}
  
  		internal Encoding GetOutEncoding()
  		{
  			if (_streamencoding != null)
  				return _streamencoding;
  			return Encoding.UTF8;
  		}
  
  		#endregion
  
  		#region Private Methods
  
  		private void IncrementPosition()
  		{
  			_index++;
  			if (_c == 10)
  			{
  				_lineposition = 1;
  				_line++;
  			}
  			else
  				_lineposition++;
  		}
  
  		private void Parse()
  		{
  			_state = ParseState.Text;
  			_index = 0;
  			_currentfragment = CreateFragment(MixedCodeDocumentFragmentType.Text);
  
  			while (_index < _text.Length)
  			{
  
gt: 				_c = _text[_index];