#region Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media;
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;

#endregion

namespace RevitAddinCreateColumn
{
    [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 columnFamilyName = "角柱";
            //柱タイプ
            string columnTypeName = "600 x 600mm";
            //柱の位置を設定
            XYZ[] columnPositions = new XYZ[]
            {
                new XYZ(0, 0, 0),
                new XYZ(Uni(7200), 0, 0),
                new XYZ(Uni(7200), Uni(7200), 0),
                new XYZ(0, Uni(7200), 0)
            };
            //柱の上部レベル
            string levelName = "レベル 3";

            //現在開いている平面ビューのレベルを取得する
            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;
            }

            //柱ファミリとタイプを検索して取得する
            FamilySymbol columnType = null;
            try
            {
                //プロジェクトに登録されている上記に対応したファミリとタイプ（シンボル）を検索して取得する
                //柱ファミリを検索
                Family columnFamily = new FilteredElementCollector(doc).OfClass(typeof(Family)).FirstOrDefault(q => q.Name == columnFamilyName) as Family;
                if (columnFamily != null)
                {
                    //柱タイプを検索
                    columnType = columnFamily.GetFamilySymbolIds().Select(q => doc.GetElement(q)).First(q => q.Name == columnTypeName) as FamilySymbol;
                }
                else
                {
                    TaskDialog.Show("エラー", $"指定された柱ファミリ '{columnFamilyName}' が見つかりません。");
                    return Result.Failed;
                }
                //上部レベルを検索
                Level topLevel = new FilteredElementCollector(doc).OfClass(typeof(Level)).FirstOrDefault(q => q.Name == levelName) as Level;
                if (topLevel == null)
                {
                    TaskDialog.Show("エラー", $"指定された上部レベル '{levelName}' が見つかりません。");
                    return Result.Failed;
                }
                //柱を配置する
                if (columnType != null && level != null)
                {
                    using (Transaction tx = new Transaction(doc))
                    {
                        tx.Start("Create Column");
                        //柱の配置
                        foreach (XYZ pos in columnPositions)
                        {
                            //柱タイプが非アクティブならアクティブにする
                            if (!columnType.IsActive) columnType.Activate();
                            //柱を配置
                            FamilyInstance column = doc.Create.NewFamilyInstance(pos, columnType, level, StructuralType.NonStructural);
                            //「上部レベル」パラメータを変更する
                            column.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).Set(topLevel.Id);
                        }
                        tx.Commit();
                    }
                }
            }
            catch (Exception ex)
            {
                // 例外が発生した場合のエラーメッセージ
                TaskDialog.Show("エラー", $"指定された柱タイプ '{columnTypeName}' が見つかりません。エラーメッセージ：{ex.Message}");
                return Result.Failed;
            }

            return Result.Succeeded;
        }
        //ミリメートル単位を内部長さ単位に変換
        private double Uni(double x)
        {
            return UnitUtils.ConvertToInternalUnits(x, UnitTypeId.Millimeters);
        }
    }
}
