using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using uBIMEarthTools.Model;
using uBIMEarthTools.Utils;

namespace uBIMEarthTools.Core
{
    class GeologyCompute
    {
        /// <summary>
        /// 三个钻孔的五种相等情况
        /// </summary>
        /// <param name="boreholeList"></param>
        /// <param name="geologyBlockList"></param>
        public static void CreateGeologyBlock(List<Borehole> boreholeList, List<GeologyBlock> geologyBlockList, bool topToBottom)
        {
            switch (Common.IsTypeEquals(boreholeList))
            {
                case (int)TypeEquals.AllEqual:
                    {
                        AllEqual(boreholeList[0], boreholeList[1], boreholeList[2], geologyBlockList, topToBottom);
                        break;
                    }
                case (int)TypeEquals.OneTwo:
                    {
                        PartEqual(boreholeList[0], boreholeList[1], boreholeList[2], geologyBlockList, topToBottom);
                        break;
                    }
                case (int)TypeEquals.OneThree:
                    {
                        PartEqual(boreholeList[0], boreholeList[2], boreholeList[1], geologyBlockList, topToBottom);
                        break;
                    }
                case (int)TypeEquals.TwoThree:
                case (int)TypeEquals.UnEqual:
                    {
                        UnEqual(boreholeList[0], boreholeList[1], boreholeList[2], geologyBlockList, topToBottom);
                        break;
                    }
            }
        }

        /// <summary>
        /// 三个钻孔的地质均相等
        /// </summary>
        /// <image url="$(SolutionDir)/Comments/均等.png" />
        /// <remarks>
        /// 钻孔一为F面左边,钻孔二为F面右边,E面左右距离为1
        /// 地质块材质为三个钻孔当前地层材质
        /// </remarks>
        /// <param name="b1"></param>
        /// <param name="b2"></param>
        /// <param name="b3"></param>
        /// <param name="geologyBlockList"></param>
        private static void AllEqual(Borehole b1, Borehole b2, Borehole b3, List<GeologyBlock> geologyBlockList, bool topToBottom)
        {
            if (topToBottom)
            {
                GeologyBlock geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.StartIndex).Point,
                    FLeftBottom = b1.ValueList.ElementAt(b1.StartIndex + 1).Point,
                    FRightUp = b2.ValueList.ElementAt(b2.StartIndex).Point,
                    FRightBottom = b2.ValueList.ElementAt(b2.StartIndex + 1).Point,
                    ELeftUp = b3.ValueList.ElementAt(b3.StartIndex).Point,
                    ELeftBottom = b3.ValueList.ElementAt(b3.StartIndex + 1).Point,
                    Type = b1.CurrentType
                };

                XYZ translate = geologyBlock.FRightUp - geologyBlock.FLeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.ERightUp = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ELeftBottom + translate;
                geologyBlockList.Add(geologyBlock);

