using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using uBIMEarthTools.Model;
using uBIMEarthTools.Utils;

namespace uBIMEarthTools.Commands
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    public class DwgDataExportCommand : IExternalCommand
    {
        public Result Execute(ExternalCommandData CommandData, ref string Message, ElementSet elementset)
        {
            #region 变量
            Autodesk.Revit.ApplicationServices.Application Revit = CommandData.Application.Application;
            UIDocument uidoc = CommandData.Application.ActiveUIDocument;
            Document doc = CommandData.Application.ActiveUIDocument.Document;
            //            ICollection<ElementId> currentselectid = uidoc.Selection.GetElementIds();
            Autodesk.Revit.DB.View curview = doc.ActiveView;
            List<TextNote> textnoteList = new FilteredElementCollector(doc, curview.Id).
                WherePasses(new ElementClassFilter(typeof(TextNote))).
                ToElements().Select(x => x as TextNote).ToList();//所有文字
            XYZ pointFirstTable_L = new XYZ();
            XYZ pointFirstTable_R = new XYZ();
            XYZ pointSecTable = new XYZ();
            XYZ pointLayer_L = new XYZ();//地层编号左侧x坐标
            XYZ pointLayer_R = new XYZ();//地层编号右侧x坐标
            XYZ pointButtom_L = new XYZ();//层底高程左侧x坐标
            XYZ pointButtom_R = new XYZ();//层底高程右侧x坐标
            XYZ pointStart = new XYZ();//此坐标以下为地层数据
            XYZ pointNum = new XYZ();//钻孔编号
            XYZ pointLevel = new XYZ();//孔口标高
            XYZ pointX = new XYZ();//孔口X
            XYZ pointY = new XYZ();//孔口Y
            List<Borehole> boreholes = new List<Borehole>();
            #endregion

            #region 用户选取点
            try
            {
                pointFirstTable_L = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击第一个图框左上角……");
                pointFirstTable_R = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击第一个图框右下角……");
                pointSecTable = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击第二个图框左上角……");
                pointLayer_L = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击地层编号列左侧……");
                pointLayer_R = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击地层编号列右侧……");
                pointButtom_L = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击层底高程列左侧……");
                pointButtom_R = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击层底高程列右侧……");
                pointStart = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击地层数据上方横线……");
                pointNum = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击钻孔编号数字左下角……");
                pointLevel = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击孔口标高数字左下角……");
                pointX = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击孔口X数字左下角……");
                pointY = uidoc.Selection.PickPoint(ObjectSnapTypes.Endpoints, "点击地孔口Y数字左下角……");
            }
            catch
            {
                return Result.Succeeded;
            }
            #endregion

            #region 保存路径
            string localFilePath = string.Empty;
            SaveFileDialog saveFileDialog = new SaveFileDialog();
            saveFileDialog.Filter = "Excel files|*.xlsx";
            saveFileDialog.FileName = doc.Title.Replace(".rvt", "") + "-" + DateTime.Now.ToString("yyyyMMdd");
            saveFileDialog.FilterIndex = 1;
            saveFileDialog.RestoreDirectory = true;
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                localFilePath = saveFileDialog.FileName.ToString();
            }
            else
                return Result.Cancelled;
            #endregion

            #region 获取数据
            TransactionStatus status = TransactionStatus.Uninitialized;
            TransactionGroup transGroup = new TransactionGroup(doc, "地质建模");
            if (transGroup.Start() == TransactionStatus.Started)
            {
                Transaction transaction = new Transaction(doc, "uBIM");

                int k = 0;
                while (true)
                {
                    #region 临时变量
                    XYZ origin_k = pointFirstTable_L + new XYZ(k * (pointSecTable.X - pointFirstTable_L.X), 0, 0);//当前图框左上角坐标
                    List<TextNote> textnoteKList = new List<TextNote>();  //当前图框里的textnote                
                    List<TextNote> dcbhList = new List<TextNote>();   //地层编号
                    List<TextNote> dcgcList = new List<TextNote>();   //地层高程
                    List<TextNote> delTextnoteList = new List<TextNote>();  //被归并的textnote，后面被排除 
                    #endregion

                    #region 获取当前图框里的textnote 
                    foreach (TextNote tntmp in textnoteList)
                    {
                        if (tntmp.Coord.X > origin_k.X && tntmp.Coord.X < origin_k.X + (pointFirstTable_R.X - pointFirstTable_L.X) &&
                            tntmp.Coord.Y > origin_k.Y - (pointFirstTable_L.Y - pointFirstTable_R.Y) && tntmp.Coord.Y < origin_k.Y)
                        {
                            //消重
                            //当前条件:距离相差1cm且文字相等
                            bool dub = false;
                            for (int i = 0; i <= textnoteKList.Count - 1; i++)
                            {
                                TextNote tntmp1 = textnoteKList[i];
                                if (tntmp.Coord.DistanceTo(tntmp1.Coord) < 1 / 304.8 && tntmp.Text == tntmp1.Text)
                                {
                                    dub = true;
                                    break;
                                }
                            }
                            if (dub == false)
                                textnoteKList.Add(tntmp);
                        }
                    }
                    if (textnoteKList.Count == 0)  //获取不到时,跳出
                        break;
                    #endregion

                    #region 获取当前图框编号,标高,X,Y
                    TextNote zkbhTn = Common.Textnote_At_Point(new XYZ(origin_k.X + pointNum.X - pointFirstTable_L.X, pointNum.Y, pointNum.Z), textnoteKList, 4);  //钻孔编号
                    TextNote kkbgTn = Common.Textnote_At_Point(new XYZ(origin_k.X + pointLevel.X - pointFirstTable_L.X, pointLevel.Y, pointLevel.Z), textnoteKList, 4);  //孔口标高
                    TextNote xTn = Common.Textnote_At_Point(new XYZ(origin_k.X + pointX.X - pointFirstTable_L.X, pointX.Y, pointX.Z), textnoteKList, 4);  //孔口X
                    TextNote yTn = Common.Textnote_At_Point(new XYZ(origin_k.X + pointY.X - pointFirstTable_L.X, pointY.Y, pointY.Z), textnoteKList, 4);  //孔口Y

                    //钻孔编号跟孔口标高不对应时,跳至下个图框
                    if (zkbhTn == null || kkbgTn == null)
                    {
                        k++;
                        continue;
                    }
                    #endregion

                    textnoteKList = textnoteKList.Where(x => !(x.Text.Contains("<") || x.Text.Contains(">"))).ToList();
                    #region 归并地层编号中类似3-1的文字(当前条件:X公差:4mm;Y公差:2mm;字高公差:null)
                    foreach (TextNote tntmp1 in textnoteKList)
                    {
                        if (tntmp1.Coord.X > origin_k.X + pointLayer_R.X - pointFirstTable_L.X)//排除超出范围的
                            continue;
                        if (delTextnoteList.Contains(tntmp1))//排除已剔除的
                            continue;
                        if (tntmp1.Text.Contains("."))//排除包含"."的
                            continue;
                        foreach (TextNote tntmp2 in textnoteKList)
                        {
                            if (delTextnoteList.Contains(tntmp2))//排除已剔除的
                                continue;
                            if (tntmp2.Coord.X > origin_k.X + pointLayer_R.X - pointFirstTable_L.X)//排除超出范围的
                                continue;
                            if (tntmp2.Text.Contains("."))//排除包含"."的
                                continue;
                            if (tntmp1.Id == tntmp2.Id)//排除与当前比较的同一TextNote
                                continue;

                            //三重过滤：X相近、Y相近、字高不一
                            if (Math.Abs(tntmp1.Coord.X - tntmp2.Coord.X) < 4 / 304.8 &&
                                Math.Abs(tntmp1.Coord.Y - tntmp2.Coord.Y) < 2 / 304.8)// &&Math.Abs(tntmp1.Height - tntmp2.Height) > 0.00001 / 304.8)
                            {
                                transaction.Start();
                                if (tntmp1.Coord.X < tntmp2.Coord.X)
                                {
                                    tntmp1.Text = tntmp1.Text + "-" + tntmp2.Text;
                                    delTextnoteList.Add(tntmp2);
                                }
                                else
                                {
                                    tntmp2.Text = tntmp2.Text + "-" + tntmp1.Text;
                                    delTextnoteList.Add(tntmp1);
                                }
                                transaction.Commit();
                            }
                        }
                    }
                    textnoteKList = textnoteKList.Except(delTextnoteList).ToList();
                    #endregion

                    #region 获取当前图框内所有地层编号与地层高程,并按从高到低排序
                    foreach (var tntmp in textnoteKList)
                    {
                        if (tntmp.Coord.Y > pointStart.Y)
                            continue;
                        else if (tntmp.Coord.X > origin_k.X + pointLayer_L.X - pointFirstTable_L.X && tntmp.Coord.X < origin_k.X + pointLayer_R.X - pointFirstTable_L.X)
                        {
                            dcbhList.Add(tntmp);
                        }
                        else if (tntmp.Coord.X > origin_k.X + pointButtom_L.X - pointFirstTable_L.X && tntmp.Coord.X < origin_k.X + pointButtom_R.X - pointFirstTable_L.X)
                        {
                            dcgcList.Add(tntmp);
                        }
                    }
                    dcbhList = dcbhList.OrderByDescending(x => x.Coord.Y).ToList();
                    dcgcList = dcgcList.OrderByDescending(x => x.Coord.Y).ToList();
                    #endregion

                    #region 寻找已有钻孔列表中有没有相同编号,没有时新建钻孔
                    Borehole bh;
                    if (boreholes.Count != 0 && boreholes.Select(x => x.Name).ToList().Contains(zkbhTn.Text))
                    {
                        bh = boreholes.ElementAt(boreholes.Select(x => x.Name).ToList().IndexOf(zkbhTn.Text));
                    }
                    else
                    {
                        bh = new Borehole { Name = zkbhTn.Text };
                        bh.ValueList.Add(new GeologyLayer(dcbhList.First().Text, new XYZ(Convert.ToDouble(xTn.Text), Convert.ToDouble(yTn.Text), Convert.ToDouble(kkbgTn.Text))));
                        boreholes.Add(bh);
                    }
                    #endregion

                    #region 导出对应的钻孔地层数据
                    for (int i = 0; i < (dcbhList.Count < dcgcList.Count ? dcbhList.Count : dcgcList.Count); i++)
                    {
                        string dcbh_i = dcbhList[i].Text.Replace("\r", "").Replace("\n", "");
                        string dcmc_i = dcgcList[i].Text.Replace("\r", "").Replace("\n", "");
                        double x = Convert.ToDouble(xTn.Text);
                        double y = Convert.ToDouble(yTn.Text);
                        double z = Convert.ToDouble(dcmc_i);
                        GeologyLayer geologyLayer = new GeologyLayer(dcbh_i, new XYZ(x, y, z));
                        bh.ValueList.Add(geologyLayer);
                    }
                    #endregion

                    k++;
                }
            }
            status = transGroup.RollBack();
            #endregion

            #region 导出数据
            if (boreholes.Count == 0)
            {
                MessageBox.Show("当前界面无法读取到钻孔数据", "uBIM");
                return Result.Succeeded;
            }

            ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
            FileInfo fileInfo = new FileInfo(localFilePath);
            using (ExcelPackage excelPackage = new ExcelPackage(fileInfo))
            {
                //using (FileStream fs = new FileStream(localFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
                //{
                //excelPackage.Load(fs);
                ExcelWorksheet layerWorksheet = excelPackage.Workbook.Worksheets.Add("Layers");
                var layers = boreholes.SelectMany(x => x.ValueList).Select(x => x.Type).Select(x => x.Trim()).Distinct().ToList();
                for (int i = 0; i < layers.Count; i++)
                {
                    layerWorksheet.Cells[i + 1, 1].Value = layers[i];
                    layerWorksheet.Cells[i + 1, 2].Value = layers[i];
                }

                ExcelWorksheet excelWorksheet = excelPackage.Workbook.Worksheets.Add("Data");
                //if (excelWorksheet == null)
                //{
                //    excelWorksheet = excelPackage.Workbook.Worksheets.Add("Data");
                //}
                excelWorksheet.Cells.Clear();

                excelWorksheet.Cells.Style.Numberformat.Format = "@";
                for (int i = 0; i < boreholes.Count; i++)
                {
                    Borehole borehole = boreholes[i];
                    if (borehole.ValueList.Count != 0)
                    {
                        excelWorksheet.Cells[2 * i + 1, 1].Value = borehole.Name;
                        excelWorksheet.Cells[2 * i + 1, 2].Value = borehole.ValueList[0].Point.X;
                        excelWorksheet.Cells[2 * i + 1, 3].Value = borehole.ValueList[0].Point.Y;
                        excelWorksheet.Cells[2 * i + 2, 1].Value = borehole.Name;
                        excelWorksheet.Cells[2 * i + 2, 2].Value = borehole.ValueList[0].Point.X;
                        excelWorksheet.Cells[2 * i + 2, 3].Value = borehole.ValueList[0].Point.Y;
                        for (int j = 0; j < borehole.ValueList.Count; j++)
                        {
                            excelWorksheet.Cells[2 * i + 1, j + 4].Value = borehole.ValueList[j].Type;
                            excelWorksheet.Cells[2 * i + 2, j + 4].Value = borehole.ValueList[j].Point.Z;
                        }
                    }
                }

                excelPackage.Save();
                //}
                //File.WriteAllBytes(localFilePath, excelPackage.GetAsByteArray());
            }
            #endregion

            return Result.Succeeded;
        }
    }
}
