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 public Result Execute2(
            ExternalCommandData commandData,
            ref String message,
            ElementSet elements,
            bool populateFullHierarchy)
        {
            try
            {
                WaitCursor    waitCursor = new WaitCursor();
                UIApplication app        = commandData.Application;
                Document      doc        = app.ActiveUIDocument.Document;
                //
                // display electrical equipment instance data,
                // i.e. equipment_name:system_name, and convert it to
                // a map from key = panel:circuit --> 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)));
                Dictionary <string, List <Element> > mapPanelAndSystemToEquipment = new Dictionary <string, List <Element> >();
                foreach (FamilyInstance elecEqip in equipment)
                {
                    ListEquipment(elecEqip, mapPanelAndSystemToEquipment);
                }
                //
                // determine mapping from panel to circuit == electrical system:
                //
                Dictionary <string, ElectricalSystemSet> mapPanelToSystems = new Dictionary <string, ElectricalSystemSet>();
                IList <Element> systems = Util.GetElectricalSystems(doc);
                n = systems.Count;
                Debug.WriteLine(string.Format("Retrieved {0} electrical system{1}.", n, Util.PluralSuffix(n)));
                //
                // all circuits which are fed from the same family instance have
                // the same panel name, so you can retrieve all of these circuits.
                //
                // todo: there is an issue here if there are several different panels
                // with the same name! they will get merged in the tree view,
                // but they should stay separate. possible workaround: add the
                // element id to keep them separate, and then remove it again
                // when displaying in tree view.
                //
                foreach (ElectricalSystem system in systems)
                {
                    string panelName = system.PanelName;

                    Debug.WriteLine("  system " + system.Name + ": panel " + panelName
                                    + " load classifications " + system.LoadClassifications);

                    if (!mapPanelToSystems.ContainsKey(panelName))
                    {
                        mapPanelToSystems.Add(panelName, new ElectricalSystemSet());
                    }
                    mapPanelToSystems[panelName].Insert(system);
                }
                n = mapPanelToSystems.Count;
                //Debug.WriteLine( string.Format( "Mapping from the {0} panel{1} to systems, system name :circuit name(connectors/unused connectors):", n, Util.PluralSuffix( n ) ) );
                Debug.WriteLine(string.Format("Mapping from the {0} panel{1} to electrical systems == circuits:",
                                              n, Util.PluralSuffix(n)));
                List <string> keys = new List <string>(mapPanelToSystems.Keys);
                keys.Sort();
                string s;
                foreach (string panelName in keys)
                {
                    s = string.Empty;
                    foreach (ElectricalSystem system in mapPanelToSystems[panelName])
                    {
                        ConnectorManager cmgr = system.ConnectorManager;

                        // the connector manager does not include any logical connectors
                        // in the Revit 2009 fcs and wu1 API, only physical ones:
                        //Debug.Assert( 0 == cmgr.Connectors.Size,
                        //  "electrical connector count is always zero" );

                        Debug.Assert(cmgr.UnusedConnectors.Size <= cmgr.Connectors.Size,
                                     "unused connectors is a subset of connectors");

                        Debug.Assert(system.Name.Equals(system.CircuitNumber),
                                     "ElectricalSystem Name and CircuitNumber properties are always identical");

                        //s += ( 0 < s.Length ? ", " : ": " ) + system.Name;

                        s += (0 < s.Length ? ", " : ": ") + system.Name // + ":" + system.CircuitNumber
                             + "(" + cmgr.Connectors.Size.ToString()
                             + "/" + cmgr.UnusedConnectors.Size.ToString() + ")";
                    }
                    Debug.WriteLine("  " + panelName + s);
                }

                /*
                 * Debug.WriteLine( "Mapping from panels to systems to connected elements:" );
                 * foreach( string panelName in keys )
                 * {
                 * Debug.WriteLine( "  panel " + panelName + ":" );
                 * foreach( ElectricalSystem system in mapPanelToSystems[panelName] )
                 * {
                 *  ConnectorManager cmgr = system.ConnectorManager;
                 *  n = cmgr.Connectors.Size;
                 *  Debug.WriteLine( string.Format( "    system {0} has {1} connector{2}{3}", system.Name, n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) );
                 *  foreach( Connector connector in system.ConnectorManager.Connectors )
                 *  {
                 *    Element owner = connector.Owner;
                 *    Debug.WriteLine( string.Format( "    owner {0} {1}, domain {2}", owner.Name, owner.Id.IntegerValue, connector.Domain ) );
                 *  }
                 * }
                 * }
                 */

                //
                // list all circuit elements:
                //
                // this captures all elements in circuits H-2: 2, 4, 6 etc,
                // but not the element T2 in H-2:1,3,5, because it has no circuit number,
                // just a panel number.
                //
                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}{2}",
                                              n, Util.PluralSuffix(n), Util.DotOrColon(n)));
                Dictionary <string, List <Element> > mapPanelAndCircuitToElements = new Dictionary <string, List <Element> >();
                foreach (Element e in circuitElements)
                {
                    string circuitName = e.get_Parameter(bipCircuit).AsString();
                    //
                    // do not map an electrical system to itself:
                    //
                    if (!(e is ElectricalSystem && e.Name.Equals(circuitName)))
                    {
                        string panelName = e.get_Parameter(bipPanel).AsString();
                        string key       = panelName + ":" + circuitName;
                        Debug.WriteLine(string.Format("  {0} <{1} {2}> panel:circuit {3}", e.GetType().Name, e.Name, e.Id.IntegerValue, key));
                        if (!mapPanelAndCircuitToElements.ContainsKey(key))
                        {
                            mapPanelAndCircuitToElements.Add(key, new List <Element>());
                        }
                        mapPanelAndCircuitToElements[key].Add(e);
                    }
                }
                n = mapPanelAndCircuitToElements.Count;
                Debug.WriteLine(string.Format("Mapped circuit elements to {0} panel:circuit{1}{2}",
                                              n, Util.PluralSuffix(n), Util.DotOrColon(n)));
                keys.Clear();
                keys.AddRange(mapPanelAndCircuitToElements.Keys);
                keys.Sort(new PanelCircuitComparer());
                foreach (string panelAndCircuit in keys)
                {
                    List <string> a = new List <string>(mapPanelAndCircuitToElements[panelAndCircuit].Count);
                    foreach (Element e in mapPanelAndCircuitToElements[panelAndCircuit])
                    {
                        FamilyInstance inst = e as FamilyInstance;
                        a.Add((null == inst ? e.Category.Name : inst.Symbol.Family.Name) + " " + e.Name);
                    }
                    a.Sort();
                    s = string.Join(", ", a.ToArray());
                    Debug.WriteLine("  " + panelAndCircuit + ": " + s);
                }

                #region Aborted attempt to use RBS_ELEC_CIRCUIT_PANEL_PARAM
