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

#endregion

namespace RevitAddinWallHeight2
{
    [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;

            try
            {
                // 選択フィルターを設定
                WallSelectionFilter filter = new WallSelectionFilter(doc);

                // フィルター付きでユーザーに壁インスタンスを選択してもらう
                Autodesk.Revit.DB.Reference myRef = uidoc.Selection.PickObject(ObjectType.Element, filter, "壁を選択してください。キャンセルするにはESCを押します");

                // 選択された要素を取得
                Element selectElement = doc.GetElement(myRef);

                // ファミリ名、タイプ名、カテゴリを取得
                Wall wall = selectElement as Wall;
                string familyName = wall.WallType.FamilyName;
                string typeName = wall.WallType.Name;
                string categeryName = selectElement.Category.Name;

                //壁の高さを取得
                string heightStr = GetParameter(wall, "指定高さ");
                //heightStrがnullまたは空でないか確認
                if (!string.IsNullOrEmpty(heightStr))
                {
                    // heightStrが数値に変換できるか確認
                    if (double.TryParse(heightStr, out double height))
                    {
                        //内部単位をミリメートルに変換
                        double heightInMM = (int)Math.Round(UnitUtils.ConvertFromInternalUnits(height, UnitTypeId.Millimeters), 0);
                        // 結果を表示
                        TaskDialog.Show("壁の情報",
                            $"壁の高さ: {heightInMM}\n" +
                            $"ファミリ名: {familyName} / " +
                            $"タイプ名: {typeName}");
                        return Result.Succeeded;
                    }
                    else
                    {
                        // 数値変換に失敗した場合
                        message = $"壁高さが数値に変換できませんでした。";
                        return Result.Failed;
                    }
                }
                else
                {
                    // 「heightStrがnullまたは空」=パラメータが見つからない場合
                    message = $"壁の「指定高さ」パラメータが見つかりませんでした。";
                    return Result.Failed;
                }
            }
            catch (Autodesk.Revit.Exceptions.OperationCanceledException)
            {
                // ユーザーがキャンセルした場合
                return Result.Cancelled;
            }
            catch (Exception ex)
            {
                // その他のエラーが発生した場合
                message = $"エラーが発生しました: {ex.Message}";
                return Result.Failed;
            }
        }
        private static string ParameterToString(Parameter param)
        {
            string val = "none";
            if (param == null)
            {
                return val;
            }
            switch (param.StorageType)
            {
                case StorageType.Double:
                    double dVal = param.AsDouble();
                    val = dVal.ToString();
                    break;
                case StorageType.Integer:
                    int iVal = param.AsInteger();
                    val = iVal.ToString();
                    break;
                case StorageType.String:
                    string sVal = param.AsString();
                    //もしnullならAsValueStringで読んでみる
                    if (sVal == null) sVal = param.AsValueString();
                    val = sVal;
                    break;
                case StorageType.ElementId:
                    ElementId idVal = param.AsElementId();
                    val = idVal.ToString();
                    break;
                case StorageType.None:
                    break;
                default:
                    break;
            }
            return val;
        }
        //要素の指定パラメータ１つを取得する
        private string GetParameter(Element elem, string paramName)
        {
            string result = null;
            foreach (Parameter param in elem.GetOrderedParameters())
            {
                string name = param.Definition.Name;
                if (name.Equals(paramName))
                {
                    result = ParameterToString(param);
                    break;
                }
            }
            return result;
        }
    }

    public class WallSelectionFilter : ISelectionFilter
    {
        private readonly Document doc;
        //コンストラクタ
        public WallSelectionFilter(Document doc)
        {
            this.doc = doc;
        }
        //要素の選択を許可するかどうかのメソッド
        public bool AllowElement(Element elem)
        {
            if (elem is Autodesk.Revit.DB.Wall)
            {
                return true;
            }

            return false;
        }
        //要素の面やエッジなどジオメトリへの参照を選択できるかどうかのメソッド
        public bool AllowReference(Autodesk.Revit.DB.Reference reference, XYZ position)
        {
            return false;
        }
    }
}