using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.Office.Interop.Word;
//using Word = Microsoft.Office.Interop.Word;
//using Office = Microsoft.Office.Core;
//using Microsoft.Office.Tools.Word;
//using Microsoft.Office.Tools;
//using Microsoft.Office.Core;
using System.IO;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Range = Microsoft.Office.Interop.Word.Range;
using Microsoft.Office.Core;
//using Microsoft.Vbe.Interop;

namespace OfficeAppHelp.Word
{
    /// <summary>
    /// Word应用
    /// </summary>
    public class WordApp
    {
        /// <summary>
        /// 查找符：软回车，同html中的br
        /// </summary>
        public const string Find_BlankRow = "^l";
        /// <summary>
        /// 查找符：制表符，相当于按了一下TAB键
        /// </summary>
        public const string Find_Tab = "^t";
        /// <summary>
        /// 查找符：段落
        /// </summary>
        public const string Find_Paragraph = "^p";
        /// <summary>
        /// 查找符：段落 通配符
        /// </summary>
        public const string Find_ParagraphASCII = "^13";

        private OfficeType _AppType = OfficeType.Null;
        /// <summary>
        /// Office类型
        /// </summary>
        public OfficeType AppType
        {
            get
            {
                if (_AppType != OfficeType.Null)
                    return _AppType;

                if (File.Exists(App.Path + "/wps.exe") || File.Exists(App.Path + "wpsoffice.exe"))
                    _AppType = OfficeType.WPS;
                else if (File.Exists(App.Path + "/MSOHTMED.EXE") || File.Exists(App.Path + "MSQRY32.EXE"))
                    _AppType = OfficeType.Microsoft;
                else
                    _AppType = OfficeType.Unknown;

                return _AppType;
            }
            private set { _AppType = value; }
        }

        /// <summary>
        /// 整个应用程序
        /// </summary>
        public Application App { get; private set; }

        /// <summary>
        /// 活动中（正在操作）的Word文档
        /// </summary>
        public Document Doc { get; set; }

        /// <summary>
        /// 是否存在文件路径
        /// </summary>
        public bool IsExistFilePath { get => Doc.FullName.Contains(':'); }

        ///// <summary>
        ///// 初始化程序和活动中的word （vsto）
        ///// </summary>
        //public WordApp()
        //{
        //    App = Globals.ThisAddIn.Application;
        //    try
        //    {
        //        Doc = App.ActiveDocument;
        //    }
        //    catch { }
        //}

        /// <summary>
        /// 初始化word程序
        /// </summary>
        public WordApp()
        {
            var wordObj = OfficeApp.GetProcessesWordApp(out OfficeType officeType);
            if (wordObj == null)
                App = new Application();
            else
            {
                App = (Application)wordObj;
                AppType = officeType;
            }

            Doc = null;
        }

        /// <summary>
        /// 初始化word程序
        /// </summary>
        /// <param name="fileName">文档路径</param>
        /// <param name="isReadOnly">是否只读模式打开</param>
        /// <param name="password">打开所需要的密码</param>
        public WordApp(string fileName, bool isReadOnly = false, string password = "")
        {
            var wordObj = OfficeApp.GetProcessesWordApp(out OfficeType officeType);
            if (wordObj == null)
                App = new Application();
            else
            {
                App = (Application)wordObj;
                AppType = officeType;
            }

            //Doc = App.Documents.Open(fileName, PasswordDocument: "1");
            Doc = App.Documents.OpenNoRepairDialog(fileName, ConfirmConversions: false, ReadOnly: isReadOnly, PasswordDocument: password);
        }

        /// <summary>
        /// 初始化程序，需要有活动中的word
        /// </summary>
        public WordApp(Application app)
        {
            App = app;

            try
            {
                Doc = app.ActiveDocument;
            }
            catch { }
        }

        /// <summary>
        /// 初始化word程序
        /// </summary>
        public WordApp(Document doc)
        {
            if (doc != null)
            {
                App = doc.Application;
                Doc = doc;
            }
        }

        /// <summary>
        /// 全新的文档
        /// </summary>
        /// <param name="paperSize">纸张大小</param>
        /// <param name="orientation">纸张方向</param>
        public void NewDoc(WdPaperSize paperSize = WdPaperSize.wdPaperA4, WdOrientation orientation = WdOrientation.wdOrientPortrait)
        {
            Close();
            Doc = App.Documents.Add();
            if (paperSize != WdPaperSize.wdPaperA4 || orientation != WdOrientation.wdOrientPortrait)
            {
                Doc.PageSetup.PaperSize = paperSize;
                Doc.PageSetup.Orientation = orientation;
            }
        }

        /// <summary>
        /// 得到文档的数量
        /// </summary>
        public int GetDocCount()
        {
            if (App == null)
                return 0;
            return App.Documents.Count;
        }

