using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Drawing;
using System.Threading;
using System.Windows.Interop;
using System.EnterpriseServices;
using System.Windows;
using System.IO;
using System.Windows.Threading;
using System.Collections;
using System.Reflection;

// Ooganizer Namespaces
using Foo.Platform;
using Foo.Platform.Win32;

namespace Foo.ClientServices.ButtonWPForm
{
    /// <summary>
    /// This class manages the creation/deletion and actions of (1 - n) ButtonForms
    /// </summary>
    [ComVisible(false)]
    internal class ButtonFormMgr
    {
        private const int INITIAL_OBJECT_CAPACITY = 30;
        private Hashtable m_ObjectList = null;        
        private Dispatcher m_Dispatcher = null;

        // we have one btnForm loaded (hidden) always, as a performance cache
        private ButtonForm m_btnForm = null;
        private bool m_IsBtnFormCached = false;

        // Imp! - allows external caller to run any action on a ButtonForm
        public delegate void _Action(ButtonForm btnForm);

        //custom private delegates
        private delegate void delegate_Create(int hParentWND, Image snapshot);
        private delegate void delegate_Delete(int hParentWND);
        private delegate int delegate_CreateWindow(int hParentWND);
        private delegate void delegate_Action(int hParentWND, _Action action);

        // Declare the Log4net Variable        
        private static log4net.ILog Log = Logger.GetLog4NetInterface(MethodBase.GetCurrentMethod().DeclaringType);

        public ButtonFormMgr(Dispatcher disp)
        {
            m_ObjectList = new Hashtable();
            m_Dispatcher = disp;

            if (!m_IsBtnFormCached)
                BetterPerformance();
        }

