context: #region WatiN Copyright (C) 2006-2011 Jeroen van Menen
  
  //Copyright 2006-2011 Jeroen van Menen
  //
  //   Licensed under the Apache License, Version 2.0 (the "License");
  //   you may not use this file except in compliance with the License.
  //   You may obtain a copy of the License at
  //
  //       http://www.apache.org/licenses/LICENSE-2.0
  //
  //   Unless required by applicable law or agreed to in writing, software
  //   distributed under the License is distributed on an "AS IS" BASIS,
  //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  //   See the License for the specific language governing permissions and
  //   limitations under the License.
  
  #endregion Copyright
  
  using System;
  using System.Collections.Generic;
  using System.Text.RegularExpressions;
  using WatiN.Core.Constraints;
  using WatiN.Core.Exceptions;
  using WatiN.Core.Native;
  using WatiN.Core.UtilityClasses;
  
  namespace WatiN.Core
  {
  	/// <summary>
  	/// This class gives access to all contained elements of the webpage or the
  	/// frames within this webpage.
  	/// </summary>
  	/// <example>
  	/// This example opens a webpage, types some text and submits it by clicking
  	/// the submit button.
  	/// <code>
  	/// using WatiN.Core;
  	/// 
  	/// namespace NewIEExample
  	/// {
  	///    public class WatiNWebsite
  	///    {
  	///      public WatiNWebsite()
  	///      {
  	///        IE ie = new IE("http://www.example.net");
  	/// 
  	///        ie.TextField(Find.ById("textFieldComment")).TypeText("This is a comment to submit");
  	///        ie.Button(Find.ByText("Submit")).Click;
  	/// 
  	///        ie.Close;
  	///      }
  	///    }
  	///  }
  	/// </code>
  	/// </example>
  	public abstract class Document : Component, IElementContainer, IDisposable
  	{
  	    private const string RESULT_PROPERTY_NAME = "watinExpressionResult";
          public const string ERROR_PROPERTY_NAME = "watinExpressionError";
  
          private DomContainer domContainer;
  
  		/// <summary>
  		/// Initializes a new instance of the <see cref="Document"/> class.
  		/// Mainly used by WatiN internally. You should override NativeDocument
  		/// and set DomContainer before accessing any method or property of 
  		/// this class.
  		/// </summary>
  		protected Document() {}
  
  		/// <summary>
  		/// Initializes a new instance of the <see cref="Document"/> class.
  		/// Mainly used by WatiN internally.
  		/// </summary>
  		/// <param name="domContainer">The DOM container.</param>
  		protected Document(DomContainer domContainer)
  		{
              if (domContainer == null)
                  throw new ArgumentNullException("domContainer");
  
  			DomContainer = domContainer;
  		}
  
          /// <summary>
          /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
          /// </summary>
          public void Dispose()
  		{
  			Dispose(true);
  
              // This object will be cleaned up by the Dispose method.
              // Therefore, you should call GC.SupressFinalize to
              // take this object off the finalization queue 
              // and prevent finalization code for this object
              // from executing a second time.
              GC.SuppressFinalize(this);
  		}
  
  		protected virtual void Dispose(bool disposing)
  		{
  			DomContainer = null;
  		}
  
  		/// <summary>
          /// Gives access to the wrapped INativeDocument interface. This makes it
  		/// possible to get even more control of the webpage by using wrapped element.
  		/// </summary>
  		/// <value>The NativeDocument.</value>
  		public abstract INativeDocument NativeDocument { get; }
  
  		/// <summary>
  		/// Gets the HTML of the Body part of the webpage.
  		/// </summary>
  		/// <value>The HTML.</value>
          public virtual string Html
  		{
  			get
  			{
  			    return Body != null ? Body.OuterHtml : null;
  			}
  		}
  
          /// <summary>
          /// Gets the Body element of the webpage, or null if none.
          /// </summary>
          /// <value>The body, or null if none.</value>
          public virtual Body Body
          {
              get
              {
                  var body = NativeDocument.Body;
                  return body != null ? new Body(DomContainer, body) : null;
              }
          }
  
  		/// <summary>
  		/// Gets the inner text of the Body part of the webpage.
  		/// </summary>
  		/// <value>The inner text.</value>
          public virtual string Text
  		{
  			get
  			{
  				return Body != null ? Body.Text : null;
  			}
  		}
  
  		/// <summary>
  		/// Returns a System.Uri instance of the url displayed in the address bar of the browser, 
  		/// of the currently displayed web page.
  		/// </summary>
  		/// <example>
  		/// The following example creates a new Internet Explorer instances, navigates to
  		/// the WatiN Project website on SourceForge and writes the Uri of the
  		/// currently displayed webpage to the debug window.
  		/// <code>
  		/// using WatiN.Core;
  		/// using System.Diagnostics;
  		///
  		/// namespace NewIEExample
  		/// {
  		///    public class WatiNWebsite
  		///    {
  		///      public WatiNWebsite()
  		///      {
  		///        IE ie = new IE("http://watin.sourceforge.net");
  		///        Debug.WriteLine(ie.Uri.ToString());
  		///      }
  		///    }
  		///  }
  		/// </code>
  		/// </example>
          public virtual Uri Uri
  		{
  			get { return new Uri(NativeDocument.Url); }
  		}
  
  		/// <summary>
  		/// Returns the url, as displayed in the address bar of the browser, of the currently
  		/// displayed web page.
  		/// </summary>
  		/// <example>
  		/// The following example creates a new Internet Explorer instances, navigates to
  		/// the WatiN Project website on SourceForge and writes the Url of the
  		/// currently displayed webpage to the debug window.
  		/// <code>
  		/// using WatiN.Core;
  		/// using System.Diagnostics;
  		///
  		/// namespace NewIEExample
  		/// {
  		///    public class WatiNWebsite
  		///    {
  		///      public WatiNWebsite()
  		///      {
  		///        IE ie = new IE("http://watin.sourceforge.net");
  		///        Debug.WriteLine(ie.Url);
  		///      }
  		///    }
  		///  }
  		/// </code>
  		/// </example>
          public virtual string Url
  		{
  			get { return NativeDocument.Url; }
  		}
  
  		/// <summary>
  		/// Determines whether the text inside the HTML Body element contains the given <paramref name="text" />.
  		/// </summary>
  		/// <param name="text">The text.</param>
  		/// <returns>
  		///     <c>true</c> if the specified text is contained in <see cref="Html"/>; otherwise, <c>false</c>.
  		/// </returns>
          public virtual bool ContainsText(string text)
  		{
              return NativeDocument.ContainsText(text);
  		}
  
  		/// <summary>
  		/// Determines whether the text inside the HTML Body element contains the given <paramref name="regex" />.
  		/// </summary>
  		/// <param name="regex">The regular expression to match with.</param>
  		/// <returns>
  		///     <c>true</c> if the specified text is contained in <see cref="Html"/>; otherwise, <c>false</c>.
  		/// </returns>
          public virtual bool ContainsText(Regex regex)
  		{
  			var innertext = Text;
  
              return innertext != null && (regex.Match(innertext).Success);
  		}
  
  
          /// <summary>
          /// Waits until the text is inside the HTML Body element contains the given <paramref name="text" />.
          /// Will time out after <see name="Settings.WaitUntilExistsTimeOut" />
          /// </summary>
          /// <param name="text">The text.</param>
          /// <returns>
          ///     <see name="TimeoutException"/> if the specified text is not found within the time out period.
          /// </returns>
          public virtual void WaitUntilContainsText(string text)
          {
              WaitUntilContainsText(text, Settings.WaitUntilExistsTimeOut);
          }
  
  	    /// <summary>
          /// Waits until the text is inside the HTML Body element contains the given <paramref name="text" />.
          /// </summary>
          /// <param name="text">The text.</param>
          /// <param name="timeOut">The number of seconds to wait</param>
          /// <returns>
          ///     <see name="TimeoutException"/> if the specified text is not found within the time out period.
          /// </returns>
          public virtual void WaitUntilContainsText(string text, int timeOut)
          {
              var tryActionUntilTimeOut = new TryFuncUntilTimeOut(TimeSpan.FromSeconds(timeOut))
              {
                  SleepTime = TimeSpan.FromMilliseconds(50),
                  ExceptionMessage = () => string.Format("waiting {0} seconds for document to contain text '{1}'.", timeOut, text)
              };
              tryActionUntilTimeOut.Try(() => ContainsText(text));
          }
  
          /// <summary>
          /// Waits until the <paramref name="regex" /> matches some text inside the HTML Body element.
          /// Will time out after <see name="Settings.WaitUntilExistsTimeOut" />
          /// </summary>
          /// <param name="regex">The regular expression to match with.</param>
          /// <returns>
          ///     <see name="TimeoutException"/> if the specified text is not found within the time out period.
          /// </returns>
          public virtual void WaitUntilContainsText(Regex regex)
          {
              WaitUntilContainsText(regex, Settings.WaitUntilExistsTimeOut);
          }
  
  	    /// <summary>
          /// Waits until the <paramref name="regex" /> matches some text inside the HTML Body element.
          /// </summary>
          /// <param name="regex">The regular expression to match with.</param>
          /// <param name="timeOut">The number of seconds to wait</param>
          /// <returns>
          ///     <see name="TimeoutException"/> if the specified text is not found within the time out period.
          /// </returns>
          public virtual void WaitUntilContainsText(Regex regex, int timeOut)
          {
              var tryActionUntilTimeOut = new TryFuncUntilTimeOut(TimeSpan.FromSeconds(timeOut))
              {
                  SleepTime = TimeSpan.FromMilliseconds(50),
                  ExceptionMessage = () => string.Format("waiting {0} seconds for document to contain regex '{1}'.", timeOut, regex)
              };
              tryActionUntilTimeOut.Try(() => ContainsText(regex));
          }
  
  		/// <summary>
  		/// Gets the text inside the HTML Body element that matches the regular expression.
  		/// </summary>
  		/// <param name="regex">The regular expression to match with.</param>
  		/// <returns>The matching text, or null if none.</returns>
          public virtual string FindText(Regex regex)
  		{
  			var match = regex.Match(Text);
  
  			return match.Success ? match.Value : null;
  		}
  
  		/// <summary>
  		/// Gets the title of the webpage.
  		/// </summary>
  		/// <value>The title.</value>
          public virtual string Title
  		{
  			get { return NativeDocument.Title; }
  		}
  
  		/// <summary>
  		/// Gets the active element in the webpage.
  		/// </summary>
  		/// <value>The active element or <c>null</c> if no element has the focus.</value>
          public virtual Element ActiveElement
  		{
  			get
  			{
  				var activeElement = NativeDocument.ActiveElement;
  			    return activeElement == null ? null : ElementFactory.CreateElement(domContainer, activeElement);
  			}
  		}
  
  		/// <summary>
  		/// Gets the specified frame by its id.
  		/// </summary>
  		/// <param name="id">The id of the frame.</param>
  		/// <exception cref="FrameNotFoundException">Thrown if the given <paramref name="id" /> isn't found.</exception>
          public virtual Frame Frame(string id)
  		{
  			return Frame(Find.ById(id));
  		}
  
  		/// <summary>
  		/// Gets the specified frame by its id.
  		/// </summary>
  		/// <param name="id">The regular expression to match with the id of the frame.</param>
  		/// <exception cref="FrameNotFoundException">Thrown if the given <paramref name="id" /> isn't found.</exception>
          public virtual Frame Frame(Regex id)
  		{
  			return Frame(Find.ById(id));
  		}
  
  		/// <summary>
  		/// Gets the specified frame by its name.
  		/// </summary>
  		/// <param name="findBy">The name of the frame.</param>
  		/// <exception cref="FrameNotFoundException">Thrown if the given name isn't found.</exception>
          public virtual Frame Frame(Constraint findBy)
  		{
  		    var frame = Frames.First(findBy);
              if (frame == null)
              {
                  throw new FrameNotFoundException(findBy.ToString());
              }
  		    return frame;
  		}
  
  		/// <summary>
  		/// Gets a typed collection of <see cref="WatiN.Core.Frame"/> opend within this <see cref="Document"/>.
  		/// </summary>
          public virtual FrameCollection Frames
  		{
  			get { return new FrameCollection(DomContainer, NativeDocument); }
  		}
  
          /// <summary>
          /// Gets the document's DOM container.
          /// </summary>
          public virtual DomContainer DomContainer
  		{
  
gt: 			get { return domContainer; }