/* ==============================================================================
 * 功能描述：SagaCheck  
 * 创 建 者：Garrett
 * 创建日期：2019/6/11 16:09:09
 * ==============================================================================*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text.RegularExpressions;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using SAGA.DotNetUtils.Extend;
using ServiceRevitLib.Common;
using SAGA.RevitUtils.Extends;
using ServiceRevitLib.Extend;

namespace ServiceRevitLib.Mode
{
    /// <summary>
    /// SagaCheck
    /// </summary>
    class ElementRangeCheck : CheckBase
    {
        #region 序列化属性
        private double m_Redundant = 500;
        /// <summary>
        /// 高度冗余
        /// </summary>
        public double Redundant
        {
            get { return m_Redundant; }
            set { m_Redundant = value; }
        }


        private double m_baseLevel;
        /// <summary>
        /// 底部标高
        /// </summary>
        public double BaseLevel
        {
            get { return m_baseLevel; }
        }

        private List<double> m_topLevels = new List<double>();

        /// <summary>
        /// 顶部标高（夹层可能涉及多个顶）
        /// </summary>
        public string TopLevels
        {
            get { return string.Join(";", m_topLevels); }
        }

        #endregion
        public override void Check()
        {
            try
            {
                base.Check();

                #region

                var document = m_Doc;
                if (!SetFloorBaseTopRange()) return;
                var elements = document.GetAllElements();
                foreach (var element in elements)
                {
                    var result = GetCheckResult(element);
                    if (result != null)
                        Content.Add(result);
                }


                #endregion
            }
            catch (Exception e)
            {
                Result = ResultState.Failure;
                ResultMsg = $"{e.Message}\r\n{e.StackTrace}";
            }
            
        }

        /// <summary>
        /// 设置当前楼层底部和顶部范围
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="result"></param>
        private bool SetFloorBaseTopRange()
        {
            bool rt = true;
            var document = m_Doc;
            try
            {
                var sagaPlans = document.GetElements<ViewPlan>()
                    .Where(t => t.ViewType == ViewType.FloorPlan && t.Name.Contains("-saga")).ToList();
                var curFloor = sagaPlans.FirstOrDefault();
                if (sagaPlans.Count != 1 || curFloor == null)
                {
                    Result = ResultState.Failure;
                    ResultMsg = "Saga标记不合法，请修正后再进行检查";

                    return false;
                }

                //设置楼层底部高度
                m_baseLevel = curFloor.GenLevel.Elevation.FromApi().Round(2);

                //设置楼层顶部高度
                var levels = m_Doc.GetLevels();
                var mbiLevels = levels.Where(t => Regex.IsMatch(t.Name, $"{RegexConstPattern.IsMBILevel}") && t.Elevation.IsThan(m_baseLevel)).ToList();
                foreach (Level level in mbiLevels)
                {
                    m_topLevels.Add(level.Elevation.FromApi().Round(2));
                    if (!Regex.IsMatch(level.Name, $"{RegexConstPattern.IsSandwich}"))
                    {
                        break;
                    }
                }
                //当前层为屋顶或屋顶夹层时，顶部限制设置为正无穷
                if (Regex.IsMatch(curFloor.GenLevel.Name, $"{RegexConstPattern.IsRF}|{RegexConstPattern.IsRFM}"))
                {
                    m_topLevels.Add(double.MaxValue);
                }


            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                rt = false;
            }
            return rt;
        }

        /// <summary>
        /// 获取检测结果
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        private ElementRangeCheckResult GetCheckResult(Element element)
        {
            var result = new ElementRangeCheckResult();
            result.Id = element.Id.ToString();
            result.FamilyName = element.GetFamilyName();
            try
            {
                double zb = 0, zt = 0;
                bool rb = false, rt = false;
                //需要识别判定的构件
                DCElementType type = DCElementType.None;
                bool isBoxInst = false;
                if (element is Wall wall)
                {
                    isBoxInst = true;
                    zb = wall.GetBaseStaticHeight();
                    zt = wall.GetTopStaticHeight();
                    type = DCElementType.Wall;
                }
                else if (element.IsSpace())
                {
                    var space = element as Space;
                    isBoxInst = true;
                    zb = space.GetBaseStaticHeight();
                    zt = space.GetTopStaticHeight();
                    type = DCElementType.Space;
                }
                else if (element is FamilyInstance)
                {
                    if (element.IsAllColumn())
                    {
                        var fi = element as FamilyInstance;
                        isBoxInst = true;
                        zb = fi.GetBaseStaticHeight();
                        zt = fi.GetTopStaticHeight();
                        type = DCElementType.Column;
                    }
                    else if (element.IsEquipment() || element.IsEquipmentPart() || element.IsBeacon())
                    {
                        zb = element.GetLocationPointMBIXYZ().Z;
                        type = GetRType(element);
                    }
                }

                if (type==DCElementType.None) return null;
                
                //冗余，使用时，统一使用单位mm
                double w = Redundant;
                zb = zb.FromApi().Round(2);
                zt = zt.FromApi().Round(2);
                //构件类型
                result.Type = type.GetDescription();
                if (isBoxInst)
                {
                    rb = zb.IsBetween(m_baseLevel - w, m_baseLevel);
                    rt = m_topLevels.Any(t => zt.IsBetween(t - w, t));
                    string ttip = rb ? "" : "底部";
                    string ttop = rt ? "" : rb ? "和顶部" : "顶部";
                    result.HeightRange = $"{zb},{zt}";
                    result.Result = (rb && rt)?ResultState.Success:ResultState.Failure;
                    result.ResultMsg = rb && rt ? "" : $"构件范围不满足要求；请检查构件{ttip}{ttop}";
                }
                else
                {
                    rb = m_topLevels.Any(t => zb.IsBetween(m_baseLevel, t));
                    result.HeightRange = $"{zb}";
                    result.Result = (rb) ? ResultState.Success : ResultState.Failure;
                    result.ResultMsg = rb? "" : $"构件范围不满足要求；请检查构件位置";
                }
            }
            catch (Exception e)
            {
                result.Result = ResultState.Failure;
                result.ResultMsg = "构件范围检查异常";
            }


            return result;
        }

        /// <summary>
        /// 获取构件类型
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        private DCElementType GetRType(Element fi)
        {
            DCElementType name = DCElementType.None;
            if (fi.IsEquipment())
            {
                name = DCElementType.Equipment;
            }
            else if (fi.IsEquipmentPart())
            {
                name = DCElementType.EuipmentPart;
            }
            else if (fi.IsBeacon())
            {
                name = DCElementType.Beacon;
            }
            return name;
        }
        /// <summary>
        /// DCElementType
        /// </summary>
        public enum DCElementType
        {
            [Description("未知")]
            None,
            [Description("墙")]
            Wall,
            [Description("柱")]
            Column,
            [Description("空间")]
            Space,
            [Description("设备")]
            Equipment,
            [Description("部件")]
            EuipmentPart,
            [Description("信标")]
            Beacon
        }
    }
}
