using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;

using Foo.AddIn.Common;
using System.Drawing;

// Ignore 'Ambiguity' warning message, seems like no way around those
#pragma warning disable 0467

namespace Foo.Addin.Office
{
    public class Excel_Workspace : IWorkspace
    {
        public const string Excel_ProgId = "Excel.Application";

        public FuncRetVal Launch(string strArtifactLocation, int WindowHeight, int WindowWidth, int WindowTop, int WindowLeft)
        {
            FuncRetVal retVal = new FuncRetVal();
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;

            try
            {
                Microsoft.Office.Interop.Excel.Application app = null;
                app = new Microsoft.Office.Interop.Excel.Application();

                // Mark the Application as visible
                app.Visible = true;

                // Position the Window
                IntPtr hWnd = (IntPtr)app.Hwnd;
                Functions.SetWindowPos(hWnd, IntPtr.Zero, WindowLeft, WindowTop, WindowHeight, WindowWidth, 0);

                // Open/Load the Document
                Microsoft.Office.Interop.Excel.Workbook workbook = app.Workbooks.Open(strArtifactLocation, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                                                                        Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                                                                        Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
                if (workbook != null)
                {
                    retVal.Type = FuncRetValEnum.Action_Succeeded;
                }
                else
                {
                    retVal.Type = FuncRetValEnum.Action_Failed;
                }
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;            
        }

        public FuncRetVal Launch(string strArtifactLocation)
        {
            FuncRetVal retVal = new FuncRetVal();
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;            

            try
            {
                Microsoft.Office.Interop.Excel.Application app = null;
                app = new Microsoft.Office.Interop.Excel.Application();

                // Mark the Application as visible
                app.Visible = true;

                Microsoft.Office.Interop.Excel.Workbook workbook = app.Workbooks.Open(strArtifactLocation, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                                                                        Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
                                                                                        Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value);
                if (workbook != null)
                {
                    retVal.Type = FuncRetValEnum.Action_Succeeded;
                }
                else
                {                    
                    retVal.Type = FuncRetValEnum.Action_Failed;
                }
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;
        }

        public FuncRetVal Show(string strArtifactLocation)
        {
            FuncRetVal retVal = new FuncRetVal();
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;
         
            try
            {
                var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Excel.Workbook>();
                foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
                {
                    if (book.FullName.ToLower() == strArtifactLocation.ToLower())
                    {                        
                        var app = book.Application;
                        bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);

                        // If For some reason the App is visible
                        if (app.Visible)
                        {
                            // Make Sure that this Workbook is activated
                            if (!bIsTheOnlyDocumentInApp)
                            {
                                book.Activate();
                                retVal.Type = FuncRetValEnum.Action_Succeeded;
                            }
                            else
                            {
                                retVal.Type = FuncRetValEnum.NoAction_Needed;
                            }                            
                            return retVal;
                        }

                        app.Visible = true;
                        retVal.Type = FuncRetValEnum.Action_Succeeded;
                        return retVal;                        
                    }
                }
                retVal.Type = FuncRetValEnum.ArtifactUnavailable;                
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;           
        }

        public FuncRetVal Hide(string strArtifactLocation)
        {
            FuncRetVal retVal = new FuncRetVal();
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;

            try
            {
                var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Excel.Workbook>();
                foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
                {
                    if (book.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        var app = book.Application;
                        bool bIsTheOnlyDocumentInApp = (app.Workbooks.Count == 1);

                        if (!app.Visible)
                        {
                            retVal.Type = FuncRetValEnum.NoAction_Needed;
                            return retVal;
                        }

                        // If this is NOT the Only open workbook in this App
                        // ~Activate the other workbook
                        if (!bIsTheOnlyDocumentInApp)
                        {
                            foreach (Microsoft.Office.Interop.Excel.Workbook book2 in app.Workbooks)
                            {
                                if (book2.FullName.ToLower() != strArtifactLocation.ToLower())
                                {
                                    book2.Activate();
                                    retVal.Type = FuncRetValEnum.Action_Succeeded;
                                    return retVal;
                                }
                            }
                        }
                        else
                        {
                            app.Visible = false;
                            retVal.Type = FuncRetValEnum.Action_Succeeded;
                            return retVal;
                        }
                    }
                }
                retVal.Type = FuncRetValEnum.ArtifactUnavailable;
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;            
        }

        public FuncRetVal QueryClose(string strArtifactLocation)
        {
            FuncRetVal retVal = new FuncRetVal();
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;

            try
            {
                var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Excel.Workbook>();
                foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
                {
                    if (book.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        if (book.Saved)
                        {
                            retVal.Type = FuncRetValEnum.Action_Succeeded;
                            return retVal;
                        }
                        else
                        {
                            retVal.Type = FuncRetValEnum.Action_Failed;
                            return retVal;
                        }
                    }
                }

                retVal.Type = FuncRetValEnum.ArtifactUnavailable;
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;
        }

        public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact, out int WindowHeight, out int WindowWidth, out int WindowTop, out int WindowLeft)
        {
            FuncRetVal retVal = new FuncRetVal();
            WindowTop = 0;
            WindowLeft = 0;
            WindowWidth = 0;
            WindowHeight = 0;
                                               
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;

            try
            {
                var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Excel.Workbook>();
                foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
                {
                    if (book.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        // In case there is a running rogue excel process left open, 
                        // we can always force it to close by closing the process
                        // int hWnd = app.Hwnd;
                        // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd);
                        var app = book.Application;                        

                        // Get the Window properties
                        IntPtr hWnd = (IntPtr)app.Hwnd;
                        Rectangle rect = Functions.GetWindowRect(hWnd);
                        WindowHeight = rect.Height;
                        WindowWidth = rect.Width;
                        WindowLeft = rect.Left;
                        WindowTop = rect.Top;

                        // Close the Workbook
                        book.Close(bAutoSaveArtifact, strArtifactLocation, false);
                        Marshal.FinalReleaseComObject(book); // force clean-up

                        // Close Excel if this is the last Workbook                            
                        if (app.Workbooks.Count == 0)
                        {
                            app.Quit();
                            Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process
                            //process.Close();
                        }

                        retVal.Type = FuncRetValEnum.Action_Succeeded;
                        return retVal;
                    }
                }

                retVal.Type = FuncRetValEnum.ArtifactUnavailable;
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;
        }

        public FuncRetVal Close(string strArtifactLocation, bool bAutoSaveArtifact)
        {
            FuncRetVal retVal = new FuncRetVal();
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;

            try
            {
                var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Excel.Workbook>();
                foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
                {
                    if (book.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        // In case there is a running rogue excel process left open, 
                        // we can always force it to close by closing the process
                        // int hWnd = app.Hwnd;
                        // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd);
                        var app = book.Application;

                        // Close the Workbook
                        book.Close(bAutoSaveArtifact, strArtifactLocation, false);
                        Marshal.FinalReleaseComObject(book); // force clean-up

                        // Close Excel if this is the last Workbook                            
                        if (app.Workbooks.Count == 0)
                        {
                            app.Quit();
                            Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process
                            //process.Close();
                        }

                        retVal.Type = FuncRetValEnum.Action_Succeeded;
                        return retVal;
                    }
                }

                retVal.Type = FuncRetValEnum.ArtifactUnavailable;
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;
        }

        public FuncRetVal Close(string strArtifactLocation)
        {
            FuncRetVal retVal = new FuncRetVal();
            if (!Validate.IsValidArtifactLocation(strArtifactLocation, ref retVal))
                return retVal;
            
            try
            {
                var RunningExcelWorkbooks = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Excel.Workbook>();
                foreach (Microsoft.Office.Interop.Excel.Workbook book in RunningExcelWorkbooks)
                {
                    if (book.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        // In case there is a running rogue excel process left open, 
                        // we can always force it to close by closing the process
                        // int hWnd = app.Hwnd;
                        // Process process = Win32Functions.GetProcessFromHandle((IntPtr) hWnd);
                        var app = book.Application;

                        // Close the Workbook
                        book.Close(true, strArtifactLocation, false);
                        Marshal.FinalReleaseComObject(book); // force clean-up

                        // Close Excel if this is the last Workbook                            
                        if (app.Workbooks.Count == 0)
                        {
                            app.Quit();
                            Marshal.FinalReleaseComObject(app); // force clean-up, should clean up excel process
                            //process.Close();
                        }

                        retVal.Type = FuncRetValEnum.Action_Succeeded;
                        return retVal;
                    }
                }

                retVal.Type = FuncRetValEnum.ArtifactUnavailable;
            }
            catch (Exception e)
            {
                retVal.Message = e.Message;
                retVal.Type = FuncRetValEnum.ErrorThrown;
            }
            return retVal;            
        }

    }
}
