using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Permissions;
using System.Runtime.InteropServices;


namespace CaLib.User
{
	/// <summary>
	/// ClipboardViewerクラスは、NativeWindowの派生クラスとして宣言する。
	/// これにより、このクラスを“サブクラス化”できる。
	/// サブクラス化することで、元のウィンドウに送られてくるWindowsメッセージを
	/// サブクラス（ここではMyClipboardViewer）側で先に受け取ることができ、
	/// 元のウィンドウのメッセージ処理には手を加えずに、Windowsメッセージ
	/// （ここで利用するのはクリップボード関連のメッセージ）を処理できるようになる。
	/// </summary>
	/// <see cref="http://www.atmarkit.co.jp/fdotnet/dotnettips/848cbviewer/cbviewer.html"/>
	[PermissionSet(SecurityAction.Demand,Name = "FullTrust")]
	public class ClipboardViewer : System.Windows.Forms.NativeWindow
	{
		private IntPtr nextHandle;

		private System.Windows.Forms.Form parent;
		//public event cbEventHandler ClipboardHandler;
		public event cbEventNotifyHandler ClipboardNotifyHandler;
		

		/// <summary>
		/// 履歴保存のオン・オフ
		/// </summary> 
		public bool Valid
		{
			get;
			set;
		}

		public ClipboardViewer(System.Windows.Forms.Form f)
		{
			f.HandleCreated	+= new EventHandler(this.OnHandleCreated);
			f.HandleDestroyed += new EventHandler(this.OnHandleDestroyed);
			this.parent = f;

			this.Valid = true;
		}

		internal void OnHandleCreated(object sender, EventArgs e)
		{
			AssignHandle(((System.Windows.Forms.Form)sender).Handle);

			// ビューアを登録
			nextHandle = WinApi.User32.SetClipboardViewer(this.Handle);
		}

		internal void OnHandleDestroyed(object sender, EventArgs e)
		{
			// ビューアを解除
			bool sts = WinApi.User32.ChangeClipboardChain(this.Handle, nextHandle);
			ReleaseHandle();
		}

		protected override void WndProc(ref System.Windows.Forms.Message msg)
		{
			switch (msg.Msg)
			{
				case (int)WinApi.Message.id.WM_DRAWCLIPBOARD:

					if (ClipboardNotifyHandler != null)
					{
						ClipboardEventNotifyArgs.DataKind dk = ClipboardEventNotifyArgs.DataKind.data;
						if (System.Windows.Forms.Clipboard.ContainsText())
						{
							dk = ClipboardEventNotifyArgs.DataKind.text;
						}
						else if (System.Windows.Forms.Clipboard.ContainsAudio())
						{
							dk = ClipboardEventNotifyArgs.DataKind.audio;
						}
						else if (System.Windows.Forms.Clipboard.ContainsFileDropList())
						{
							dk = ClipboardEventNotifyArgs.DataKind.fileDropList;
						}
						else if (System.Windows.Forms.Clipboard.ContainsImage())
						{
							dk = ClipboardEventNotifyArgs.DataKind.image;
						}

						ClipboardNotifyHandler(this, new ClipboardEventNotifyArgs(dk));
					}

					//if (System.Windows.Forms.Clipboard.ContainsText())
					//{
					//    // クリップボードの内容がテキストの場合のみ
					//    if (ClipboardHandler != null)
					//    {
					//        string buffer = null;
					//        try
					//        {
					//            buffer = System.Windows.Forms.Clipboard.GetText();
					//        }
					//        catch (ExternalException e)
					//        {
					//            //クリップボードをクリアできませんでした。この例外は、通常、クリップボードが別のプロセスで使用されている場合に発生します。
					//            System.Diagnostics.Trace.WriteLine("Clipboard exception " + e.Message);
					//        }
					//
					//        System.Diagnostics.Trace.WriteLine(string.Format("Clipboard text {0}", string.IsNullOrEmpty(buffer) ? "null" : buffer));
					//
					//        if (buffer != null)
					//        {
					//            // クリップボードの内容を取得してハンドラを呼び出す
					//            ClipboardHandler(this, new ClipboardEventArgs(buffer));
					//        }
					//    }
					//    else
					//    {
					//        System.Diagnostics.Trace.WriteLine("Clipboard handler is null");
					//    }
					//}
					//else {
					//    System.Windows.Forms.IDataObject iData = System.Windows.Forms.Clipboard.GetDataObject();
					//    if (iData != null)
					//    {
					//        System.Diagnostics.Trace.WriteLine("Clipboard has " + iData.GetType().ToString());
					//    }
					//}

					if ((int)nextHandle != 0)
						WinApi.User32.SendMessage(nextHandle, msg.Msg, msg.WParam, msg.LParam);
					break;

				// クリップボード・ビューア・チェーンが更新された
				case (int)WinApi.Message.id.WM_CHANGECBCHAIN:
					if (msg.WParam == nextHandle)
					{
						nextHandle = (IntPtr)msg.LParam;

						System.Diagnostics.Trace.WriteLine("クリップボード・ビューア・チェーンが更新された A");
					}
					else if ((int)nextHandle != 0)
					{
						WinApi.User32.SendMessage(nextHandle, msg.Msg, msg.WParam, msg.LParam);

						System.Diagnostics.Trace.WriteLine("クリップボード・ビューア・チェーンが更新された B");
					}
					else{
						System.Diagnostics.Trace.WriteLine("クリップボード・ビューア・チェーンが更新された C");
					}
					break;
			}
			base.WndProc(ref msg);
		}
	}
}