#if USE_RBS_ELEC_CIRCUIT_PANEL_PARAM
                //
                // list all panel elements:
                //
                // selecting all elements with a BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER
                // captures all elements in circuits H-2: 2, 4, 6 etc, but not the element
                // T2 in H-2:1,3,5, because it has no circuit number, just a panel number.
                //
                // so grab everything with a panel number instead.
                //
                // all this added to the selection was lots of wires, so forget it again.
                //
                BuiltInParameter bipCircuit      = BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER;
                BuiltInParameter bipPanel        = BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM;
                List <Element>   circuitElements = new List <Element>();
                Util.GetElementsWithParameter(circuitElements, bipPanel, app);
                n = circuitElements.Count;
                Debug.WriteLine(string.Format("Retrieved {0} circuit element{1}{2}",
                                              n, Util.PluralSuffix(n), Util.DotOrColon(n)));
                Dictionary <string, List <Element> > mapCircuitToElements = new Dictionary <string, List <Element> >();
                foreach (Element e in circuitElements)
                {
                    string    panelName = e.get_Parameter(bipPanel).AsString();
                    Parameter p         = e.get_Parameter(bipCircuit);
                    if (null == p)
                    {
                        Debug.WriteLine(string.Format("  {0} <{1} {2}> panel:circuit {3}:null", e.GetType().Name, e.Name, e.Id.IntegerValue, panelName));
                    }
                    else
                    {
                        string circuitName = p.AsString();
                        //
                        // do not map an electrical system to itself:
                        //
                        if (!(e is ElectricalSystem && e.Name.Equals(circuitName)))
                        {
                            string key = panelName + ":" + circuitName;
                            Debug.WriteLine(string.Format("  {0} <{1} {2}> panel:circuit {3}", e.GetType().Name, e.Name, e.Id.IntegerValue, key));
                            if (!mapCircuitToElements.ContainsKey(key))
                            {
                                mapCircuitToElements.Add(key, new List <Element>());
                            }
                            mapCircuitToElements[key].Add(e);
                        }
                    }
                }
                n = mapCircuitToElements.Count;
                Debug.WriteLine(string.Format("Mapped circuit elements to {0} panel:circuit{1}{2}",
                                              n, Util.PluralSuffix(n), Util.DotOrColon(n)));
                keys.Clear();
                keys.AddRange(mapCircuitToElements.Keys);
                keys.Sort(new PanelCircuitComparer());
                foreach (string circuitName in keys)
                {
                    List <string> a = new List <string>(mapCircuitToElements[circuitName].Count);
                    foreach (Element e in mapCircuitToElements[circuitName])
                    {
                        FamilyInstance inst = e as FamilyInstance;
                        a.Add((null == inst ? e.Category.Name : inst.Symbol.Family.Name) + " " + e.Name);
                    }
                    a.Sort();
                    s = string.Join(", ", a.ToArray());
                    Debug.WriteLine("  " + circuitName + ": " + s);
                }
