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

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>
		/// コンストラクタ
		/// </summary>
		public ExWebBrowser()
		{
			  this.ScriptErrorsSuppressed = true;
		}
		/// <summary>
		/// コンストラクタ
		/// </summary>
		/// <param name="f"></param>
		public ExWebBrowser(ExWebBrowser f)
		{
			  this.ScriptErrorsSuppressed = true;
			  this.fb = f;
		}
		
		
		/// <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>
		protected 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>
		protected 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>
		protected 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>
		/// Raises the <see cref="StartNavigate"/> event
		/// </summary>
		/// <exception cref="ArgumentNullException">Thrown when BrowserExtendedNavigatingEventArgs is null</exception>
		protected 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;
		}


	#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

	#region Raises the Quit event when the browser window is about to be destroyed

	/// <summary>
	/// Overridden
	/// </summary>
	/// <param name="m">The <see cref="Message"/> send to this procedure</param>
	[PermissionSet(SecurityAction.LinkDemand, Name="FullTrust")] 
	protected override void WndProc(ref Message m)
	{
		if (m.Msg == (int)WindowsMessages.WM_PARENTNOTIFY)
		{
			//int lp = m.LParam.ToInt32();
			int wp = m.WParam.ToInt32();

			int X = wp & 0xFFFF;
			//int Y = (wp >> 16) & 0xFFFF;
			if (X == (int)WindowsMessages.WM_DESTROY)
				this.OnQuit();
		}
		base.WndProc(ref m);
	}

	/// <summary>
	/// A list of all the available window messages
	/// </summary>
	enum WindowsMessages
	{
		WM_ACTIVATE = 0x6,
		WM_ACTIVATEAPP = 0x1C,
		WM_AFXFIRST = 0x360,
		WM_AFXLAST = 0x37F,
		WM_APP = 0x8000,
		WM_ASKCBFORMATNAME = 0x30C,
		WM_CANCELJOURNAL = 0x4B,
		WM_CANCELMODE = 0x1F,
		WM_CAPTURECHANGED = 0x215,
		WM_CHANGECBCHAIN = 0x30D,
		WM_CHAR = 0x102,
		WM_CHARTOITEM = 0x2F,
		WM_CHILDACTIVATE = 0x22,
		WM_CLEAR = 0x303,
		WM_CLOSE = 0x10,
		WM_COMMAND = 0x111,
		WM_COMPACTING = 0x41,
		WM_COMPAREITEM = 0x39,
		WM_CONTEXTMENU = 0x7B,
		WM_COPY = 0x301,
		WM_COPYDATA = 0x4A,
		WM_CREATE = 0x1,
		WM_CTLCOLORBTN = 0x135,
		WM_CTLCOLORDLG = 0x136,
		WM_CTLCOLOREDIT = 0x133,
		WM_CTLCOLORLISTBOX = 0x134,
		WM_CTLCOLORMSGBOX = 0x132,
		WM_CTLCOLORSCROLLBAR = 0x137,
		WM_CTLCOLORSTATIC = 0x138,
		WM_CUT = 0x300,
		WM_DEADCHAR = 0x103,
		WM_DELETEITEM = 0x2D,
		WM_DESTROY = 0x2,
		WM_DESTROYCLIPBOARD = 0x307,
		WM_DEVICECHANGE = 0x219,
		WM_DEVMODECHANGE = 0x1B,
		WM_DISPLAYCHANGE = 0x7E,
		WM_DRAWCLIPBOARD = 0x308,
		WM_DRAWITEM = 0x2B,
		WM_DROPFILES = 0x233,
		WM_ENABLE = 0xA,
		WM_ENDSESSION = 0x16,
		WM_ENTERIDLE = 0x121,
		WM_ENTERMENULOOP = 0x211,
		WM_ENTERSIZEMOVE = 0x231,
		WM_ERASEBKGND = 0x14,
		WM_EXITMENULOOP = 0x212,
		WM_EXITSIZEMOVE = 0x232,
		WM_FONTCHANGE = 0x1D,
		WM_GETDLGCODE = 0x87,
		WM_GETFONT = 0x31,
		WM_GETHOTKEY = 0x33,
		WM_GETICON = 0x7F,
		WM_GETMINMAXINFO = 0x24,
		WM_GETOBJECT = 0x3D,
		WM_GETTEXT = 0xD,
		WM_GETTEXTLENGTH = 0xE,
		WM_HANDHELDFIRST = 0x358,
		WM_HANDHELDLAST = 0x35F,
		WM_HELP = 0x53,
		WM_HOTKEY = 0x312,
		WM_HSCROLL = 0x114,
		WM_HSCROLLCLIPBOARD = 0x30E,
		WM_ICONERASEBKGND = 0x27,
		WM_IME_CHAR = 0x286,
		WM_IME_COMPOSITION = 0x10F,
		WM_IME_COMPOSITIONFULL = 0x284,
		WM_IME_CONTROL = 0x283,
		WM_IME_ENDCOMPOSITION = 0x10E,
		WM_IME_KEYDOWN = 0x290,
		WM_IME_KEYLAST = 0x10F,
		WM_IME_KEYUP = 0x291,
		WM_IME_NOTIFY = 0x282,
		WM_IME_REQUEST = 0x288,
		WM_IME_SELECT = 0x285,
		WM_IME_SETCONTEXT = 0x281,
		WM_IME_STARTCOMPOSITION = 0x10D,
		WM_INITDIALOG = 0x110,
		WM_INITMENU = 0x116,
		WM_INITMENUPOPUP = 0x117,
		WM_INPUTLANGCHANGE = 0x51,
		WM_INPUTLANGCHANGEREQUEST = 0x50,
		WM_KEYDOWN = 0x100,
		WM_KEYFIRST = 0x100,
		WM_KEYLAST = 0x108,
		WM_KEYUP = 0x101,
		WM_KILLFOCUS = 0x8,
		WM_LBUTTONDBLCLK = 0x203,
		WM_LBUTTONDOWN = 0x201,
		WM_LBUTTONUP = 0x202,
		WM_MBUTTONDBLCLK = 0x209,
		WM_MBUTTONDOWN = 0x207,
		WM_MBUTTONUP = 0x208,
		WM_MDIACTIVATE = 0x222,
		WM_MDICASCADE = 0x227,
		WM_MDICREATE = 0x220,
		WM_MDIDESTROY = 0x221,
		WM_MDIGETACTIVE = 0x229,
		WM_MDIICONARRANGE = 0x228,
		WM_MDIMAXIMIZE = 0x225,
		WM_MDINEXT = 0x224,
		WM_MDIREFRESHMENU = 0x234,
		WM_MDIRESTORE = 0x223,
		WM_MDISETMENU = 0x230,
		WM_MDITILE = 0x226,
		WM_MEASUREITEM = 0x2C,
		WM_MENUCHAR = 0x120,
		WM_MENUCOMMAND = 0x126,
		WM_MENUDRAG = 0x123,
		WM_MENUGETOBJECT = 0x124,
		WM_MENURBUTTONUP = 0x122,
		WM_MENUSELECT = 0x11F,
		WM_MOUSEACTIVATE = 0x21,
		WM_MOUSEFIRST = 0x200,
		WM_MOUSEHOVER = 0x2A1,
		WM_MOUSELAST = 0x20A,
		WM_MOUSELEAVE = 0x2A3,
		WM_MOUSEMOVE = 0x200,
		WM_MOUSEWHEEL = 0x20A,
		WM_MOVE = 0x3,
		WM_MOVING = 0x216,
		WM_NCACTIVATE = 0x86,
		WM_NCCALCSIZE = 0x83,
		WM_NCCREATE = 0x81,
		WM_NCDESTROY = 0x82,
		WM_NCHITTEST = 0x84,
		WM_NCLBUTTONDBLCLK = 0xA3,
		WM_NCLBUTTONDOWN = 0xA1,
		WM_NCLBUTTONUP = 0xA2,
		WM_NCMBUTTONDBLCLK = 0xA9,
		WM_NCMBUTTONDOWN = 0xA7,
		WM_NCMBUTTONUP = 0xA8,
		WM_NCMOUSEHOVER = 0x2A0,
		WM_NCMOUSELEAVE = 0x2A2,
		WM_NCMOUSEMOVE = 0xA0,
		WM_NCPAINT = 0x85,
		WM_NCRBUTTONDBLCLK = 0xA6,
		WM_NCRBUTTONDOWN = 0xA4,
		WM_NCRBUTTONUP = 0xA5,
		WM_NEXTDLGCTL = 0x28,
		WM_NEXTMENU = 0x213,
		WM_NOTIFY = 0x4E,
		WM_NOTIFYFORMAT = 0x55,
		WM_NULL = 0x0,
		WM_PAINT = 0xF,
		WM_PAINTCLIPBOARD = 0x309,
		WM_PAINTICON = 0x26,
		WM_PALETTECHANGED = 0x311,
		WM_PALETTEISCHANGING = 0x310,
		WM_PARENTNOTIFY = 0x210,
		WM_PASTE = 0x302,
		WM_PENWINFIRST = 0x380,
		WM_PENWINLAST = 0x38F,
		WM_POWER = 0x48,
		WM_PRINT = 0x317,
		WM_PRINTCLIENT = 0x318,
		WM_QUERYDRAGICON = 0x37,
		WM_QUERYENDSESSION = 0x11,
		WM_QUERYNEWPALETTE = 0x30F,
		WM_QUERYOPEN = 0x13,
		WM_QUEUESYNC = 0x23,
		WM_QUIT = 0x12,
		WM_RBUTTONDBLCLK = 0x206,
		WM_RBUTTONDOWN = 0x204,
		WM_RBUTTONUP = 0x205,
		WM_RENDERALLFORMATS = 0x306,
		WM_RENDERFORMAT = 0x305,
		WM_SETCURSOR = 0x20,
		WM_SETFOCUS = 0x7,
		WM_SETFONT = 0x30,
		WM_SETHOTKEY = 0x32,
		WM_SETICON = 0x80,
		WM_SETREDRAW = 0xB,
		WM_SETTEXT = 0xC,
		WM_SETTINGCHANGE = 0x1A,
		WM_SHOWWINDOW = 0x18,
		WM_SIZE = 0x5,
		WM_SIZECLIPBOARD = 0x30B,
		WM_SIZING = 0x214,
		WM_SPOOLERSTATUS = 0x2A,
		WM_STYLECHANGED = 0x7D,
		WM_STYLECHANGING = 0x7C,
		WM_SYNCPAINT = 0x88,
		WM_SYSCHAR = 0x106,
		WM_SYSCOLORCHANGE = 0x15,
		WM_SYSCOMMAND = 0x112,
		WM_SYSDEADCHAR = 0x107,
		WM_SYSKEYDOWN = 0x104,
		WM_SYSKEYUP = 0x105,
		WM_TCARD = 0x52,
		WM_TIMECHANGE = 0x1E,
		WM_TIMER = 0x113,
		WM_UNDO = 0x304,
		WM_UNINITMENUPOPUP = 0x125,
		WM_USER = 0x400,
		WM_USERCHANGED = 0x54,
		WM_VKEYTOITEM = 0x2E,
		WM_VSCROLL = 0x115,
		WM_VSCROLLCLIPBOARD = 0x30A,
		WM_WINDOWPOSCHANGED = 0x47,
		WM_WINDOWPOSCHANGING = 0x46,
		WM_WININICHANGE = 0x1A
	}

	/// <summary>
	/// Raises the <see cref="Quit"/> event
	/// </summary>
	protected void OnQuit()
	{
		EventHandler h = Quit;
		if (null != h)
			h(this, EventArgs.Empty);
	}

	/// <summary>
	/// Raised when the browser application quits
	/// </summary>
	/// <remarks>
	/// Do not confuse this with DWebBrowserEvents2.Quit... That's something else.
	/// </remarks>
	public event EventHandler Quit;


	#endregion
  }

}
