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;

using Foo.Platform;
using Foo.GUILib;

namespace Foo.ClientServices.GUIWPForms
{
    internal enum WPForms
    {
        ArtifactWall,
        WorkspaceSelector,
        SettingsNAboutUs,
    }

    /// <summary>
    /// Object Factory Creator for WPForms above
    /// </summary>
    internal class GUIWPFormsObjectFactory
    {            
        /// <summary>
        /// Object Form Factory for all our GUI Forms
        /// </summary>
        /// <param name="form">a WPF form object to create</param>
        /// <param name="bPerformanceCache">true if to create a performanceCache window, should be false all other times</param>
        /// <returns></returns>
        public static Window CreateWPFormWindow(WPForms form, bool bPerformanceCache)
        {
            Window wpfForm = null;
            switch (form)
            {
                case WPForms.ArtifactWall:
                    wpfForm = new ArtifactWall(bPerformanceCache);
                    break;

                case WPForms.WorkspaceSelector:
                    wpfForm = new WorkspaceSelector(bPerformanceCache);
                    break;

                case WPForms.SettingsNAboutUs:
                    wpfForm = new SettingsNAboutUs(bPerformanceCache);
                    break;
            }

            // Imp! - if this is being loaded for performance we must handle it
            WPFHiddenWindow.ExecuteShowOnAHiddenWindow(wpfForm, bPerformanceCache);

            return wpfForm;
        }
    }

    /// <summary>
    /// This class manages the creation/deletion and actions of (1 - n) ButtonForms
    /// </summary>
    [ComVisible(false)]
    internal class GUIFormsMgr
    {

        private const int INITIAL_OBJECT_CAPACITY = 30;
        private Hashtable m_ObjectList = null;        
        private Dispatcher m_Dispatcher = null;

        // load one instance of all wpforms (hidden) cached always, as a performance cache
        private Window[] m_wpfCachedForms = null;
        private bool m_AreWpfFormsCached = false;        

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

        //custom private delegates
        private delegate bool delegate_Create(WPForms wpfFormType);
        private delegate bool delegate_Show(WPForms wpfFormType);        
        private delegate bool delegate_Delete(WPForms wpfFormType);        
        private delegate bool delegate_Action(WPForms wpfFormType, _Action action);

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

        /// <summary>
        /// GUIFormsMgr - Responsible for managing the GUI Window Messaging Threads
        /// </summary>
        /// <param name="disp">Dispatcher Thread Context</param>
        public GUIFormsMgr(Dispatcher disp)
        {
            m_ObjectList = new Hashtable();
            m_Dispatcher = disp;

            if (!m_AreWpfFormsCached)
                BetterPerformance();
        }