#endif // USE_RBS_ELEC_CIRCUIT_PANEL_PARAM
                #endregion // Aborted attempt to use RBS_ELEC_CIRCUIT_PANEL_PARAM

                //
                // merge the two trees of equipment and circuit elements
                // to reproduce the content of the system browser ... the
                // hardest part of this is setting up the PanelSystemComparer
                // to generate the same sort order as the system browser:
                //
                //n = mapPanelAndSystemToEquipment.Count + mapPanelAndCircuitToElements.Count;
                //Dictionary<string, List<Element>> mapSystemBrowser = new Dictionary<string, List<Element>>( n );
                Dictionary <string, List <Element> > mapSystemBrowser = new Dictionary <string, List <Element> >(mapPanelAndCircuitToElements);
                foreach (KeyValuePair <string, List <Element> > pair in mapPanelAndSystemToEquipment)
                {
                    mapSystemBrowser[pair.Key] = pair.Value;
                }
                n = mapSystemBrowser.Count;
                Debug.WriteLine(string.Format("Mapped equipment + circuit elements to {0} panel:system{1}{2}",
                                              n, Util.PluralSuffix(n), Util.DotOrColon(n)));
                keys.Clear();
                keys.AddRange(mapSystemBrowser.Keys);
                keys.Sort(new PanelSystemComparer());
                foreach (string panelAndSystem in keys)
                {
                    List <string> a = new List <string>(mapSystemBrowser[panelAndSystem].Count);
                    foreach (Element e in mapSystemBrowser[panelAndSystem])
                    {
                        a.Add(Util.BrowserDescription(e));
                    }
                    a.Sort();
                    s = string.Join(", ", a.ToArray());
                    Debug.WriteLine(string.Format("  {0}({1}): ", panelAndSystem, a.Count) + s);
                }
                //
                // get the electrical equipment category id:
                //
                Categories categories = doc.Settings.Categories;
                ElementId  electricalEquipmentCategoryId = categories.get_Item(BuiltInCategory.OST_ElectricalEquipment).Id;
                //
                // we have assembled the required information and structured it
                // sufficiently for the tree view, so now let us go ahead and display it:
                //
                CmdInspectElectricalForm dialog = new CmdInspectElectricalForm(mapSystemBrowser, electricalEquipmentCategoryId, populateFullHierarchy);
                dialog.Show();
                return(Result.Succeeded);
            }
            catch (Exception ex)
            {
                message = ex.Message;
                return(Result.Failed);
            }
        }