using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Foo.AddIn.Common;
using System.Runtime.InteropServices;
using System.Reflection;

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

namespace Foo.Addin.Office
{
    public class Word_Workspace : IWorkspace
    {
        public const string Word_ProgId = "Word.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.Word.Application app = null;
                app = Functions.GetCOMObject(Word_ProgId) as Microsoft.Office.Interop.Word.Application;

                // If no existing Word App is open, open a new one
                if (app == null)
                {
                    app = new Microsoft.Office.Interop.Word.Application();
                    app.Visible = true;
                }

                object fileName = strArtifactLocation;
                object missing = Missing.Value;
                Microsoft.Office.Interop.Word.Document doc = null;
                doc = app.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                                         ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);

                if (doc != null)
                {
                    // Find the correct Window and position it
                    foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
                    {
                        if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
                        {
                            window.Top = WindowTop;
                            window.Left = WindowLeft;
                            window.Height = WindowHeight;
                            window.Width = WindowWidth;
                            
                            retVal.Type = FuncRetValEnum.Action_Succeeded;
                            return retVal;
                        }
                    }
                    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.Word.Application app = null;               
                app = Functions.GetCOMObject(Word_ProgId) as Microsoft.Office.Interop.Word.Application;

                // If no existing Word App is open, open a new one
                if (app == null)
                {
                    app = new Microsoft.Office.Interop.Word.Application();
                    app.Visible = true;
                }

                object fileName = strArtifactLocation;
                object missing = Missing.Value;
                Microsoft.Office.Interop.Word.Document doc = null;
                doc = app.Documents.Open(ref fileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                                         ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);

                if (doc != 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 RunningWordDocuments = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Word.Document>();
                foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
                {
                    foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
                    {
                        if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
                        {
                            if (!window.Visible)
                            {
                                window.Visible = true;
                                retVal.Type = FuncRetValEnum.Action_Succeeded;
                                return retVal;
                            }
                            else
                            {
                                retVal.Type = FuncRetValEnum.NoAction_Needed;
                                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 RunningWordDocuments = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Word.Document>();
                foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
                {
                    foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
                    {
                        if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
                        {
                            if (window.Visible)
                            {
                                window.Visible = false;
                                retVal.Type = FuncRetValEnum.Action_Succeeded;
                                return retVal;
                            }
                            else
                            {
                                retVal.Type = FuncRetValEnum.NoAction_Needed;
                                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 RunningWordDocuments = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Word.Document>();
                foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
                {
                    if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        if (doc.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 RunningWordDocuments = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Word.Document>();
                foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
                {
                    if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        // Found the document to close * Close it Without Prompting *                    
                        object saveOption = null;
                        if (bAutoSaveArtifact)
                            saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges;
                        else
                            saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;

                        object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat;
                        object routeDocument = false;
                        var app = doc.Application;

                        // Let's get the Window that belongs to this document
                        Microsoft.Office.Interop.Word.Window docWindow = null;
                        foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
                        {
                            if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
                                docWindow = window;
                        }

                        // Get the Window properties
                        WindowTop = docWindow.Top;
                        WindowLeft = docWindow.Left;
                        WindowWidth = docWindow.Width;
                        WindowHeight = docWindow.Height;

                        //Object missing = Missing.Value;
                        doc.Close(ref saveOption, ref originalFormat, ref routeDocument);
                        Marshal.FinalReleaseComObject(doc); // force clean-up

                        // Close the Window
                        if (docWindow != null)
                            docWindow.Close(ref saveOption, ref routeDocument);

                        // Close Word if this is the Last Document Instance                        
                        if (app.Documents.Count == 0)
                        {
                            app.Quit(ref saveOption, ref originalFormat, ref routeDocument);

                            Marshal.FinalReleaseComObject(docWindow);
                            Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure                            
                        }

                        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 RunningWordDocuments = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Word.Document>();
                foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
                {
                    if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        // Found the document to close * Close it Without Prompting *                    
                        object saveOption = null;
                        if (bAutoSaveArtifact)
                            saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges;
                        else
                            saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdDoNotSaveChanges;

                        object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat;
                        object routeDocument = false;
                        var app = doc.Application;

                        // Let's get the Window that belongs to this document
                        Microsoft.Office.Interop.Word.Window docWindow = null;
                        foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
                        {
                            if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
                                docWindow = window;
                        }

                        //Object missing = Missing.Value;
                        doc.Close(ref saveOption, ref originalFormat, ref routeDocument);
                        Marshal.FinalReleaseComObject(doc); // force clean-up

                        // Close the Window
                        if (docWindow != null)
                            docWindow.Close(ref saveOption, ref routeDocument);

                        // Close Word if this is the Last Document Instance                        
                        if (app.Documents.Count == 0)
                        {
                            app.Quit(ref saveOption, ref originalFormat, ref routeDocument);

                            Marshal.FinalReleaseComObject(docWindow);
                            Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure
                        }

                        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 RunningWordDocuments = Functions.GetRunningObjectsOfType<Microsoft.Office.Interop.Word.Document>();
                foreach (Microsoft.Office.Interop.Word.Document doc in RunningWordDocuments)
                {
                    if (doc.FullName.ToLower() == strArtifactLocation.ToLower())
                    {
                        // Found the document to close * Close it Without Prompting *                    
                        object saveOption = Microsoft.Office.Interop.Word.WdSaveOptions.wdSaveChanges;
                        object originalFormat = Microsoft.Office.Interop.Word.WdOriginalFormat.wdOriginalDocumentFormat;
                        object routeDocument = false;
                        var app = doc.Application;

                        // Let's get the Window that belongs to this document
                        Microsoft.Office.Interop.Word.Window docWindow = null;
                        foreach (Microsoft.Office.Interop.Word.Window window in doc.Windows)
                        {
                            if (window.Document.FullName.ToLower() == strArtifactLocation.ToLower())
                                docWindow = window;
                        }

                        //Object missing = Missing.Value;
                        doc.Close(ref saveOption, ref originalFormat, ref routeDocument);
                        Marshal.FinalReleaseComObject(doc); // force clean-up

                        // Close the Window
                        if (docWindow != null)
                            docWindow.Close(ref saveOption, ref routeDocument);

                        // Close Word if this is the Last Document Instance                        
                        if (app.Documents.Count == 0)
                        {
                            app.Quit(ref saveOption, ref originalFormat, ref routeDocument);

                            Marshal.FinalReleaseComObject(docWindow);
                            Marshal.FinalReleaseComObject(app); // force clean-up, closes Process for sure
                        }

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

    }
}