        /// <summary>
        /// 替换
        /// </summary>
        /// <param name="findText">查找内容</param>
        /// <param name="newValue">替换内容</param>
        public bool Replace(string findText, string newValue)
        {
            return RangeEx.Replace(Doc.Content, findText, newValue);
        }

        public Range InsertHtmlFile(string htmlFile)
        {
            //插入富文本控件
            ContentControl contentControl = Doc.ContentControls.Add(WdContentControlType.wdContentControlRichText);
            return null;
        }

        ///// <summary>
        /////保存为图片
        ///// </summary>
        //public void SaveImg()
        //{
        //    for (int i = 1; i <= Doc.ActiveWindow.Panes[1].Pages.Count; i++)
        //    {
        //        var bits = (byte[])Doc.ActiveWindow.Panes[1].Pages[i].EnhMetaFileBits;
        //        System.IO.MemoryStream ms = new System.IO.MemoryStream(bits);
        //        var ret = System.Drawing.Image.FromStream(ms);
        //        ret.Save(string.Format(@"G:\{0}_{1}.jpg", "我的文档", i));
        //    }
        //}

        /// <summary>
        /// 在文档前面加文本（使文档发生变化，为了解决保存自定义属性的问题）
        /// </summary>
        public void AddNullText()
        {
            Doc.Range(0, 0).Text = "1";
            Doc.Range(0, 1).Text = "";
        }

        public byte[] ReadAllBytes()
        {
            //文件上传的解决办法代码
            var ipersistfile = (System.Runtime.InteropServices.ComTypes.IPersistFile)Doc;
            string tempfile = Path.Combine("C:/" + new Random().Next(111111, 999999) + ".docx");
            ipersistfile.Save(tempfile, true);
            byte[] vs = File.ReadAllBytes(tempfile);
            File.Delete(tempfile);
            return vs;
            //using (var stream = File.Open(tempfile, FileMode.Open, FileAccess.Read, FileShare.Read))
            //{
            //    byte[] by = new byte[stream.Length];
            //    stream.Read(by, 0, Convert.ToInt32(stream.Length));
            //    string name = stream.Name;
            //    //do something with the stream
            //}
        }

        /// <summary>
        /// 保存或者另存为
        /// </summary>
        /// <param name="fileName">另存为的绝对路径+文件名，为null为保存文档</param>
        public void Save(string fileName = null)
        {
            if (string.IsNullOrEmpty(fileName))
                Doc.Save();
            else
                Doc.SaveAs2(fileName, WdSaveFormat.wdFormatXMLDocument, AddToRecentFiles: false);
        }

        /// <summary>
        /// 保存或者另存为当前文档（到默认路径或桌面）(针对于wps的优化)
        /// </summary>
        public void Save2(string path = null)
        {
            AddNullText();//word模拟修改状态，以用于保存文档和保存自定义属性
            if (path != null)
                Doc.SaveAs(path);
            else
            {
                if (IsExistFilePath)
                    Doc.Save();
                else
                {
                    string dir = string.Format(@"{0}\{1}_{2}.docx",
                        Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
                        Doc.FullName,
                        DateTime.Now.ToString("yyyyMMddHHmmss"));
                    Doc.SaveAs(dir);
                }
            }
        }

        /// <summary>
        /// 设置自定义属性(不存在将添加)
        /// </summary>
        /// <param name="name">名字</param>
        /// <param name="val">值</param>
        public void SetProperty(string name, string val = "")
        {
            DocumentProperties properties = (DocumentProperties)Doc.CustomDocumentProperties;
            try//存在
            {
                DocumentProperty property = properties[name];
                properties[name].Value = val;//存在就更新
            }
            catch//不存在
            {
                properties.Add(name, false, MsoDocProperties.msoPropertyTypeString, val);
            }
        }

        /// <summary>
        /// 获取文档自定义属性
        /// </summary>
        public string GetPropertyVal(string name)
        {
            DocumentProperties properties = (DocumentProperties)Doc.CustomDocumentProperties;
            try//存在
            {
                DocumentProperty property = properties[name];
                return (string)properties[name].Value;
            }
            catch//不存在
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 获取文档属性
        /// </summary>
        public dynamic GetDocProperty(string key)
        {
            DocumentProperties attrs = (DocumentProperties)Doc.BuiltInDocumentProperties;
            try
            {
                DocumentProperty attr = attrs[key];
                return attr.Value == null ? string.Empty : attr.Value;
            }
            catch
            {
                return string.Empty;
            }
        }

        /// <summary>
        /// 关闭当前文档
        /// </summary>
        public void Close()
        {
            if (Doc != null)
                Doc.Close(WdSaveOptions.wdDoNotSaveChanges);

            Doc = null;
        }

    }
}
