#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 RevitAddinCreateSheets
{
    [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[,] zumenList = new string[,]
                    {
                    { "A101","FloorPlan","1階平面図","レベル 1"},
                    { "A102","FloorPlan","2階平面図","レベル 2"}
                    };
            //行数
            int rowsOfZumen = zumenList.GetLength(0);
            //列数
            int columnsOfZumen = zumenList.GetLength(1);

            //図面枠ファミリとタイプを指定
            string zumenwakuFamilyName = "図面枠 A1";
            string zumenwakuTypeName = "図面枠 A1";
            // 図面枠のファミリタイプを取得する
            FamilySymbol titleBlockType = new FilteredElementCollector(doc)
                .OfClass(typeof(FamilySymbol))
                .OfCategory(BuiltInCategory.OST_TitleBlocks)
                .Cast<FamilySymbol>()
                .FirstOrDefault(x => (x.Family.Name == zumenwakuFamilyName)
                && ((x.Name == zumenwakuTypeName)));

            if (titleBlockType == null)
            {
                message = "図面枠ファミリタイプが見つかりません。";
                return Result.Failed;
            }
            //図面枠のBoundingBoxを取得
            BoundingBoxXYZ boundingBox = titleBlockType.get_BoundingBox(doc.ActiveView);
            //図面枠の中心座標を取得(図面枠の中心にシートを配置するため)
            XYZ center = (boundingBox.Max + boundingBox.Min) / 2;

            using (Transaction tx = new Transaction(doc))
            {
                tx.Start("Transaction Create Sheets");
                //全部のシートを作る
                for (int i = 0; i < rowsOfZumen; i++)
                {
                    //シート番号
                    string sheetNumber = zumenList[i, 0];
                    //ビューのファミリタイプ
                    string viewFamilyTypeName = zumenList[i, 1];
                    //シート名
                    string sheetName = zumenList[i, 2];
                    //ビュー名
                    string viewName = zumenList[i, 3];


                    //新しいシートを作成
                    ViewSheet sheet = ViewSheet.Create(doc, titleBlockType.Id);
                    SetParameter(sheet, "シート番号", sheetNumber);
                    sheet.Name = sheetName; ;//シート名
                    //シートに配置する平面ビューを取得
                    View view = new FilteredElementCollector(doc)
                        .OfClass(typeof(View))
                        .Cast<View>()
                        .FirstOrDefault(v => (v.Name == viewName) && (v.ViewType.ToString() == viewFamilyTypeName));
                    //シートの中央にViewportを作り、そこに平面ビューを追加
                    if (view != null)
                    {
                        Viewport.Create(doc, sheet.Id, view.Id, center);
                    }
                }
                tx.Commit();
            }

            return Result.Succeeded;
        }
        public bool SetParameter(Element elem, string paramName, object val)
        {
            foreach (Parameter param in elem.GetOrderedParameters())
            {
                string name = param.Definition.Name;
                if (name.Equals(paramName))
                {
                    switch (val)
                    {
                        case string s:
                            param.Set(s);
                            break;
                        case int i:
                            param.Set(i);
                            break;
                        case double d:
                            param.Set(d);
                            break;
                        default:
                            return false;
                    }
                    return true;
                }
            }
            return false;
        }
    }
}
