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

#endregion

namespace RevitAddinCreateCeiling
{
    [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;
            View activeView = uidoc.ActiveView;
            //天井のタイプ
            string ceilingTypeName = "グリッド 600x600mm";
            //天井高さ設定
            double ceilingHeight = 2800; //mm
            // 天井の高さを指定（ミリメートル単位をフィート単位に変換）
            double ceilingHeightFt = UnitUtils.ConvertToInternalUnits(ceilingHeight, UnitTypeId.Millimeters);
            //今開いているのは平面ビューか？
            if (!(activeView is ViewPlan viewPlan))
            {
                TaskDialog.Show("エラー", "現在のビューは平面ビューではありません。");
                return Result.Failed;
            }
            // 天井タイプを取得
            CeilingType ceilingType = new FilteredElementCollector(doc)
                .OfClass(typeof(CeilingType))
                .Where(typ => typ.Name == ceilingTypeName)
                .First() as CeilingType;
            // 天井を配置する部屋Roomを選択
            Reference roomRef = uidoc.Selection.PickObject(
                ObjectType.Element,
                new RoomSelectionFilter(doc),
                "天井を作成するRoomを選択してください");
            Room room = doc.GetElement(roomRef) as Room;
            if (room == null)
            {
                message = "選択された要素がRoomではありません。";
                return Result.Failed;
            }
            // Roomの境界を取得
            SpatialElementBoundaryOptions options = new SpatialElementBoundaryOptions();
            IList<IList<BoundarySegment>> boundaries = room.GetBoundarySegments(options);
            if (boundaries == null || boundaries.Count == 0)
            {
                message = "Roomの境界が取得できません。";
                return Result.Failed;
            }
            // Roomの境界から天井の輪郭用のCurveLoopを作成
            CurveLoop curveLoop = new CurveLoop();
            foreach (BoundarySegment segment in boundaries[0])
            {
                curveLoop.Append(segment.GetCurve());
            }
            try
            {
                if (ceilingType != null)
                {
                    // トランザクション開始
                    using (Transaction tx = new Transaction(doc))
                    {
                        tx.Start("Create Ceiling");
                        // 天井を作成
                        Ceiling ceiling = Ceiling.Create(
                            doc,
                            new CurveLoop[] { curveLoop },
                            ceilingType.Id,
                            room.Level.Id);
                        if (ceiling != null)//天井が正常に作成された場合
                        {
                            // 天井の高さオフセットを設定
                            Parameter heightOffsetParam = ceiling.get_Parameter(BuiltInParameter.CEILING_HEIGHTABOVELEVEL_PARAM);
                            if (heightOffsetParam != null && !heightOffsetParam.IsReadOnly)
                            {
                                heightOffsetParam.Set(ceilingHeightFt);
                            }
                            tx.Commit();
                            TaskDialog.Show("成功", $"Room '{room.Name}' に高さ{ceilingHeight}の天井を正常に作成しました。");
                        }
                    }
                }
                else
                {
                    TaskDialog.Show("エラー", "天井タイプが見つかりません。");
                    return Result.Failed;
                }
            }
            catch (System.Exception ex)
            {
                TaskDialog.Show("エラー", $"天井の作成に失敗しました。エラーメッセージ：{ex.Message}");
                return Result.Failed;
            }
            return Result.Succeeded;
        }
    }
    // Room選択用のフィルター
    public class RoomSelectionFilter : ISelectionFilter
    {
        private readonly Document doc;
        //コンストラクタ
        public RoomSelectionFilter(Document doc)
        {
            this.doc = doc;
        }
        //要素の選択を許可するかどうかのメソッド
        public bool AllowElement(Element elem)
        {
            return elem is Room;
        }
        //要素の面やエッジなどジオメトリへの参照を選択できるかどうかのメソッド
        public bool AllowReference(Reference reference, XYZ position)
        {
            return false;
        }
    }
}