                b1.StartIndex++;
                b2.StartIndex++;
                b3.StartIndex++;
            }
            else
            {
                GeologyBlock geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.EndIndex - 1).Point,
                    FLeftBottom = b1.ValueList.ElementAt(b1.EndIndex).Point,
                    FRightUp = b2.ValueList.ElementAt(b2.EndIndex - 1).Point,
                    FRightBottom = b2.ValueList.ElementAt(b2.EndIndex).Point,
                    ELeftUp = b3.ValueList.ElementAt(b3.EndIndex - 1).Point,
                    ELeftBottom = b3.ValueList.ElementAt(b3.EndIndex).Point,
                    Type = b1.CurrentType
                };

                XYZ translate = geologyBlock.FRightUp - geologyBlock.FLeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.ERightUp = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ELeftBottom + translate;
                geologyBlockList.Add(geologyBlock);

                b1.EndIndex--;
                b2.EndIndex--;
                b3.EndIndex--;
            }
        }

        /// <summary>
        /// 三个钻孔中的两个的地质相等,把这两个放在前两位
        /// </summary>
        /// <image url="$(SolutionDir)/Comments/部分相等.png" />
        /// <remarks>
        /// 钻孔一为F面左边,钻孔二为F面右边,E面左右、上下距离为1
        /// 地质块1材质为前两个钻孔当前地层材质,地质块2、3材质为下个地层材质
        /// </remarks>        
        /// <param name="b1"></param>
        /// <param name="b2"></param>
        /// <param name="b3"></param>
        /// <param name="geologyBlockList"></param>
        private static void PartEqual(Borehole b1, Borehole b2, Borehole b3, List<GeologyBlock> geologyBlockList, bool topToBottom)
        {
            if (topToBottom)
            {
                GeologyBlock geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.StartIndex).Point,
                    FLeftBottom = b1.ValueList.ElementAt(b1.StartIndex + 1).Point,
                    FRightUp = b2.ValueList.ElementAt(b2.StartIndex).Point,
                    FRightBottom = b2.ValueList.ElementAt(b2.StartIndex + 1).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    ERightUp = (b2.ValueList.ElementAt(b2.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    Type = b1.CurrentType
                };

                XYZ translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);

                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.StartIndex + 1).Point,
                    FRightUp = b2.ValueList.ElementAt(b2.StartIndex + 1).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    ELeftBottom = (b1.ValueList.ElementAt(b1.StartIndex + 1).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    ERightUp = (b2.ValueList.ElementAt(b2.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    ERightBottom = (b2.ValueList.ElementAt(b2.StartIndex + 1).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    Type = GetType(b1, b2, topToBottom, 1)
                };
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.FLeftBottom = geologyBlock.FLeftUp + translate;
                geologyBlock.FRightBottom = geologyBlock.FRightUp + translate;
                geologyBlockList.Add(geologyBlock);

                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    FLeftBottom = (b1.ValueList.ElementAt(b1.StartIndex + 1).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    FRightUp = (b2.ValueList.ElementAt(b2.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    FRightBottom = (b2.ValueList.ElementAt(b2.StartIndex + 1).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    ELeftUp = b3.ValueList.ElementAt(b3.StartIndex).Point,
                    Type = GetType(b3, topToBottom)
                };
                translate = geologyBlock.FRightUp - geologyBlock.FLeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.ERightUp = geologyBlock.ELeftUp + translate;
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);

                b1.StartIndex++;
                b2.StartIndex++;
            }
            else
            {
                GeologyBlock geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.EndIndex - 1).Point,
                    FLeftBottom = b1.ValueList.ElementAt(b1.EndIndex).Point,
                    FRightUp = b2.ValueList.ElementAt(b2.EndIndex - 1).Point,
                    FRightBottom = b2.ValueList.ElementAt(b2.EndIndex).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    ERightUp = (b2.ValueList.ElementAt(b2.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    Type = b1.CurrentType
                };

                XYZ translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);

                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.EndIndex).Point,
                    FRightUp = b2.ValueList.ElementAt(b2.EndIndex).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    ELeftBottom = (b1.ValueList.ElementAt(b1.EndIndex).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    ERightUp = (b2.ValueList.ElementAt(b2.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    ERightBottom = (b2.ValueList.ElementAt(b2.EndIndex).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    //Type = string.Empty
                    Type = GetType(b1, b2, topToBottom)
                    //Type = b1.CurrentType
                };
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.FLeftBottom = geologyBlock.FLeftUp + translate;
                geologyBlock.FRightBottom = geologyBlock.FRightUp + translate;
                geologyBlockList.Add(geologyBlock);

                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    FLeftBottom = (b1.ValueList.ElementAt(b1.EndIndex).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    FRightUp = (b2.ValueList.ElementAt(b2.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    FRightBottom = (b2.ValueList.ElementAt(b2.EndIndex).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    ELeftUp = b3.ValueList.ElementAt(b3.EndIndex).Point,
                    Type = GetType(b3, topToBottom)
                };
                translate = geologyBlock.FRightUp - geologyBlock.FLeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.ERightUp = geologyBlock.ELeftUp + translate;
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);

                b1.EndIndex--;
                b2.EndIndex--;
            }

        }

        /// <summary>
        /// 三个钻孔的地质均不等时
        /// </summary>
        /// <image url="$(SolutionDir)/Comments/均不等.png" />
        /// <remarks>
        /// 钻孔一为F面,F面左右距离为1,钻孔二为E面左边,钻孔三为E面右边,E面上下距离为1
        /// 地质块1材质为钻孔一当前地层材质,地质块2、3材质为下个地层材质
        /// </remarks> 
        /// <param name="b1"></param>
        /// <param name="b2"></param>
        /// <param name="b3"></param>
        /// <param name="geologyBlockList"></param>
        private static void UnEqual(Borehole b1, Borehole b2, Borehole b3, List<GeologyBlock> geologyBlockList, bool topToBottom)
        {
            if (topToBottom)
            {
                GeologyBlock geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.StartIndex).Point,
                    FLeftBottom = b1.ValueList.ElementAt(b1.StartIndex + 1).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b2.ValueList.ElementAt(b2.StartIndex).Point) / 2,
                    ERightUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    Type = b1.CurrentType
                };
                XYZ translate = geologyBlock.ERightUp - geologyBlock.ELeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.FRightUp = geologyBlock.FLeftUp + translate;
                geologyBlock.FRightBottom = geologyBlock.FLeftBottom + translate;
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);


                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.StartIndex + 1).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b2.ValueList.ElementAt(b2.StartIndex).Point) / 2,
                    ELeftBottom = (b1.ValueList.ElementAt(b1.StartIndex + 1).Point + b2.ValueList.ElementAt(b2.StartIndex).Point) / 2,
                    ERightUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    ERightBottom = (b1.ValueList.ElementAt(b1.StartIndex + 1).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    Type = GetType(b1, topToBottom, 1)
                };
                translate = geologyBlock.ERightUp - geologyBlock.ELeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.FRightUp = geologyBlock.FLeftUp + translate;
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.FLeftBottom = geologyBlock.FLeftUp + translate;
                geologyBlock.FRightBottom = geologyBlock.FRightUp + translate;
                geologyBlockList.Add(geologyBlock);

                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b2.ValueList.ElementAt(b2.StartIndex).Point) / 2,
                    FLeftBottom = (b1.ValueList.ElementAt(b1.StartIndex + 1).Point + b2.ValueList.ElementAt(b2.StartIndex).Point) / 2,
                    FRightUp = (b1.ValueList.ElementAt(b1.StartIndex).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    FRightBottom = (b1.ValueList.ElementAt(b1.StartIndex + 1).Point + b3.ValueList.ElementAt(b3.StartIndex).Point) / 2,
                    ELeftUp = b2.ValueList.ElementAt(b2.StartIndex).Point,
                    ERightUp = b3.ValueList.ElementAt(b3.StartIndex).Point,
                    //Type = string.Empty
                    Type = GetType(b2, b3, topToBottom)
                    //Type = b1.CurrentType
                };
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);

                b1.StartIndex++;
            }
            else
            {
                GeologyBlock geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.EndIndex - 1).Point,
                    FLeftBottom = b1.ValueList.ElementAt(b1.EndIndex).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b2.ValueList.ElementAt(b2.EndIndex).Point) / 2,
                    ERightUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    Type = b1.CurrentType
                };
                XYZ translate = geologyBlock.ERightUp - geologyBlock.ELeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.FRightUp = geologyBlock.FLeftUp + translate;
                geologyBlock.FRightBottom = geologyBlock.FLeftBottom + translate;
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);

                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = b1.ValueList.ElementAt(b1.EndIndex).Point,
                    ELeftUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b2.ValueList.ElementAt(b2.EndIndex).Point) / 2,
                    ELeftBottom = (b1.ValueList.ElementAt(b1.EndIndex).Point + b2.ValueList.ElementAt(b2.EndIndex).Point) / 2,
                    ERightUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    ERightBottom = (b1.ValueList.ElementAt(b1.EndIndex).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    Type = GetType(b1, topToBottom)
                };
                translate = geologyBlock.ERightUp - geologyBlock.ELeftUp;
                translate = new XYZ(translate.X, translate.Y, 0).Normalize() / 304.8;
                geologyBlock.FRightUp = geologyBlock.FLeftUp + translate;
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.FLeftBottom = geologyBlock.FLeftUp + translate;
                geologyBlock.FRightBottom = geologyBlock.FRightUp + translate;
                geologyBlockList.Add(geologyBlock);

                geologyBlock = new GeologyBlock(b1, b2, b3)
                {
                    FLeftUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b2.ValueList.ElementAt(b2.EndIndex).Point) / 2,
                    FLeftBottom = (b1.ValueList.ElementAt(b1.EndIndex).Point + b2.ValueList.ElementAt(b2.EndIndex).Point) / 2,
                    FRightUp = (b1.ValueList.ElementAt(b1.EndIndex - 1).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    FRightBottom = (b1.ValueList.ElementAt(b1.EndIndex).Point + b3.ValueList.ElementAt(b3.EndIndex).Point) / 2,
                    ELeftUp = b2.ValueList.ElementAt(b2.EndIndex).Point,
                    ERightUp = b3.ValueList.ElementAt(b3.EndIndex).Point,
                    Type = GetType(b2, b3, topToBottom)
                };
                translate = new XYZ(0, 0, -1) / 304.8;
                geologyBlock.ELeftBottom = geologyBlock.ELeftUp + translate;
                geologyBlock.ERightBottom = geologyBlock.ERightUp + translate;
                geologyBlockList.Add(geologyBlock);

                b1.EndIndex--;
            }
        }

        private static string GetType(Borehole a, Borehole b, bool topToBottom, int offset = 0)
        {
            Dictionary<string, double> heightDic = new Dictionary<string, double>();

            GetTypeHeight(heightDic, a, topToBottom, offset);
            GetTypeHeight(heightDic, b, topToBottom, offset);

            return heightDic.OrderByDescending(x => x.Value).First().Key;

        }

        private static string GetType(Borehole a, bool topToBottom, int offset = 0)
        {
            Dictionary<string, double> heightDic = new Dictionary<string, double>();

            GetTypeHeight(heightDic, a, topToBottom, offset);

            return heightDic.OrderByDescending(x => x.Value).First().Key;

        }

        private static void GetTypeHeight(Dictionary<string, double> heightDic, Borehole a, bool topToBottom, int offset = 0)
        {
            GetTypeHeight(heightDic, a, topToBottom ? a.StartIndex + offset : a.EndIndex + offset);
        }

        private static void GetTypeHeight(Dictionary<string, double> heightDic, Borehole a, int index)
        {
            //上
            if (index != 0)
            {
                if (heightDic.ContainsKey(a.ValueList[index].Type))
                {
                    heightDic[a.ValueList[index].Type] += a.ValueList[index - 1].Point.Z -
                                                                 a.ValueList[index].Point.Z;
                }
                else
                {
                    heightDic[a.ValueList[index].Type] = a.ValueList[index - 1].Point.Z -
                                                                a.ValueList[index].Point.Z;
                }
            }
            //下
            if (index <= a.ValueList.Count - 2)
            {
                if (heightDic.ContainsKey(a.ValueList[index + 1].Type))
                {
                    heightDic[a.ValueList[index + 1].Type] += a.ValueList[index].Point.Z -
                                                                     a.ValueList[index + 1].Point.Z;
                }
                else
                {
                    heightDic[a.ValueList[index + 1].Type] = a.ValueList[index].Point.Z -
                                                                    a.ValueList[index + 1].Point.Z;
                }
            }
        }
    }


}