        /// <summary>
        /// Calls Create_ButtonForm via Dispatcher if neccessary
        /// </summary>        
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        public void Create_ButtonFormDISP(int hParentWND, Image snapshot)
        {
            if (hParentWND != 0)
            {
                if (m_Dispatcher.Thread == Thread.CurrentThread)
                {
                    Create_ButtonForm(hParentWND, snapshot);
                }
                else
                {
                    object[] parameters = new object[] { hParentWND, snapshot };
                    m_Dispatcher.Invoke((delegate_Create)Create_ButtonFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
                }
            }
        }

        /// <summary>
        /// Calls Create_ButtonFormWindow via Dispatcher if neccessary
        /// </summary>        
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        public int Create_ButtonFormWindowDISP(int hParentWND)
        {
            if (hParentWND != 0)
            {
                if (m_Dispatcher.Thread == Thread.CurrentThread)
                {
                    return Create_ButtonFormWindow(hParentWND);
                }
                else
                {
                    object[] parameters = new object[] { hParentWND };
                    return (int)m_Dispatcher.Invoke((delegate_CreateWindow)Create_ButtonFormWindowDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
                }
            }
            return 0;
        }

        /// <summary>
        /// Calls Delete_ButtonForm via Dispatcher if neccessary
        /// </summary>        
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        public void Delete_ButtonFormDISP(int hParentWND)
        {
            if (hParentWND != 0)
            {
                if (m_Dispatcher.Thread == Thread.CurrentThread)
                {
                    Delete_ButtonForm(hParentWND);
                }
                else
                {
                    object[] parameters = new object[] { hParentWND };
                    m_Dispatcher.Invoke((delegate_Delete)Delete_ButtonFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
                }
            }
        }

        /// <summary>
        /// Use this Dispatching Action Function to run any _Action on the ButtonForm
        /// </summary>        
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        public void RunAction_ButtonFormDISP(int hParentWND, _Action action)
        {
            if (hParentWND != 0)
            {
                if (m_Dispatcher.Thread == Thread.CurrentThread)
                {
                    RunAction_ButtonForm(hParentWND, action);
                }
                else
                {
                    object[] parameters = new object[] { hParentWND, action };
                    m_Dispatcher.Invoke((delegate_Action)RunAction_ButtonFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
                }
            }
        }

        /// <summary>
        /// Calls Terminate via Dispatcher if neccessary
        /// </summary>
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        public void TerminateDISP()
        {
            if (m_Dispatcher.Thread == Thread.CurrentThread)
            {
                Terminate();
            }
            else
            {
                m_Dispatcher.Invoke((Action)TerminateDISP, System.Windows.Threading.DispatcherPriority.Normal, null);
            }
        }

        /// <summary>
        /// Creates a new ButtonForm object into the ObjectList
        /// </summary>
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        private void Create_ButtonForm(int hParentWND, Image snapshot)
        {
            try
            {
                if (!m_IsBtnFormCached)
                    BetterPerformance();

                m_ObjectList[hParentWND] = new ButtonForm();
                ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];

                if (btnForm != null)
                {
                    // We use the InteropHelper to set the Owner Property
                    WindowInteropHelper InteropHelper = new WindowInteropHelper(btnForm);
                    InteropHelper.Owner = (IntPtr)hParentWND;

                    // Set the important Fields into the Button Form
                    btnForm.HookedWindow = (IntPtr)hParentWND; // give it the handle to the hooked window                    
                    btnForm.SnapShot = snapshot;               // give it the snapshot of the window                    

                    RECT ParentWndRect = new RECT();
                    Win32Functions.GetWindowRect((IntPtr)hParentWND, out ParentWndRect);

                    // Get Initial Location for the form
                    btnForm.Top = ParentWndRect.top;
                    btnForm.Left = ParentWndRect.left;

                    // Get Initial Height and Width of the form
                    btnForm.Height = (ParentWndRect.bottom - ParentWndRect.top);
                    btnForm.Width = (ParentWndRect.right - ParentWndRect.left);
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
        }

        /// <summary>
        /// Use this function to delete the ButtonForm Object
        /// </summary>
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        private void Delete_ButtonForm(int hParentWND)
        {
            try
            {
                if (m_ObjectList.ContainsKey(hParentWND))
                {
                    ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];
                    if (btnForm != null)
                    {
                        m_ObjectList.Remove(hParentWND);
                        btnForm.Close();
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
        }

        /// <summary>
        /// Use this to run void() function actions on the specified buttonform
        /// </summary>
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        /// <param name="action">a pointer to a delegate (action function) to run</param>
        private void RunAction_ButtonForm(int hParentWND, _Action action)
        {
            try
            {
                if (m_ObjectList.ContainsKey(hParentWND))
                {
                    ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];
                    if (btnForm != null)
                        action(btnForm);
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
        }

        /// <summary>
        /// Use this to actually create the Window, call this after calling Create_ButtonForm
        /// This will create the window by calling Show(), this will also show the window
        /// </summary>
        /// <param name="hParentWND">handle to Parent/Owner Window</param>
        /// <returns>the Handle to the newly created window object</returns>
        private int Create_ButtonFormWindow(int hParentWND)
        {
            try
            {
                if (m_ObjectList.ContainsKey(hParentWND))
                {
                    ButtonForm btnForm = (ButtonForm)m_ObjectList[hParentWND];

                    // We use the InteropHelper to see if this WPFForm has been created previously
                    WindowInteropHelper InteropHelper = new WindowInteropHelper(btnForm);
                    if (InteropHelper.Handle == IntPtr.Zero)
                    {
                        btnForm.Show();
                    }
                    return (int)InteropHelper.Handle;
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
            return 0;
        }

        /// <summary>
        /// Kills all ButtonForm Instances (STOPS ALL)
        /// </summary>
        private void Terminate()
        {
            try
            {
                foreach (object o in m_ObjectList)
                {
                    if ((o != null) && (o is ButtonForm))
                    {
                        ButtonForm btnForm = (ButtonForm)o;
                        btnForm.Close();
                    }
                }
                m_ObjectList.Clear();

                if (m_IsBtnFormCached)
                {
                    m_btnForm.Close();
                    m_IsBtnFormCached = false;
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
        }

        /// <summary>
        /// In order to improve first WPForm performance we have one
        /// WPForm ButtonForm loaded at all times. (opacity set to 0).
        /// ~it has no parent setting so it is just a form of the desktop
        /// </summary>
        private void BetterPerformance()
        {
            if (!m_IsBtnFormCached)
            {
                try
                {
                    // Performance Cache (keeps a window loaded always)
                    m_btnForm = new ButtonForm(true);
                    m_btnForm.LoadHideButtonFormPerfCache();
                    m_IsBtnFormCached = true;
                }
                catch (Exception e)
                {
                    Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
                }
            }
        }
    }
}
