// Generates the core of the HTML file for the given page of the index.
        private static void OutputIndexPage(CIndexPage indexpage, CHTMLFile f)
        {
            int nTotal = indexpage.m_nTotalIndis + indexpage.m_alLetters.Count;

              if (indexpage.m_alLetters.Count > 0)
              {
            ArrayList alFirstHalf = new ArrayList();
            ArrayList alSecondHalf = new ArrayList();
            ArrayList alCurrentHalf = alFirstHalf;

            int nHalfWay;
            if (nTotal < 20)
            {
              // If less than 20 individuals, list them in one nColumn.
              // Set half-way pointer beyond end so that it is never reached.
              nHalfWay = nTotal + 1;
            }
            else
            {
              nHalfWay = (nTotal + 1) / 2;
            }
            int nAdded = 0;

            foreach (CIndexLetter letter in indexpage.m_alLetters)
            {
              if (nAdded == nHalfWay)
              {
            // Don't add heading letter to bottom of first half.
            alCurrentHalf = alSecondHalf;
              }

              // Add heading letter.
              alCurrentHalf.Add(new CStringTuple(letter.m_sTitle, ""));
              ++nAdded;

              // Add indis.
              foreach (CStringTuple tuple in letter.m_alItems)
              {
            if (nAdded == nHalfWay)
            {
              alCurrentHalf = alSecondHalf;
            }
            alCurrentHalf.Add(tuple);
            ++nAdded;
              }
            }

            // Output HTML.
            OutputIndexPageColumns(f, alFirstHalf, alSecondHalf);
              }
              else
              {
            f.m_sw.WriteLine("    <p>There are no individuals to list.</p>");
              }
        }
        // Generates the HTML file for the given page of the index.
        private static void OutputIndividualsIndexPage(CGedcom gedcom, string sHeadingsLinks, CIndexPage indexpage)
        {
            LogFile.TheLogFile.WriteLine(LogFile.DT_HTML, LogFile.EDebugLevel.Note, "OutputIndividualsIndexPage()");

              string sOwner = MainForm.s_config.m_sOwnersName;
              if (sOwner != "")
              {
              sOwner = " of " + sOwner;
              }

              string sFullFilename = MainForm.s_config.m_sOutputFolder;
              if (sFullFilename != "")
              {
              sFullFilename += "\\";
              }
              sFullFilename += indexpage.m_sFilename;

              CHTMLFile f = null;
              try
              {
            f = new CHTMLFile(sFullFilename, MainForm.s_config.m_sIndexTitle, "Index of all individuals in the family tree" + sOwner, "individuals index family tree people history dates"); // Creates a new file, and puts standard header html into it.

            OutputPageHeader(f.m_sw, "", "", false, true);

            f.m_sw.WriteLine("    <div class=\"hr\" />");
            f.m_sw.WriteLine("");

            f.m_sw.WriteLine("  <div id=\"page\">");
            f.m_sw.WriteLine(String.Concat("    <h1 class=\"centred\">", MainForm.s_config.m_sIndexTitle, "</h1>"));

            if (sHeadingsLinks != "")
            {
              f.m_sw.WriteLine("    <div id=\"headingsLinks\">");
              f.m_sw.WriteLine(String.Concat("      <p>", sHeadingsLinks, "</p>"));
              f.m_sw.WriteLine("    </div>");
            }

            OutputIndexPage(indexpage, f);

            f.m_sw.WriteLine("  </div> <!-- page -->");
              }
              catch (IOException e)
              {
            LogFile.TheLogFile.WriteLine(LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught IO Exception(3) : " + e.ToString());
              }
              catch (ArgumentException e)
              {
            LogFile.TheLogFile.WriteLine(LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught Argument Exception(3) : " + e.ToString());
              }
              finally
              {
            if (f != null)
            {
              f.Close();
            }
              }
        }
 // Splits the index across multiple pages
 private static ArrayList CreateIndexPages(ArrayList alLetters)
 {
     ArrayList alPages = new ArrayList();
       uint uLetters = (uint)(alLetters.Count);
       uint uIndisPerPage;
       if( MainForm.s_config.m_bMultiPageIndexes == false )
       {
     // Set to 0 for all names in one page.
     uIndisPerPage = 0;
       }
       else
       {
     uIndisPerPage = MainForm.s_config.m_uIndividualsPerIndexPage;
       }
       uint uIndiAccumulator = 0;
       uint uCurrentPage = 0;
       string sCurrentPageName = String.Format("individuals{0}.{1}", ++uCurrentPage, MainForm.s_config.m_sHtmlExtension);
       CIndexPage indexpageCurrent = new CIndexPage(sCurrentPageName);
       uint uLetter = 0;
       while (uLetter < uLetters)
       {
     uint uCurrentIndis = (uint)(((CIndexLetter)alLetters[(int)uLetter]).m_alItems.Count);
     if (uIndisPerPage != 0 && uIndiAccumulator + uCurrentIndis > uIndisPerPage)
     {
       uint uWith = (uint)(uIndiAccumulator + uCurrentIndis - uIndisPerPage);
       uint uWithout = uIndisPerPage - uIndiAccumulator;
       if (uWith < uWithout || uIndiAccumulator == 0)
       {
     // Better to include it.
     indexpageCurrent.m_nTotalIndis += ((CIndexLetter)alLetters[(int)uLetter]).m_alItems.Count;
     indexpageCurrent.m_alLetters.Add(alLetters[(int)uLetter++]);
       }
       // Start new page.
       alPages.Add(indexpageCurrent);
       sCurrentPageName = String.Format("individuals{0}.{1}", ++uCurrentPage, MainForm.s_config.m_sHtmlExtension);
       indexpageCurrent = new CIndexPage(sCurrentPageName);
       uIndiAccumulator = 0;
     }
     else
     {
       indexpageCurrent.m_nTotalIndis += ((CIndexLetter)alLetters[(int)uLetter]).m_alItems.Count;
       indexpageCurrent.m_alLetters.Add(alLetters[(int)uLetter++]);
       uIndiAccumulator += uCurrentIndis;
     }
       }
       if (indexpageCurrent != null)
       {
     alPages.Add(indexpageCurrent);
       }
       return alPages;
 }