using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Windows.Forms;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;

namespace カブラウザもどき
{
    /// <summary>
  /// An extended version of the <see cref="WebBrowser"/> control.
    /// </summary>
    public class ExWebBrowser : System.Windows.Forms.WebBrowser
    {
        ExWebBrowser fb = null;  // New Windows に使うExWebBrowser
        private UnsafeNativeMethods.IWebBrowser2 axIWebBrowser2;
        bool done = false;
        TimeSpan timeout = new TimeSpan(0, 0, 10);

        /// <summary>
        /// This method supports the .NET Framework infrastructure and is not intended to be used directly from your code. 
        /// Called by the control when the underlying ActiveX control is created. 
        /// </summary>
        /// <param name="nativeActiveXObject"></param>
        [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected override void AttachInterfaces(object nativeActiveXObject)
        {
            this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
            base.AttachInterfaces(nativeActiveXObject);
        }

        /// <summary>
        /// This method supports the .NET Framework infrastructure and is not intended to be used directly from your code. 
        /// Called by the control when the underlying ActiveX control is discarded. 
        /// </summary>
        [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected override void DetachInterfaces()
        {
            this.axIWebBrowser2 = null;
            base.DetachInterfaces();
        }

	    /// <summary>
	    /// Returns the automation object for the web browser
	    /// </summary>
        public object ApplicationAx
        { 
          get { return axIWebBrowser2.Application; }
            /*
            get
            {
                if (this.ActiveXInstance == null)
                {
                    throw new AxHost.InvalidActiveXStateException("Application", AxHost.ActiveXInvokeKind.PropertyGet);
                }
                return ((SHDocVw.IWebBrowser2)this.ActiveXInstance).Application;
            }
           */
        }


        System.Windows.Forms.AxHost.ConnectionPointCookie cookie;
        WebBrowserExtendedEvents events;

        /// <summary>
        /// This method will be called to give you a chance to create your own event sink
        /// </summary>
        [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected override void CreateSink()
        {
            // Make sure to call the base class or the normal events won't fire
            base.CreateSink();
            events = new WebBrowserExtendedEvents(this);
            cookie = new AxHost.ConnectionPointCookie(this.ActiveXInstance, events, typeof(UnsafeNativeMethods.DWebBrowserEvents2));
        }

        /// <summary>
        /// Detaches the event sink
        /// </summary>
        [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected override void DetachSink()
        {
            if (null != cookie)
            {
                cookie.Disconnect();
                cookie = null;
            }
        }

        /// <summary>
        /// Fires when downloading of a document begins
        /// </summary>
        public event EventHandler Downloading;

        /// <summary>
        /// Raises the <see cref="Downloading"/> event
        /// </summary>
        /// <param name="e">Empty <see cref="EventArgs"/></param>
        /// <remarks>
        /// You could start an animation or a notification that downloading is starting
        /// </remarks>
        public void OnDownloading(EventArgs e)
        {
            if (Downloading != null)
                Downloading(this, e);
        }

        /// <summary>
        /// Fires when downloading is completed
        /// </summary>
        /// <remarks>
        /// Here you could start monitoring for script errors. 
        /// </remarks>
        public event EventHandler DownloadComplete;
        /// <summary>
        /// Raises the <see cref="DownloadComplete"/> event
        /// </summary>
        /// <param name="e">Empty <see cref="EventArgs"/></param>
        public virtual void OnDownloadComplete(EventArgs e)
        {
            if (DownloadComplete != null)
                DownloadComplete(this, e);
        }


        /// <summary>
        /// Fires before navigation occurs in the given object (on either a window or frameset element).
        /// </summary>
        public event EventHandler<BrowserExtendedNavigatingEventArgs> StartNavigate;
        /// <summary>
        /// Raised when a new window is to be created. Extends DWebBrowserEvents2::NewWindow2 with additional information about the new window.
        /// </summary>
        public event EventHandler<BrowserExtendedNavigatingEventArgs> StartNewWindow;

        /// <summary>
        /// Raises the <see cref="StartNewWindow"/> event
        /// </summary>
        /// <exception cref="ArgumentNullException">Thrown when BrowserExtendedNavigatingEventArgs is null</exception>
        public void OnStartNewWindow(BrowserExtendedNavigatingEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");

            //e.AutomationObject = this.fb.ApplicationAx;
            //this.StartNewWindow = new StartNewWindow();

            if (this.StartNewWindow != null)
                this.StartNewWindow(this, e);
        }

        protected override void OnDocumentCompleted(WebBrowserDocumentCompletedEventArgs e)
        {
            base.OnDocumentCompleted(e);
            // このメソッドが実行されるため実際のURLを確認する
            if (e.Url == this.Url)
            {
                done = true;
            }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="f"></param>
        public ExWebBrowser()
        {
            this.ScriptErrorsSuppressed = true;
        }
        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="f"></param>
        public ExWebBrowser(ExWebBrowser f)
        {
            this.ScriptErrorsSuppressed = true;
            this.fb = f;
        }

        public void SetFb(ExWebBrowser f) {
            this.fb = f;
        }
        
        /// <summary>
        /// Raises the <see cref="StartNavigate"/> event
        /// </summary>
        /// <exception cref="ArgumentNullException">Thrown when BrowserExtendedNavigatingEventArgs is null</exception>
        public void OnStartNavigate(BrowserExtendedNavigatingEventArgs e)
        {
          if (e == null)
            throw new ArgumentNullException("e");

          if (this.StartNavigate != null)
            this.StartNavigate(this, e);
        }

        /// <summary>
        /// 同期ナビゲート
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public bool NavigateAndWait(string url)
        {
            this.Refresh(WebBrowserRefreshOption.Completely);
            base.Navigate(new Uri(url)); // ページの移動

            done = false;
            DateTime start = DateTime.Now;

            while (done == false)
            {
                if (DateTime.Now - start > timeout)
                {
                    // タイムアウト
                    return false;
                }
                Application.DoEvents();
            }
            return true;
        }
    }

    public delegate void WebBrowserNewWindow2EventHandler(object sender, WebBrowserNewWindow2EventArgs e);
    public class WebBrowserNewWindow2EventArgs : System.ComponentModel.CancelEventArgs
    {
        private object ppDispValue;

        public WebBrowserNewWindow2EventArgs(object ppDisp)
        {
            this.ppDispValue = ppDisp;
        }
        public object ppDisp
        {
            get
            {
                return ppDispValue;
            }
            set
            {
                ppDispValue = value;
            }
        }
    }

    #region The Implementation of DWebBrowserEvents2 for firing extra events

    //This class will capture events from the WebBrowser
    class WebBrowserExtendedEvents : UnsafeNativeMethods.DWebBrowserEvents2
    {
        public WebBrowserExtendedEvents() { }

        ExWebBrowser _Browser;
        public WebBrowserExtendedEvents(ExWebBrowser browser) { _Browser = browser; }

        #region DWebBrowserEvents2 Members

        //Implement whichever events you wish
        public void BeforeNavigate2(object pDisp, ref object URL, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel)
        {
            Uri urlUri = new Uri(URL.ToString());

            string tFrame = null;
            if (targetFrameName != null)
                tFrame = targetFrameName.ToString();

            BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(pDisp, urlUri, tFrame, UrlContext.None);
            _Browser.OnStartNavigate(args);

            cancel = args.Cancel;
            pDisp = args.AutomationObject;
        }

        //The NewWindow2 event, used on Windows XP SP1 and below
        public void NewWindow2(ref object pDisp, ref bool cancel)
        {
            BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(pDisp, null, null, UrlContext.None);
            _Browser.OnStartNewWindow(args);
            cancel = args.Cancel;
            pDisp = args.AutomationObject;
        }

        // NewWindow3 event, used on Windows XP SP2 and higher
        public void NewWindow3(ref object ppDisp, ref bool Cancel, uint dwFlags, string bstrUrlContext, string bstrUrl)
        {
            BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(ppDisp, new Uri(bstrUrl), null, (UrlContext)dwFlags);
            _Browser.OnStartNewWindow(args);
            Cancel = args.Cancel;
            ppDisp = args.AutomationObject;
        }

        // Fired when downloading begins
        public void DownloadBegin()
        {
            _Browser.OnDownloading(EventArgs.Empty);
        }

        // Fired when downloading is completed
        public void DownloadComplete()
        {
            _Browser.OnDownloadComplete(EventArgs.Empty);
        }

        #region Unused events

        // This event doesn't fire. 
        [DispId(0x00000107)]
        public void WindowClosing(bool isChildWindow, ref bool cancel)
        {
        }

        public void OnQuit()
        {

        }

        public void StatusTextChange(string text)
        {
        }

        public void ProgressChange(int progress, int progressMax)
        {
        }

        public void TitleChange(string text)
        {
        }

        public void PropertyChange(string szProperty)
        {
        }

        public void NavigateComplete2(object pDisp, ref object URL)
        {
        }

        public void DocumentComplete(object pDisp, ref object URL)
        {
        }

        public void OnVisible(bool visible)
        {
        }

        public void OnToolBar(bool toolBar)
        {
        }

        public void OnMenuBar(bool menuBar)
        {
        }

        public void OnStatusBar(bool statusBar)
        {
        }

        public void OnFullScreen(bool fullScreen)
        {
        }

        public void OnTheaterMode(bool theaterMode)
        {
        }

        public void WindowSetResizable(bool resizable)
        {
        }

        public void WindowSetLeft(int left)
        {
        }

        public void WindowSetTop(int top)
        {
        }

        public void WindowSetWidth(int width)
        {
        }

        public void WindowSetHeight(int height)
        {
        }

        public void SetSecureLockIcon(int secureLockIcon)
        {
        }

        public void FileDownload(ref bool cancel)
        {
        }

        public void NavigateError(object pDisp, ref object URL, ref object frame, ref object statusCode, ref bool cancel)
        {
        }

        public void PrintTemplateInstantiation(object pDisp)
        {
        }

        public void PrintTemplateTeardown(object pDisp)
        {
        }

        public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone)
        {
        }

        public void PrivacyImpactedStateChange(bool bImpacted)
        {
        }

        public void CommandStateChange(int Command, bool Enable)
        {
        }

        public void ClientToHostWindow(ref int CX, ref int CY)
        {
        }
        #endregion

        #endregion
    }

    #endregion
}
