/// <summary>
 /// Constructor used to populate from a dictionary mapping element ids
 /// to a list of child elements.
 /// </summary>
 public CmdInspectElectricalForm2(
     MapParentToChildren map,
     ElementId electricalEquipmentCategoryId,
     IList <Element> electricalEquipment)
 {
     _electricalEquipmentCategoryId = electricalEquipmentCategoryId;
     _comparer = new ElectricalElementComparer(electricalEquipmentCategoryId);
     InitializeComponent();
     tv.BeginUpdate();
     PopulateFromMapParentToChildren(tv.Nodes, ElementId.InvalidElementId, map);
     tv.EndUpdate();
     listBox1.SelectedIndex = 0;
 }
 void PopulateFromMapParentToChildren(
     TreeNodeCollection tnc,
     ElementId parentId,
     MapParentToChildren map)
 {
     if (map.ContainsKey(parentId))
     {
         List <Element> children = map[parentId];
         children.Sort(_comparer);
         string key, text;
         bool   isEquipment; // isCircuit
         foreach (Element e in children)
         {
             if (!_done.ContainsKey(e.Id))
             {
                 _done[e.Id] = 1;
                 //isCircuit = e is ElectricalSystem;
                 isEquipment = e.Category.Id.Equals(_electricalEquipmentCategoryId);
                 key         = Util.ElementDescriptionAndId(e);
                 //text = ( isEquipment || isCircuit ) ? e.Name : Util.BrowserDescription( e );
                 text = ElectricalElementText(e, _electricalEquipmentCategoryId);
                 TreeNode tn = tnc.Add(key, text);
                 CmdInspectElectricalForm.AddLoadNodes(tn, e);
                 if (map.ContainsKey(e.Id))
                 {
                     //
                     // highlight circuit e.g. electrical system node that has
                     // electrical equipment connected to it; also avoid setting
                     // it to bold multiple times over:
                     //
                     if (isEquipment)
                     {
                         TreeNode p = tn.Parent;
                         listBox1.Items.Add(new PanelTreeNodeHelper(e, tn));
                         if (null != p && (null == p.NodeFont || !p.NodeFont.Bold))
                         {
                             p.NodeFont = new System.Drawing.Font(this.Font, FontStyle.Bold);
                         }
                     }
                     PopulateFromMapParentToChildren(tn.Nodes, e.Id, map);
                 }
             }
         }
     }
 }
    static void PopulateChildren( 
      MapParentToChildren mapParentToChildren, 
      Element parent )
    {
      Connector c2 = null;
      ElementId id = parent.Id;
      FamilyInstance fi = parent as FamilyInstance;
      ElectricalSystem eq = parent as ElectricalSystem;
      Debug.Assert( null != fi || null != eq, "expected element to be family instance or electrical system" );
      ConnectorSet connectors = (null == eq)
        ? fi.MEPModel.ConnectorManager.Connectors
        : eq.ConnectorManager.Connectors;
      foreach( Connector c in connectors )
      {
        Debug.Assert( c.Owner.Id.Equals( id ), "expected connector owner to be this element" );
        //if( c.IsConnected ) // only valid for PhysicalConn
        //MEPSystem mepSystem = c.MEPSystem; // null for electrical connector
        //if( null == mepSystem ) // || !mepSystem.Id.IntegerValue.Equals( m_system.Id.IntegerValue )
        //{
        //  continue;
        //}
        //c2 = GetConnectedConnector( c );

        ConnectorSet refs = c.AllRefs;
        Debug.Assert( 1 == refs.Size, "expected one single connected connector" );
        foreach( Connector tmp in refs )
        {
          c2 = tmp;
        }
        if( null != c2 )
        {
          Element e = c2.Owner;
          Debug.Assert( null != e, "expected valid connector owner" );
          Debug.Assert( e is FamilyInstance || e is ElectricalSystem, "expected electrical connector owner to be family instance or electrical equipment" );
          mapParentToChildren.Add( id, e );
        }
      }
    }
        public Result Execute(
            ExternalCommandData commandData,
            ref String message,
            ElementSet elements)
        {
            try
            {
                //
                // dictionary defining tree view info displayed in modeless
                // dialogue mapping parent node to all its circuit elements:
                // null --> root panels
                // panel  --> systems
                // system --> circuit elements, panels, ...
                //
                MapParentToChildren mapParentToChildren           = new MapParentToChildren();
                ElementId           electricalEquipmentCategoryId = ElementId.InvalidElementId;
                List <Element>      equipment;
                {
                    //
                    // run the analysis in its own scope, so the wait cursor
                    // disappears before we display the modeless dialogue:
                    //
                    WaitCursor    waitCursor = new WaitCursor();
                    UIApplication app        = commandData.Application;
                    Document      doc        = app.ActiveUIDocument.Document;
                    ElementId     nullId     = ElementId.InvalidElementId;
                    //
                    // retrieve electrical equipment instances:
                    //
                    equipment = Util.GetElectricalEquipment(doc);
                    int n = equipment.Count;
                    Debug.WriteLine(string.Format("Retrieved {0} electrical equipment instance{1}{2}",
                                                  n, Util.PluralSuffix(n), Util.DotOrColon(n)));
                    Dictionary <string, FamilyInstance> mapPanel = new Dictionary <string, FamilyInstance>();
                    foreach (FamilyInstance e in equipment)
                    {
                        //
                        // ensure that every panel shows up in the list,
                        // even if it does not have children:
                        //
                        mapParentToChildren.Add(e.Id, null);
                        mapPanel[e.Name] = e;
                        MEPModel            mepModel = e.MEPModel;
                        ElectricalSystemSet systems2 = mepModel.ElectricalSystems;
                        string panelAndSystem        = string.Empty;
                        if (null == systems2)
                        {
                            panelAndSystem = CmdElectricalSystemBrowser.Unassigned; // this is a root node
                        }
                        else
                        {
                            Debug.Assert(1 == systems2.Size, "expected equipment to belong to one single panel and system");
                            foreach (ElectricalSystem system in systems2)
                            {
                                if (0 < panelAndSystem.Length)
                                {
                                    panelAndSystem += ", ";
                                }
                                panelAndSystem += system.PanelName + ":" + system.Name + ":" + system.Id.IntegerValue.ToString();
                            }
                        }
                        Debug.WriteLine("  " + Util.ElementDescriptionAndId(e) + " " + panelAndSystem);
                    }
                    //
                    // retrieve electrical systems:
                    // these are also returned by Util.GetCircuitElements(), by the way,
                    // since they have the parameters RBS_ELEC_CIRCUIT_PANEL_PARAM and
                    // RBS_ELEC_CIRCUIT_NUMBER that we use to identify those.
                    //
                    FilteredElementCollector c       = new FilteredElementCollector(doc);
                    IList <Element>          systems = c.OfClass(typeof(ElectricalSystem)).ToElements();
                    n = systems.Count;
                    Debug.WriteLine(string.Format("Retrieved {0} electrical system{1}{2}",
                                                  n, Util.PluralSuffix(n), Util.DotOrColon(n)));
                    foreach (ElectricalSystem system in systems)
                    {
                        string panelName = system.PanelName;
                        if (0 == panelName.Length)
                        {
                            panelName = CmdElectricalSystemBrowser.Unassigned; // will not appear in tree
                        }
                        else
                        {
                            //
                            // todo: is there a more direct way to identify
                            // what panel a system belongs to? this seems error
                            // prone ... what if a panel name occurs multiple times?
                            // how do we identify which one to use?
                            //
                            FamilyInstance panel = mapPanel[panelName];
                            mapParentToChildren.Add(panel.Id, system);
                        }
                        string panelAndSystem = panelName + ":" + system.Name + ":" + system.Id.IntegerValue.ToString();
                        Debug.WriteLine("  " + Util.ElementDescriptionAndId(system) + " " + panelAndSystem);
                        Debug.Assert(system.ConnectorManager.Owner.Id.Equals(system.Id), "expected electrical system's connector manager owner to be system itself");
                    }
                    //
                    // now we have the equipment and systems,
                    // we can build the non-leaf levels of the tree:
                    //
                    foreach (FamilyInstance e in equipment)
                    {
                        MEPModel            mepModel = e.MEPModel;
                        ElectricalSystemSet systems2 = mepModel.ElectricalSystems;
                        if (null == systems2)
                        {
                            mapParentToChildren.Add(nullId, e); // root node
                        }
                        else
                        {
                            Debug.Assert(1 == systems2.Size, "expected equipment to belong to one single panel and system");
                            foreach (ElectricalSystem system in systems2)
                            {
                                mapParentToChildren.Add(system.Id, e);
                            }
                        }
                    }
                    //
                    // list all circuit elements:
                    //
                    BuiltInParameter bipPanel        = BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM;
                    BuiltInParameter bipCircuit      = BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER;
                    IList <Element>  circuitElements = Util.GetCircuitElements(doc);
                    n = circuitElements.Count;
                    Debug.WriteLine(string.Format("Retrieved {0} circuit element{1}...",
                                                  n, Util.PluralSuffix(n)));
                    n = 0;
                    foreach (Element e in circuitElements)
                    {
                        if (e is ElectricalSystem)
                        {
                            ++n;
                        }
                        else
                        {
                            string         circuitName    = e.get_Parameter(bipCircuit).AsString();
                            string         panelName      = e.get_Parameter(bipPanel).AsString();
                            string         key            = panelName + ":" + circuitName;
                            string         panelAndSystem = string.Empty;
                            FamilyInstance inst           = e as FamilyInstance;
                            Debug.Assert(null != inst, "expected all circuit elements to be family instances");
                            MEPModel            mepModel = inst.MEPModel;
                            ElectricalSystemSet systems2 = mepModel.ElectricalSystems;
                            Debug.Assert(null != systems2, "expected circuit element to belong to an electrical system");

                            // this fails in "2341_MEP - 2009 Central.rvt", says martin:
                            //
                            // a circuit element can belong to several systems ... imagine
                            // a piece of telephone equipment which hooks up to a phone line
                            // and also requires power ... so i removed this assertion:
                            //
                            //Debug.Assert( 1 == systems2.Size, "expected circuit element to belong to one single system" );

                            foreach (ElectricalSystem system in systems2)
                            {
                                if (0 < panelAndSystem.Length)
                                {
                                    panelAndSystem += ", ";
                                }
                                panelAndSystem += system.PanelName + ":" + system.Name + ":" + system.Id.IntegerValue.ToString();
                                Debug.Assert(system.PanelName == panelName, "expected same panel name in parameter and electrical system");
                                // this fails in "2341_MEP - 2009 Central.rvt", says martin:
                                //Debug.Assert( system.Name == circuitName, "expected same name in circuit parameter and system" );
                                mapParentToChildren.Add(system.Id, e);
                            }
                            Debug.WriteLine(string.Format("  {0} panel:circuit {1}", Util.ElementDescriptionAndId(e), panelAndSystem));
                        }
                    }
                    Debug.WriteLine(string.Format("{0} circuit element{1} were the electrical systems.",
                                                  n, Util.PluralSuffix(n)));
                    //
                    // get the electrical equipment category id:
                    //
                    Categories categories = doc.Settings.Categories;
                    electricalEquipmentCategoryId = categories.get_Item(BuiltInCategory.OST_ElectricalEquipment).Id;
                }
                //
                // we have assembled the entire required tree view structure, so let us display it:
                //
                CmdInspectElectricalForm2 dialog = new CmdInspectElectricalForm2(mapParentToChildren, electricalEquipmentCategoryId, equipment);
                dialog.Show();
                return(Result.Succeeded);
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return(Result.Failed);
            }
        }
    public Result Execute(
      ExternalCommandData commandData,
      ref String message,
      ElementSet elements )
    {
      UIApplication app = commandData.Application;
      Document doc = app.ActiveUIDocument.Document;
      //
      // retrieve electrical equipment:
      //
      List<Element> equipment = Util.GetElectricalEquipment( doc );
      int n = equipment.Count;
      Debug.WriteLine( string.Format( 
        "Retrieved {0} electrical equipment instance{1}{2}",
        n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) );
      //
      // determine which equipment has parents;
      // the remaining ones are root nodes:
      //
      Dictionary<ElementId, ElementId> equipmentParents 
        = new Dictionary<ElementId, ElementId>();

      foreach( FamilyInstance fi in equipment )
      {
        foreach( Connector c in fi.MEPModel.ConnectorManager.Connectors )
        {
          ConnectorSet refs = c.AllRefs;
          foreach( Connector c2 in refs )
          {
            Debug.Assert( null != c2.Owner, 
              "expected valid connector owner" );

            Debug.Assert( c2.Owner is ElectricalSystem, 
              "expected panel element to be electrical system" );

            ElectricalSystem eq = c2.Owner as ElectricalSystem;
            foreach( Element e2 in eq.Elements )
            {
              Debug.Assert( e2 is FamilyInstance, 
                "expected electrical system element to be family instance" );

              if( !e2.Id.Equals( fi.Id ) )
              {
                if( equipment.Exists( 
                  delegate( Element e ) 
                  { return e.Id.Equals( e2.Id ); } ) )
                {
                  equipmentParents[e2.Id] = eq.Id;
                }
              }
            }
          }
        }
      }

      //n = equipment.RemoveAll( delegate( Element e ) { return subequipment.Exists( delegate( Element e2 ) { return e2.Id.Equals( e.Id ); } ); } );

      //
      // populate parent to children mapping:
      //
      ElementId nullId = ElementId.InvalidElementId;
      MapParentToChildren mapParentToChildren = new MapParentToChildren();

      foreach( FamilyInstance fi in equipment )
      {
        //ElementId parentId = equipmentParents.ContainsKey( fi.Id ) ? equipmentParents[fi.Id] : nullId;
        //mapParentToChildren.Add( parentId, fi );

        //
        // handle root nodes;
        // non-roots are handled below a children:
        //
        if( !equipmentParents.ContainsKey( fi.Id ) )
        {
          mapParentToChildren.Add( nullId, fi );
        }
        
        foreach( Connector c in fi.MEPModel.ConnectorManager.Connectors )
        {
          ConnectorSet refs = c.AllRefs;
          foreach( Connector c2 in refs )
          {
            Debug.Assert( null != c2.Owner, 
              "expected valid connector owner" );

            Debug.Assert( c2.Owner is ElectricalSystem, 
              "expected panel element to be electrical system" );

            ElectricalSystem eq = c2.Owner as ElectricalSystem;
            mapParentToChildren.Add( fi.Id, eq );
            foreach( Element e2 in eq.Elements )
            {
              Debug.Assert( e2 is FamilyInstance, 
                "expected electrical system element to be family instance" );

              if( !e2.Id.Equals( fi.Id ) )
              {
                mapParentToChildren.Add( eq.Id, e2 );
              }
            }
          }
        }
      }

      #region Test code
#if TEST_CODE
      //
      // retrieve electrical systems:
      //
      List<Element> systems = new List<Element>();
      doc.get_Elements( typeof( ElectricalSystem ), systems );
      n = systems.Count;
      Debug.WriteLine( string.Format( "Retrieved {0} electrical system{1}{2}",
        n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) );