        /// <summary>
        /// Calls Create_WpfForm via Dispatcher if neccessary
        /// </summary>        
        /// <param name="wpfFormType">Object type to create</param>
        public bool Create_WpfFormDISP(WPForms wpfFormType)
        {            
            if (m_Dispatcher.Thread == Thread.CurrentThread)
            {
                return Create_WpfForm(wpfFormType);
            }
            else
            {
                object[] parameters = new object[] { wpfFormType };
                return (bool) m_Dispatcher.Invoke((delegate_Create)Create_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
            }         
        }

        /// <summary>
        /// Calls Show_WpfForm via Dispatcher if neccessary
        /// </summary>        
        /// <param name="wpfFormType">Object type to create</param>
        public bool Show_WpfFormDISP(WPForms wpfFormType)
        {
            if (m_Dispatcher.Thread == Thread.CurrentThread)
            {
                return Show_WpfForm(wpfFormType);
            }
            else
            {
                object[] parameters = new object[] { wpfFormType };
                return (bool) m_Dispatcher.Invoke((delegate_Create)Show_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
            }
        }  

        /// <summary>
        /// Calls Delete_WpfForm via Dispatcher if neccessary
        /// </summary>        
        /// <param name="wpfFormType">Object type to delete</param>
        public bool Delete_WpfFormDISP(WPForms wpfFormType)
        {           
            if (m_Dispatcher.Thread == Thread.CurrentThread)
            {
                return Delete_WpfForm(wpfFormType);
            }
            else
            {
                object[] parameters = new object[] { wpfFormType };
                return (bool)m_Dispatcher.Invoke((delegate_Delete)Delete_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
            }           
        }

        /// <summary>
        /// Use this Dispatching Action Function to run any _Action on the WpfForm
        /// </summary>        
        /// <param name="wpfFormType">Object type to run action on</param>
        public bool RunAction_WpfFormDISP(WPForms wpfFormType, _Action action)
        {           
            if (m_Dispatcher.Thread == Thread.CurrentThread)
            {
                return RunAction_WpfForm(wpfFormType, action);
            }
            else
            {
                object[] parameters = new object[] { wpfFormType, action };
                return (bool) m_Dispatcher.Invoke((delegate_Action)RunAction_WpfFormDISP, System.Windows.Threading.DispatcherPriority.Normal, parameters);
            }           
        }

        /// <summary>
        /// Calls Terminate via Dispatcher if neccessary
        /// </summary>        
        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 WpfForm object into the ObjectList
        /// </summary>
        /// <param name="wpfFormType">Object type to run action on</param>
        private bool Create_WpfForm(WPForms wpfFormType)
        {
            try
            {
                if (!m_AreWpfFormsCached)
                    BetterPerformance();

                // we only allow one object * so delete the previous one if exists *
                if (m_ObjectList[wpfFormType] != null)
                    Delete_WpfForm(wpfFormType);                    

                m_ObjectList[wpfFormType] = GUIWPFormsObjectFactory.CreateWPFormWindow(wpfFormType, false);
                Window wpfForm = (Window) m_ObjectList[wpfFormType];

                if (wpfForm == null)
                {
                    Log.Error(string.Format("{0}() - Some Type of Error Occured. wpfForm is null", MethodBase.GetCurrentMethod().Name));
                    return false;
                }
                else
                {
                    return true;
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
            return false;
        }

        /// <summary>
        /// Show a WpfForm object in the ObjectList
        /// </summary>
        /// <param name="wpfFormType">Object type to run action on</param>
        private bool Show_WpfForm(WPForms wpfFormType)
        {
            try
            {                                                
                Window wpfForm = (Window)m_ObjectList[wpfFormType];

                if (wpfForm == null)
                {
                    Log.Error(string.Format("{0}() - Some Type of Error Occured. wpfForm is null", MethodBase.GetCurrentMethod().Name));
                    return false;
                }
                else
                {
                    // We use the InteropHelper to see if this WPFForm has been created previously
                    WindowInteropHelper InteropHelper = new WindowInteropHelper(wpfForm);
                    if (InteropHelper.Handle == IntPtr.Zero)
                    {
                        wpfForm.Show();
                        return true;
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
            return false;
        }

        /// <summary>
        /// Use this function to delete the WpfForm Object
        /// </summary>
        /// <param name="wpfFormType">Object type to run action on</param>
        private bool Delete_WpfForm(WPForms wpfFormType)
        {
            try
            {
                if (m_ObjectList.ContainsKey(wpfFormType))
                {
                    Window wpfForm = (Window)m_ObjectList[wpfFormType];
                    if (wpfForm != null)
                    {
                        m_ObjectList.Remove(wpfFormType);
                        wpfForm.Close();
                        return true;
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
            return false;
        }

        /// <summary>
        /// Use this to run void() function actions on the specified wpfForm
        /// </summary>
        /// <param name="wpfFormType">Object type to run action on</param>
        /// <param name="action">a pointer to a delegate (action function) to run</param>
        private bool RunAction_WpfForm(WPForms wpfFormType, _Action action)
        {
            try
            {
                if (m_ObjectList.ContainsKey(wpfFormType))
                {
                    Window wpfForm = (Window)m_ObjectList[wpfFormType];
                    if (wpfForm != null && action != null)
                    {
                        action(wpfForm);
                        return true;
                    }
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
            return false;
        }
       
        /// <summary>
        /// Kills all ButtonForm Instances (STOPS ALL)
        /// </summary>
        private void Terminate()
        {
            try
            {
                foreach (object o in m_ObjectList)
                {
                    if ((o != null) && (o is Window))
                    {
                        Window WpfForm = (Window)o;
                        WpfForm.Close();
                    }
                }
                m_ObjectList.Clear();

                if (m_AreWpfFormsCached)
                {
                    foreach (Window window in m_wpfCachedForms)
                    {
                        if (window != null)
                            window.Close();
                    }

                    // Caching is incomplete
                    m_AreWpfFormsCached = false;
                }
            }
            catch (Exception e)
            {
                Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
            }
        }

        /// <summary>
        /// In order to improve WPForm performance we have one set of forms
        /// 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_AreWpfFormsCached && (m_wpfCachedForms == null))
            {
                try
                {
                    lock (this)
                    {
                        int nForms = Enum.GetValues(typeof(WPForms)).Length;
                        if (nForms > 0)
                        {                            
                            // Allocate the cached forms array
                            m_wpfCachedForms = new Window[nForms];

                            // Iterate thru enums and create the corresponding objects in the Cache
                            for (int i = 0; i < nForms; ++i)
                            {
                                WPForms form = (WPForms)Enum.ToObject(typeof(WPForms), i);
                                m_wpfCachedForms[i] = GUIWPFormsObjectFactory.CreateWPFormWindow(form, true);
                            }                            

                            // Caching is complete
                            m_AreWpfFormsCached = true;
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.Error(string.Format("{0}() - error thrown", MethodBase.GetCurrentMethod().Name), e);
                }
            }
        }

    }
}
