#region Namespaces
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using System;
using System.Collections.Generic;
using System.Diagnostics;

#endregion

namespace RevitAddinInstallHVAC
{
    [Transaction(TransactionMode.Manual)]
    public class Command : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {
            UIApplication uiapp = commandData.Application;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Application app = uiapp.Application;
            Document doc = uidoc.Document;

            //*******条件**********
            //空調機ファミリとタイプ名
            string ACFamilyName = "07062_ACP-CID_室内機_天井埋込両ダクト形";
            string ACTypeName = "9.0kW";

            try
            {
                // 横の空調機台数
                int xNumber = 0;
                // 縦の空調機台数
                int yNumber = 0;
                //設置高さ
                double height = 0;
                // Windowを表示してユーザーに横と縦の台数を入力してもらう
                Window1 window1 = new Window1();
                bool? result = window1.ShowDialog();
                // OKボタンが押されたかどうかを確認
                if (result == true)
                {
                    // okButtonが押されたら縦横の台数、高さを取得
                    xNumber = window1.GetXNumber();
                    yNumber = window1.GetYNumber();
                    height = window1.GetHeight();
                    height = UnitUtils.ConvertToInternalUnits(height, UnitTypeId.Millimeters);
                }
                else
                {
                    // キャンセルや閉じるボタンが押された場合の処理
                    return Result.Cancelled;
                }

                // 現在開いている平面ビューのレベルを取得する
                Level level = null;
                View activeView = uidoc.ActiveView;
                //平面ビューか？
                if (activeView is ViewPlan viewPlan)
                {
                    // 平面ビューのレベルを取得
                    level = doc.GetElement(viewPlan.GenLevel.Id) as Level;
                }
                else
                {
                    TaskDialog.Show("エラー", "現在のビューは平面ビューではありません。");
                    return Result.Failed;
                }
                // スペース用選択フィルターを設定
                SpaceSelectionFilter filter = new SpaceSelectionFilter(doc);
                Reference myRef = uidoc.Selection.PickObject(ObjectType.Element, filter, "スペースを選択してください。キャンセルするにはESCを押します");
                // 選択された要素を取得
                Element selectElement = doc.GetElement(myRef);
                //selectElementをスペースとして認識する
                Autodesk.Revit.DB.Mechanical.Space space = selectElement as Autodesk.Revit.DB.Mechanical.Space;
                //スペースのバウンディングボックスを取得
                (XYZ pMin, XYZ pMax) = GetSpaceBoundary(space);
                //スペースの幅と奥行を取得（内部単位のまま）
                double width = pMax.X - pMin.X;
                double depth = pMax.Y - pMin.Y;
                //空調機の間隔を計算する
                //横方向の間隔
                double dx = width / xNumber;
                //縦方向の間隔
                double dy = depth / yNumber;

                //プロジェクトに登録されている上記に対応した空調機タイプ（シンボル）を検索して取得する
                FamilySymbol acType = new FilteredElementCollector(doc)
                    .OfClass(typeof(FamilySymbol))
                    .OfCategory(BuiltInCategory.OST_MechanicalEquipment)
                    .Cast<FamilySymbol>()
                    .FirstOrDefault(x => (x.Family.Name == ACFamilyName)
                    && ((x.Name == ACTypeName)));

                //空調機を配置する
                if (acType != null && level != null && space != null)
                {
                    using (Transaction tx = new Transaction(doc))
                    {
                        tx.Start("Install HVAC");
                        //空調機タイプが非アクティブならアクティブにする
                        if (!acType.IsActive) acType.Activate();
                        //配置する
                        for (int i = 0; i < xNumber; i++)
                        {
                            for (int j = 0; j < yNumber; j++)
                            {
                                //配置ポイントを計算
                                XYZ pos = new XYZ(pMin.X + dx / 2 + i * dx, pMin.Y + dy / 2 + j * dy, height);
                                //空調機を配置
                                FamilyInstance lightingFixture = doc.Create.NewFamilyInstance(pos, acType, level, StructuralType.NonStructural);
                            }
                        }
                        tx.Commit();
                    }
                }
                else
                {
                    TaskDialog.Show("エラー", "空調機タイプ、レベル、スペースのいずれかがnullです");
                }
            }
            catch (Exception ex)
            {
                // 例外が発生した場合のエラーメッセージ
                TaskDialog.Show("エラー", $"空調機の配置に失敗しました。エラーメッセージ：{ex.Message}");
                return Result.Failed;
            }
            return Result.Succeeded;
        }
        public (XYZ pMin, XYZ pMax) GetSpaceBoundary(Autodesk.Revit.DB.Mechanical.Space space)
        {
            //spaceのバウンディングボックスを取得
            BoundingBoxXYZ bb = space.get_BoundingBox(null);
            //spaceの最小点と最大点を取得
            XYZ pMin = bb.Min;
            XYZ pMax = bb.Max;
            return (pMin, pMax);
        }
    }
    //スペースだけ選択可能にするフィルター
    public class SpaceSelectionFilter : ISelectionFilter
    {
        private readonly Document doc;
        //コンストラクタ
        public SpaceSelectionFilter(Document doc)
        {
            this.doc = doc;
        }
        //要素の選択を許可するかどうかのメソッド
        public bool AllowElement(Element elem)
        {
            if (elem is Autodesk.Revit.DB.SpatialElement)
            {
                return true;
            }
            return false;
        }
        //要素の面やエッジなどジオメトリへの参照を選択できるかどうかのメソッド
        public bool AllowReference(Reference reference, XYZ position)
        {
            return false;
        }
    }
}
