/// <summary>
            /// Create a new node for a HCUnit.
            /// </summary>
            /// <param name="hcunit"></param>
            public OrbatNode(HCUnit hcunit)
                : base(hcunit.Title)
            {
                this.hcunit = hcunit;

                this.Update();
            }
        /// <summary>
        /// Displays a series of dummy events for alert testing.
        /// </summary>
        public void TestAlert()
        {
            this.currentEvents.Clear();
            this.currentIndex = 0;

            DateTime         time          = DateTime.Now.AddMinutes(-10);
            Country          newOwner      = new Country(1, "UK", Language.Country_Name_England, Language.Country_Demonym_England, Side.Allied);
            Country          prevOwner     = new Country(4, "DE", Language.Country_Name_Germany, Language.Country_Demonym_Germany, Side.Axis);
            ChokePoint       testCP        = new ChokePoint(0, "Berlin", ChokePointType.Generic, prevOwner, new Point(), null);
            MilitaryFacility testFacility  = new MilitaryFacility(0, "Berlin Central Armybase", testCP, FacilityType.Armybase, new Point());
            Facility         testFacility2 = new Facility(0, "Bilton's House", testCP, FacilityType.City, new Point());
            HCUnit           testHCUnit    = new HCUnit(0, HCUnitLevel.Brigade, "27idkg1", "1.Kampfgruppe", "27.Infanterie 1.Kampfgruppe", null, prevOwner, Branch.Army, MoveType.Land, null, null);

            this.currentEvents.Add(new FacilityCapturedGameEvent(time, testFacility, newOwner, prevOwner, "xiper"));
            this.currentEvents.Add(new HCUnitRoutedGameEvent(time, testHCUnit, testCP));
            this.currentEvents.Add(new ChokePointCapturedGameEvent(time, testCP, newOwner, prevOwner, DateTime.Now.AddMinutes(-171)));

            testCP.SetInitState(prevOwner, newOwner, testHCUnit);
            testCP.Activity    = ActivityLevel.Heavy;
            testFacility.Owner = newOwner;

            if (tmrAutoNext.Enabled)
            {
                tmrAutoNext.Stop();
            }

            if (this.Visible)
            {
                this.Visible = false;
            }

            DisplayAlerts();
        }
        // text colour
        private void tvwOrbat_DrawText(object sender, DrawEventArgs e)
        {
            e.TextBrush = new SolidBrush(Color.FromArgb(224, 224, 224)); // default forecolor

            HCUnit hcunit = ((OrbatNode)e.Node.Tag).hcunit;

            if (hcunit == null)
            {
                return;
            }

            if (hcunit.IsDeployable && !hcunit.IsDeployed)
            {
                e.TextBrush = Brushes.Gray; // is an undeployed division or brigade
            }
            else if (sender == tvwOrbatTxtChokePoint)
            {
                // color of chokepoint column depends on how recently the unit has
                // been moved, within the past 24 hours

                if (hcunit.LastMovedPlayer == null)
                {
                    return;                           // not moved recently
                }
                e.TextBrush = new SolidBrush(Misc.GetFadedYellow(hcunit.LastMovedTime, 12 * 60, 224));
            }
        }
        // don't show right-click menu on non-brigade/divisions
        private void cmsOrbat_Opening(object sender, System.ComponentModel.CancelEventArgs e)
        {
            HCUnit hcunit = this.SelectedBrigade;

            if (hcunit == null)
            {
                e.Cancel = true;
            }
        }
 /// <summary>
 /// Adds any child HCUnits to the given node.
 /// </summary>
 /// <param name="parentNode">The node under which to add items.</param>
 /// <param name="parentUnit">The HCUnit containing child units.</param>
 private void PopulateNode(Node parentNode, HCUnit parentUnit)
 {
     foreach (HCUnit childUnit in parentUnit.ChildUnits)
     {
         Node childNode = new OrbatNode(childUnit);
         parentNode.Nodes.Add(childNode);
         PopulateNode(childNode, childUnit);
     }
 }
        private void miEquipment_Click(object sender, EventArgs e)
        {
            HCUnit hcunit = this.SelectedBrigade;

            if (hcunit == null)
            {
                return;
            }

            GameStatus_RevealWidget(WidgetType.Equipment, hcunit.Toe);
        }
 /// <summary>
 /// A recursive method to find the tree node that is associated with the given HCUnit.
 /// </summary>
 /// <param name="root">The root node to start searching.</param>
 /// <param name="hcunit">The HCUnit to look for.</param>
 /// <returns>The node if found, otherwise null.</returns>
 private TreeNodeAdv FindOrbatNode(TreeNodeAdv root, HCUnit hcunit)
 {
     foreach (TreeNodeAdv node in root.Nodes)
     {
         if (((OrbatNode)node.Tag).hcunit == hcunit)
         {
             return(node);
         }
         TreeNodeAdv res = FindOrbatNode(node, hcunit);
         if (res != null)
         {
             return(res);
         }
     }
     return(null);
 }
        /// <summary>
        /// Populates the tree with the given countries and hcunit hierarchy.
        /// </summary>
        /// <param name="countrys">An array of Country's.</param>
        /// <param name="topHCUnit">The top-level HCUnit that contains all other hcunits.</param>
        private void PopulateTree(IEnumerable <Country> countrys, HCUnit topHCUnit)
        {
            tvwOrbat.BeginUpdate();

            ((TreeModel)tvwOrbat.Model).Nodes.Clear();

            foreach (Country country in countrys)
            {
                if (!country.IsActive)
                {
                    continue;
                }

                Node countryNode = new OrbatNode(country.Name);
                ((TreeModel)tvwOrbat.Model).Nodes.Add(countryNode);

                foreach (int branch in Enum.GetValues(typeof(Branch)))
                {
                    if (branch == (int)Branch.None)
                    {
                        continue;
                    }

                    Node branchNode = new OrbatNode(Misc.EnumString((Branch)branch));
                    countryNode.Nodes.Add(branchNode);

                    if (topHCUnit != null)
                    {
                        foreach (HCUnit hcunit in topHCUnit.ChildUnits) // top levels
                        {
                            if (hcunit.Country != country || hcunit.Branch != (Branch)branch)
                            {
                                continue;
                            }

                            Node hcunitNode = new OrbatNode(hcunit);
                            branchNode.Nodes.Add(hcunitNode);
                            PopulateNode(hcunitNode, hcunit);
                        }
                    }
                }
            }

            RestoreTree();
            tvwOrbat.EndUpdate();
            ResizeWidget();
        }
            /// <summary>
            /// Gets a tooltip for the orbat entries.
            /// </summary>
            /// <returns>The tooltip string, or null if no tooltip.</returns>
            public string GetToolTip(TreeNodeAdv node, NodeControl nodeControl)
            {
                HCUnit hcunit = ((OrbatNode)node.Tag).hcunit;

                if (hcunit == null)
                {
                    return(null);
                }

                if (nodeControl.ParentColumn.Index == 2)
                {
                    return(hcunit.TooltipRedeploy);
                }
                else
                {
                    return(hcunit.Tooltip);
                }
            }
        /// <summary>
        /// Recurses down the hcunit tree and generates a pair of parallel lists containing
        /// supply info for the currently selected vehicle.
        /// </summary>
        /// <param name="parent">The parent hcunit to process.</param>
        /// <param name="hcunits">A list containing the units that have the selected vehicle.</param>
        /// <param name="count">A list containing the number of vehicles the unit has.</param>
        private void GetSupply(HCUnit parent, ref List <HCUnit> hcunits, ref List <int> count)
        {
            int cycle = (int)numSupplyCycle.Value;


            // add unit if it's toe contains the vehicle and has supply

            if (parent.Toe != null && parent.Toe.Vehicles.Contains(this.selectedVehicle) &&
                cycle < parent.Toe[this.selectedVehicle].Cycle.Length && parent.Toe[this.selectedVehicle].Cycle[cycle] > 0)
            {
                hcunits.Add(parent);
                count.Add(parent.Toe[this.selectedVehicle].Cycle[cycle]);
            }


            // recurse child units

            foreach (HCUnit child in parent.ChildUnits)
            {
                GetSupply(child, ref hcunits, ref count);
            }
        }
        /// <summary>
        /// Makes the Order of Battle widget visible by making sure it's expanded, scrolling it into
        /// view, and expanding the relevant tree nodes to select the given hcunit.
        /// </summary>
        /// <seealso cref="tmrReveal_Tick"/>
        /// <param name="arg">The HCUnit to select.</param>
        public void Reveal(object arg)
        {
            HCUnit hcunit = arg as HCUnit;

            if (hcunit == null)
            {
                return;
            }

            if (tmrReveal.Enabled)
            {
                return; // another Reveal() in progress
            }
            TreeNodeAdv node = FindOrbatNode(tvwOrbat.Root, hcunit);

            if (node == null)
            {
                return;           // not found;
            }
            tvwOrbat.EnsureVisible(node);
            node.IsExpanded       = true;
            tvwOrbat.SelectedNode = node;

            Expando expOrderOfBattle = (Expando)this.Parent;

            if (expOrderOfBattle.Collapsed)
            {
                expOrderOfBattle.Collapsed = false; // animate
                tmrReveal.Start();                  // scroll into view after animation
            }
            else
            {
                if (expOrderOfBattle.TaskPane != null)
                {
                    expOrderOfBattle.TaskPane.ScrollControlIntoView(expOrderOfBattle);
                }
            }
        }
        /// <summary>
        /// Generates an image of all hcunits that have supply of the currently selected vehicle.
        /// </summary>
        /// <param name="hcunits">A list of hcunits.</param>
        /// <param name="count">A list of the hcunits' supply numbers.</param>
        /// <param name="imgmap">An ImageMap on which to add tooltips & clickable regions.</param>
        /// <returns>The supply image to display.</returns>
        private Image GenerateSupplyImage(IList <HCUnit> hcunits, IList <int> count, ImageMap.ImageMap imgmap)
        {
            // calculate required dimensions

            const int lineHeight    = 14;
            int       linesRequired = 0;

            HCUnit prevDivision = null;

            foreach (HCUnit hcunit in hcunits)
            {
                linesRequired++;
                HCUnit division = hcunit.Level == HCUnitLevel.Division ? hcunit : hcunit.ParentUnit;
                if (division != prevDivision)
                {
                    linesRequired++; prevDivision = division;
                }
            }

            if (linesRequired == 0)
            {
                linesRequired = 4; // for "not available" message
            }
            int height = (linesRequired * lineHeight) + 2;
            int width  = imgmap.Width;


            // create bitmap, graphics objects

            Bitmap   bitmap = new Bitmap(width, height);
            Graphics g      = Graphics.FromImage(bitmap);

            g.SmoothingMode     = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;


            // remove previous tooltips

            imgmap.RemoveAll();


            // create graphics resources

            Brush brushMain         = new SolidBrush(Color.FromArgb(192, 192, 192));
            Brush brushHCUnitAllied = new SolidBrush(Color.FromArgb(128, 204, 255)); // light blue
            Brush brushHCUnitAxis   = new SolidBrush(Color.FromArgb(255, 178, 102)); // orange

            Font fontMain = new Font("Tahoma", 8.25F);

            StringFormat alignRight = new StringFormat {
                Alignment = StringAlignment.Far
            };
            StringFormat alignCenter = new StringFormat {
                Alignment = StringAlignment.Center
            };


            // hcunit loop

            int y = 0;

            prevDivision = null;

            for (int i = 0; i < hcunits.Count; i++)
            {
                HCUnit hcunit   = hcunits[i];
                HCUnit division = hcunit.Level == HCUnitLevel.Division ? hcunit : hcunit.ParentUnit;
                HCUnit brigade  = hcunit.Level == HCUnitLevel.Brigade  ? hcunit : hcunit.GetDummyDivHQBrigade();


                // draw division heading

                if (division != prevDivision)
                {
                    g.DrawImage(division.Country.BrigadeFlag, 0, y + 2.5F, 17.57F, 9); // 41x21
                    g.DrawString(division.Title, fontMain, brushMain, 17, y);

                    y           += lineHeight;
                    prevDivision = division;
                }


                // draw unit title

                g.FillEllipse(hcunit.Country.Side == Side.Allied ? brushHCUnitAllied : brushHCUnitAxis,
                              21, y + 4, 5, 5);
                g.DrawString(brigade.Title, fontMain, brushMain, 29, y);

                int stringWidth = (int)g.MeasureString(brigade.Title, fontMain, width - 29).Width - 4;
                imgmap.AddRectangle(Language.Common_Tooltip_GoToBrigade, new Rectangle(30, y + 2, stringWidth, 10), true, hcunit);


                // draw count

                g.DrawString(count[i].ToString(), fontMain, brushMain, 250, y, alignRight);


                y += lineHeight;
            } // end hcunit loop


            // if none available, show message

            if (hcunits.Count == 0)
            {
                g.DrawString(String.Format(Language.Equipment_NotAvailable, numSupplyCycle.Value),
                             fontMain, brushMain, pnlSupply.Width / 2, lineHeight * 2.5F, alignCenter);
            }
            // note: int division intentional

            // all done

            g.Dispose();
            return(bitmap);
        }
        /// <summary>
        /// Generate an info image for the given ChokePoint, showing facility status,
        /// deployed hcunits, and linked cps.
        /// </summary>
        /// <param name="cp">The reference ChokePoint.</param>
        /// <param name="imgmap">An ImageMap on which to add tooltips & clickable regions.</param>
        /// <returns>The info image.</returns>
        private Image GenerateInfoImage(ChokePoint cp, ImageMap.ImageMap imgmap)
        {
            #region Init

            // get data

            ReadOnlyCollection <Bridge>    nearbyBridges = cp.GetNearbyBridges(game.Bridges);
            SortedList <float, ChokePoint> attackFrom    = cp.AttackFrom;


            // calculate required dimensions

            const int lineHeight    = 14;
            int       linesRequired = 5;

            if (attackFrom.Count == 1)
            {
                linesRequired += 1;
            }
            else if (attackFrom.Count > 1)
            {
                linesRequired += 1 + attackFrom.Count;
            }

            if (cp.IsContested)
            {
                linesRequired += 2; // capbar
            }
            linesRequired += 1 + cp.Facilities.Count;

            if (cp.LinkedChokePoints.Count > 0)
            {
                linesRequired += 1 + cp.LinkedChokePoints.Count;
            }

            if (cp.DeployedHCUnits.Count > 0)
            {
                linesRequired++;
                HCUnit prevDivision = null;
                foreach (HCUnit hcunit in cp.DeployedHCUnits)
                {
                    linesRequired++;
                    HCUnit division = hcunit.Level == HCUnitLevel.Division ? hcunit : hcunit.ParentUnit;
                    if (division != prevDivision)
                    {
                        linesRequired++; prevDivision = division;
                    }
                }
            }

            if (nearbyBridges.Count > 0)
            {
                linesRequired += 1 + nearbyBridges.Count;
            }

            int       height = (linesRequired * lineHeight) + 2;
            const int width  = 334;


            // create bitmap, graphics resources

            Bitmap   bitmap = new Bitmap(width, height);
            Graphics g      = Graphics.FromImage(bitmap);
            g.SmoothingMode     = SmoothingMode.HighQuality;
            g.InterpolationMode = InterpolationMode.High;

            Brush brushMain         = new SolidBrush(Color.FromArgb(192, 192, 192));
            Brush brushHead         = new SolidBrush(Color.FromArgb(224, 224, 224));
            Brush brushHCUnitAllied = new SolidBrush(Color.FromArgb(128, 204, 255)); // light blue
            Brush brushHCUnitAxis   = new SolidBrush(Color.FromArgb(255, 178, 102)); // orange

            Pen penDark = new Pen(Color.FromArgb(80, 80, 80));

            Font fontMain = new Font("Tahoma", 8.25F);
            Font fontHead = new Font("Tahoma", 8.25F, FontStyle.Bold);

            StringFormat alignRight = new StringFormat {
                Alignment = StringAlignment.Far
            };
            StringFormat formatNoWrap = new StringFormat {
                FormatFlags = StringFormatFlags.NoWrap
            };                                                                                  // prevents odd spacing when line is clipped

            DateTime oneHourAgo     = DateTime.Now.AddHours(-1);
            DateTime twelveHoursAgo = DateTime.Now.AddHours(-12);

            imgmap.RemoveAll(); // remove previous tooltips

            int   y    = 0;
            int[] xTab = new[] { 2, 15, 32, 44 };
            int   stringWidth;

            #endregion

            #region General info

            // get x position for owner/controller values

            float xFlagPos = 80; // min
            stringWidth = (int)g.MeasureString(Language.Misc_OwnedBy, fontHead).Width;
            if (xTab[0] + stringWidth + 2 > xFlagPos)
            {
                xFlagPos = xTab[0] + stringWidth + 2;
            }
            stringWidth = (int)g.MeasureString(Language.Misc_ControlledBy, fontHead).Width;
            if (xTab[0] + stringWidth + 2 > xFlagPos)
            {
                xFlagPos = xTab[0] + stringWidth + 2;
            }
            xFlagPos = (float)Math.Round(xFlagPos);


            // owner

            g.DrawString(Language.Misc_OwnedBy, fontHead, brushHead, xTab[0], y);
            g.DrawImage(cp.Owner.CountryFlag, xFlagPos, y + 3.5F, 12, 7.125F);

            string captured = null;
            if (cp.LastOwnerChanged > twelveHoursAgo) // within past 12 hours
            {
                captured = " (" + String.Format(Language.Time_CapturedMinsAgo, Misc.MinsAgoLong(cp.LastOwnerChanged)) + ")";
            }

            g.DrawString(String.Format("{0}{1}", cp.Owner, captured), fontMain, brushMain, xFlagPos + 15, y);
            y += lineHeight;


            // controller

            g.DrawString(Language.Misc_ControlledBy, fontHead, brushHead, xTab[0], y);
            g.DrawImage(cp.Controller.CountryFlag, xFlagPos, y + 3.5F, 12, 7.125F);

            string gained = null;
            if (cp.LastControllerChanged > twelveHoursAgo) // within past 12 hours
            {
                gained = " (" + String.Format(cp.Controller.Side == cp.Owner.Side ? Language.Time_RegainedMinsAgo : Language.Time_GainedMinsAgo,
                                              Misc.MinsAgoLong(cp.LastControllerChanged)) + ")";
            }

            g.DrawString(String.Format("{0}{1}", cp.Controller, gained), fontMain, brushMain, xFlagPos + 15, y);
            y += lineHeight;


            // contested

            if (cp.IsContested)
            {
                g.DrawImage(Resources.contested, xTab[1], y + 2, 13, 10.52F); // 21x17

                string since = null;
                if (cp.LastContestedChanged > twelveHoursAgo) // within past 12 hours
                {
                    since = " (" + String.Format(Language.Time_ForMins, Misc.MinsAgoLong(cp.LastContestedChanged)) + ")";
                }

                g.DrawString(Language.Misc_Contested + since, fontMain, brushMain, xTab[2], y);
            }
            else
            {
                g.DrawImage(Resources.uncontested, xTab[1], y + 2, 13, 10.52F); // 21x17

                string since = null;
                if (cp.LastContestedChanged > twelveHoursAgo) // within past 12 hours
                {
                    since = " (" + String.Format(Language.Time_ForMins, Misc.MinsAgoLong(cp.LastContestedChanged)) + ")";
                }

                g.DrawString(Language.Misc_Uncontested + since, fontMain, brushMain, xTab[2], y);
            }
            y += lineHeight;


            // attack objective

            if (cp.HasAO)
            {
                g.DrawImage(Resources.attack_objective, xTab[1], y + 2, 12, 10.29F); // 21x18

                string placed = null;
                if (cp.LastAOChanged > twelveHoursAgo) // within past 12 hours
                {
                    placed = " (" + String.Format(Language.Time_PlacedMinsAgo, Misc.MinsAgoLong(cp.LastAOChanged)) + ")";
                }
                g.DrawString(Language.TownStatus_AttackObjective + placed, fontMain, brushMain, xTab[2], y);

                string attackUnit = cp.AttackingHCUnit.Title;
                if (cp.AttackingHCUnit.DeployedChokePoint != null)
                {
                    attackUnit += " " + String.Format(Language.Misc_AtChokePoint, cp.AttackingHCUnit.DeployedChokePoint);
                }

                string aoTooltip = String.Format(Language.TownStatus_Tooltip_AOPlacedBy, attackUnit);

                imgmap.AddRectangle(aoTooltip, new Rectangle(xTab[1], y + 2, 100, 10));

                y += lineHeight;
            }
            else
            {
                g.DrawImage(Resources.no_attack_objective, xTab[1], y + 2, 12, 10.29F); // 21x18

                string removed = null;
                if (cp.LastAOChanged > twelveHoursAgo) // within past 12 hours
                {
                    removed = " (" + String.Format(Language.Time_RemovedMinsAgo, Misc.MinsAgoLong(cp.LastAOChanged)) + ")";
                }

                g.DrawString(Language.TownStatus_NoAttackObjective + removed, fontMain, brushMain, xTab[2], y);
                y += lineHeight;
            }


            // activity level

            g.DrawImage(cp.ActivityImage, xTab[1], y + 2, 12, 10.8F); // 20x18
            g.DrawString(Language.TownStatus_Activity + " " + Misc.EnumString(cp.Activity), fontMain, brushMain, xTab[2], y);
            y += lineHeight;


            // attack from

            if (attackFrom.Count > 0)
            {
                if (attackFrom.Count == 1)
                {
                    g.DrawString(Language.TownStatus_UnderAttackFrom + " " + attackFrom.Values[0].Name, fontMain, brushMain, xTab[2], y);
                    y += lineHeight;
                }
                else
                {
                    g.DrawString(Language.TownStatus_UnderAttackFrom, fontMain, brushMain, xTab[2], y);
                    y += lineHeight;

                    for (int i = attackFrom.Count - 1; i >= 0; i--)
                    {
                        g.DrawString(String.Format("{0} ({1:0}%)", attackFrom.Values[i], attackFrom.Keys[i]), fontMain, brushMain, xTab[3], y);
                        y += lineHeight;
                    }
                }
            }

            #endregion

            #region Base counts

            int countArmybase = 0, countAirbase = 0, countNavalbase = 0;

            foreach (Facility facility in cp.Facilities)
            {
                if (facility.Type == FacilityType.Armybase)
                {
                    countArmybase++;
                }
                else if (facility.Type == FacilityType.Airbase)
                {
                    countAirbase++;
                }
                else if (facility.Type == FacilityType.Navalbase)
                {
                    countNavalbase++;
                }
            }

            int yOffset = 0;
            if (countArmybase > 0)
            {
                g.DrawImage(Resources.armybase, 300, yOffset, 18, 16);
                g.DrawString("x" + countArmybase, fontMain, brushMain, 334, yOffset + 1, alignRight);
                yOffset += 18;
            }
            if (countAirbase > 0)
            {
                g.DrawImage(Resources.airbase, 300, yOffset, 18, 16);
                g.DrawString("x" + countAirbase, fontMain, brushMain, 334, yOffset + 1, alignRight);
                yOffset += 20;
            }
            if (countNavalbase > 0)
            {
                g.DrawImage(Resources.navalbase, 300, yOffset, 18, 16);
                g.DrawString("x" + countNavalbase, fontMain, brushMain, 334, yOffset + 1, alignRight);
            }

            #endregion

            #region Capbar

            if (cp.IsContested)
            {
                const int left  = 19;
                const int right = 319;
                int       range = right - left;
                int       mid   = (int)((100 - cp.PercentOwnership) * range / 100) + left;

                g.DrawImage(cp.Owner.Side == Side.Allied ? Resources.capbar_red_left : Resources.capbar_blue_left,
                            left - 4, y + 9, 4, 10);
                g.DrawImage(cp.Owner.Side == Side.Allied ? Resources.capbar_red : Resources.capbar_blue,
                            new Rectangle(left, y + 9, mid - left, 10),
                            new Rectangle(0, 0, 1, 10), GraphicsUnit.Pixel);
                g.DrawImage(cp.Owner.Side == Side.Allied ? Resources.capbar_blue : Resources.capbar_red,
                            new Rectangle(mid, y + 9, right - mid, 10),
                            new Rectangle(0, 0, 1, 10), GraphicsUnit.Pixel);
                g.DrawImage(cp.Owner.Side == Side.Allied ? Resources.capbar_blue_right : Resources.capbar_red_right,
                            right, y + 9, 4, 10);
                g.DrawImage(Resources.capbar_pointer, mid - 13, y + 6, 27, 23);

                y += lineHeight + lineHeight;
            }

            #endregion

            #region Facility list

            int maxNameWidth = 255;

            // heading(s)

            g.DrawString(Language.TownStatus_Section_Facilities, fontHead, brushHead, xTab[0], y);
            if (cp.HasAO || cp.IsContested)
            {
                g.DrawString(Language.TownStatus_Tables, fontMain, brushHead, 252, y);
                maxNameWidth = 215;
            }
            if (cp.IsContested)
            {
                g.DrawString(Language.TownStatus_HeldFor, fontMain, brushHead, 250, y, alignRight);
                maxNameWidth = 160;
            }
            g.DrawString(Language.TownStatus_Spawn, fontMain, brushHead, 297, y);


            // facility loop

            foreach (Facility facility in cp.Facilities)
            {
                y += lineHeight;


                // owner flag & facility icon

                g.DrawImage(facility.Owner.CountryFlag, xTab[1], y + 3.5F, 12, 7.125F);
                g.DrawImage(facility.Icon, xTab[2], y + 2.5F, 11, 8.94F);


                // facility name

                g.DrawString(facility.Name, fontMain, brushMain, new RectangleF(xTab[3], y, maxNameWidth, lineHeight), formatNoWrap);


                // held for column

                if (cp.IsContested)
                {
                    if (facility.LastOwnerChanged > twelveHoursAgo) // within past 12 hours
                    {
                        Brush brush;
                        if (facility.LastOwnerChanged < oneHourAgo)
                        {
                            brush = new SolidBrush(Color.FromArgb(128, 128, 128));
                        }
                        else
                        {
                            brush = new SolidBrush(Misc.GetFadedYellow(facility.LastOwnerChanged, 15, 192));
                        }

                        g.DrawString(Misc.MinsAgoShort(facility.LastOwnerChanged), fontMain, brush, 250, y, alignRight);
                        imgmap.AddRectangle(Misc.Timestamp(facility.LastOwnerChanged) + " " + String.Format(Language.TownStatus_Tooltip_CapturedBy, facility.LastCapper),
                                            new Rectangle(210, y + 2, 38, 10));
                    }
                    else
                    {
                        g.DrawLine(penDark, 209, y + 6, 247.5F, y + 6);
                    }
                }


                // table status column

                if (cp.HasAO || cp.IsContested)
                {
                    if (facility.RadioTableUp)
                    {
                        g.DrawImage(Resources.table_up, 269, y + 2, 12, 10);
                    }
                    else
                    {
                        g.DrawImage(Resources.table_down, 269, y + 2, 12, 10);
                    }
                }


                // spawnable column

                Image  spawnImage;
                string spawnTooltip;

                if (!facility.SpawnableFacility)
                {
                    spawnImage   = Resources.spawn_nonspawnable;
                    spawnTooltip = null;
                }
                else if (facility.Owner.Side == cp.Owner.Side) // friendly
                {
                    if (facility.EnemySpawnable)
                    {
                        spawnImage   = Resources.spawn_enemyspawnable;
                        spawnTooltip = Language.TownStatus_Tooltip_SpawnSpawnable;
                    }
                    else if (facility.OwnerCanSpawn)
                    {
                        spawnImage   = Resources.spawn_friendly;
                        spawnTooltip = Language.TownStatus_Tooltip_SpawnFriendly;
                    }
                    else
                    {
                        spawnImage   = Resources.spawn_closed;
                        spawnTooltip = Language.TownStatus_Tooltip_SpawnClosed;
                    }
                }
                else // enemy
                {
                    if (facility.OwnerCanSpawn)
                    {
                        spawnImage   = Resources.spawn_enemy;
                        spawnTooltip = Language.TownStatus_Tooltip_SpawnEnemy;
                    }
                    else
                    {
                        spawnImage   = Resources.spawn_closed;
                        spawnTooltip = Language.TownStatus_Tooltip_SpawnClosed;
                    }
                }

                g.DrawImage(spawnImage, 311, y + 2, 9, 9);
                if (spawnTooltip != null)
                {
                    imgmap.AddRectangle(spawnTooltip, new Rectangle(311, y + 2, 9, 9));
                }
            } // end facility loop

            #endregion

            #region Deployed hcunits

            if (cp.DeployedHCUnits.Count > 0)
            {
                int xTimeColumn = new BegmMisc.TextWidth(fontMain, 70, 230).MeasureAll(cp.DeployedHCUnits).MaxWidth + 100;

                y += lineHeight;
                g.DrawString(Language.TownStatus_Section_HCUnits, fontHead, brushHead, xTab[0], y);

                HCUnit prevDivision = null;

                foreach (HCUnit hcunit in cp.DeployedHCUnits)
                {
                    y += lineHeight;

                    HCUnit division = hcunit.Level == HCUnitLevel.Division ? hcunit : hcunit.ParentUnit;
                    HCUnit brigade  = hcunit.Level == HCUnitLevel.Brigade  ? hcunit : hcunit.GetDummyDivHQBrigade();

                    if (division != prevDivision) // draw division heading w/ tooltip
                    {
                        prevDivision = division;

                        g.DrawImage(division.Country.BrigadeFlag, xTab[1], y + 2.5F, 17.57F, 9); // 41x21
                        g.DrawString(division.Title, fontMain, brushMain, xTab[2], y);

                        string divTooltip = null;
                        if (division.IsDeployed)
                        {
                            if (division.DeployedChokePoint != cp)
                            {
                                divTooltip = String.Format(Language.Common_Tooltip_DivisionDeployed, division.DeployedChokePoint);
                            }
                        }
                        else
                        {
                            divTooltip = Language.Common_Tooltip_DivisionNotDeployed;
                        }

                        if (divTooltip != null)
                        {
                            stringWidth = (int)g.MeasureString(division.Title, fontMain, width - 32).Width - 2;
                            imgmap.AddRectangle(divTooltip, new Rectangle(xTab[2] + 1, y + 2, stringWidth, 10), true, division);
                        }

                        y += lineHeight;
                    }


                    // draw unit title, time w/ last moved tooltip

                    g.FillEllipse(hcunit.Country.Side == Side.Allied ? brushHCUnitAllied : brushHCUnitAxis,
                                  xTab[2] + 4, y + 4, 5, 5);
                    g.DrawString(brigade.Title, fontMain, brushMain, xTab[3], y);
                    if (hcunit.HasLastMoved)
                    {
                        g.DrawString(Misc.MinsAgoShort(hcunit.LastMovedTime), fontMain, brushMain, xTimeColumn, y, alignRight);
                    }

                    string brigTooltip = hcunit.Tooltip;
                    if (brigTooltip != null)
                    {
                        stringWidth = (int)g.MeasureString(brigade.Title, fontMain, width - xTab[3]).Width - 2;
                        imgmap.AddRectangle(brigTooltip, new Rectangle(xTab[3] + 1, y + 2, stringWidth, 10), true, hcunit);
                    }
                }
            }

            #endregion

            #region Linked cps/firebases

            if (cp.LinkedChokePoints.Count > 0)
            {
                // calc x position for kms column based on max town name length

                float xKmsColumn = 170; // min
                foreach (ChokePoint linkedChokePoint in cp.LinkedChokePoints)
                {
                    stringWidth = (int)g.MeasureString(linkedChokePoint.Name, fontMain).Width;
                    if (stringWidth + 100 > xKmsColumn)
                    {
                        xKmsColumn = stringWidth + 100;
                    }
                }


                y += lineHeight;
                g.DrawString(Language.TownStatus_Section_LinkedTowns, fontHead, brushHead, xTab[0], y);

                foreach (ChokePoint linkedChokePoint in cp.LinkedChokePoints)
                {
                    y += lineHeight;


                    // owner flag

                    g.DrawImage(linkedChokePoint.Owner.CountryFlag, xTab[1], y + 3.5F, 12, 7.125F);
                    imgmap.AddRectangle(String.Format(Language.Common_Tooltip_GoToMap, linkedChokePoint.Name), new Rectangle(xTab[1], y + 3, 12, 8), true, linkedChokePoint.ID);


                    // fb icon

                    Firebase linkedFirebase = cp.GetFirebaseFrom(linkedChokePoint);
                    string   fbTooltip;

                    if (linkedFirebase == null)
                    {
                        fbTooltip = String.Format(Language.TownStatus_Tooltip_FirebaseNone, cp, linkedChokePoint);
                    }
                    else // draw fb icon
                    {
                        Image fbImage;

                        if (linkedFirebase.Link.State == FirebaseState.Inactive)
                        {
                            fbImage   = Resources.facility_firebase;
                            fbTooltip = String.Format(Language.TownStatus_Tooltip_FirebaseInactive, cp, linkedChokePoint);
                        }
                        else if (linkedFirebase.IsOpen)
                        {
                            fbImage   = Resources.facility_firebase_open;
                            fbTooltip = String.Format(Language.TownStatus_Tooltip_FirebaseUp,
                                                      linkedChokePoint, cp, Misc.EnumString(linkedFirebase.Link.State).ToLower(), Misc.EnumString(linkedFirebase.Link.Side));
                        }
                        else
                        {
                            fbImage   = Resources.facility_firebase_closed;
                            fbTooltip = String.Format(Language.TownStatus_Tooltip_FirebaseDown,
                                                      linkedChokePoint, cp, Misc.EnumString(linkedFirebase.Link.State).ToLower(), Misc.EnumString(linkedFirebase.Link.Side));
                        }

                        g.DrawImage(fbImage, xTab[2], y + 2.5F, 11, 8.94F);
                    }
                    imgmap.AddRectangle(fbTooltip, new Rectangle(xTab[2], y + 2, 11, 9));


                    // linked cp name

                    g.DrawString(linkedChokePoint.Name, fontMain, brushMain, xTab[3], y);
                    stringWidth = (int)g.MeasureString(linkedChokePoint.Name, fontMain, width - xTab[3]).Width - 2;
                    imgmap.AddRectangle(String.Format(Language.Common_Tooltip_GoToStatus, linkedChokePoint.Name), new Rectangle(xTab[3] + 1, y + 2, stringWidth, 10), true, linkedChokePoint);


                    // distance

                    double distance = Misc.DistanceBetween(cp.LocationOctets, linkedChokePoint.LocationOctets) * 0.8; // x 800m / 1000m
                    g.DrawString(distance.ToString("0.0 km"), fontMain, brushMain, (int)xKmsColumn, y, alignRight);
                }
            }

            #endregion

            #region Nearby bridges

            if (nearbyBridges.Count > 0)
            {
                y += lineHeight;
                g.DrawString(Language.TownStatus_Section_Bridges, fontHead, brushHead, xTab[0], y);

                foreach (Bridge bridge in nearbyBridges)
                {
                    y += lineHeight;
                    g.DrawImage(Resources.bridge, xTab[2], y + 3, 11, 9);
                    g.DrawString(bridge.Name, fontMain, brushMain, xTab[3], y);
                }
            }

            #endregion

            g.Dispose();
            return(bitmap);
        }