#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;

#endregion

namespace RevitAddinWallLinkedModel
{
    [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
            {
                //選択した壁
                Wall selectedWall = null;
                //壁が属するドキュメント
                Document elementDoc = doc;
                // 壁が選択されるまで繰り返し
                while (selectedWall == null)
                {
                    try
                    {
                        // 要素を選択。リンクされた要素にはフィルターが使えない
                        Reference myRef = uidoc.Selection.PickObject(ObjectType.LinkedElement,
                            "リンクしている建築モデルから壁を選択してください。キャンセルするにはESCを押します");
                        // 選択された要素用の変数宣言
                        Element selectElement = null;
                        // リンクされた要素か？
                        if (myRef.LinkedElementId != ElementId.InvalidElementId)
                        {
                            // リンクインスタンスを取得する
                            RevitLinkInstance linkInstance = doc.GetElement(myRef.ElementId) as RevitLinkInstance;
                            if (linkInstance != null)
                            {
                                // リンクインスタンスが属しているリンクドキュメントを取得する
                                Document linkedDoc = linkInstance.GetLinkDocument();
                                if (linkedDoc != null)
                                {
                                    //リンクドキュメントから要素を取得する
                                    selectElement = linkedDoc.GetElement(myRef.LinkedElementId);
                                    elementDoc = linkedDoc;

                                    //上記で得られたselectElementがnullでないことを確認する
                                    if (selectElement != null)
                                    {
                                        // nullではないので、壁かどうかをチェックする。Wallにキャストを試みる
                                        selectedWall = selectElement as Wall;
                                        if (selectedWall == null)//壁としては認識されない場合
                                        {
                                            // リンクモデルの要素だが、壁以外が選択された場合、再試行を促す
                                            TaskDialogResult retryResult = TaskDialog.Show("選択エラー",
                                                $"選択された要素は壁ではありません。\n" +
                                                $"選択された要素のカテゴリ: {selectElement.Category.Name}\n\n" +
                                                $"壁を選択し直しますか？",
                                                TaskDialogCommonButtons.Yes | TaskDialogCommonButtons.No);

                                            if (retryResult == TaskDialogResult.Yes)
                                            {
                                                continue; // Yesの場合はwhileループが継続される
                                            }
                                            else
                                            {
                                                return Result.Cancelled;
                                            }
                                        }
                                    }
                                    else
                                    {
                                        TaskDialog.Show("エラー", "選択された要素が取得できませんでした。再度リンクモデルの壁を選択してださい。");
                                        continue;
                                    }
                                }
                            }
                            else
                            {
                                TaskDialog.Show("エラー", "選択された要素はリンクインスタンスではありません。再度リンクモデルの壁を選択してください。");
                                continue;
                            }
                        }
                    }
                    catch (Autodesk.Revit.Exceptions.OperationCanceledException)
                    {
                        return Result.Cancelled;
                    }
                } //whileループの終わり

                // 壁の情報を取得
                string familyName = selectedWall.WallType.FamilyName;
                string typeName = selectedWall.WallType.Name;
                string categoryName = selectedWall.Category.Name;

                // 結果を表示
                TaskDialog.Show("選択された壁",
                    $"{elementDoc.Title}\n" +
                    $"要素カテゴリ: {categoryName}\n" +
                    $"ファミリ名: {familyName}\n" +
                    $"タイプ名: {typeName}");

                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                message = $"エラーが発生しました: {ex.Message}";
                return Result.Failed;
            }
        }
    }
}
