// The main method that causes the page to be created.
        public bool Create(CStats stats)
        {
            // Sanity check
              if( m_sr == null )
              {
            return false;
              }

              // Create the strings to use for the HTML file.
              string sPageDescription = "GEDmill GEDCOM to HTML page for " + m_sr.m_sSourceDescriptiveTitle;
              string sKeywords = "family tree history " + m_sr.m_sSourceDescriptiveTitle;
              string sFilename = String.Concat( MainForm.s_config.m_sOutputFolder, "\\sour", m_sr.m_xref );
              string sFullFilename = String.Concat(sFilename, ".", MainForm.s_config.m_sHtmlExtension);

              CHTMLFile f = null;
              try
              {
            // Create a new file with an HTML header.
            f = new CHTMLFile( sFullFilename, m_sr.DescriptiveTitle, sPageDescription, sKeywords );

            // Create a navbar to main site, front page etc.
            OutputPageHeader( f.m_sw, "", "", true, true );

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

            // Write the page's title text.
            f.m_sw.WriteLine("      <div id=\"main\">");
            f.m_sw.WriteLine("        <div id=\"summary\">");
            f.m_sw.WriteLine("          <div id=\"names\">");
            string sName = m_sr.DescriptiveTitle;
            if( sName == "" )
            {
              sName = "Source ";
              bool bGotSourceName = false;
              // Try user reference number
              foreach( CUserReferenceNumber urn in m_sr.m_alUserReferenceNumbers )
              {
            if( urn.m_sUserReferenceNumber != "" )
            {
              sName += urn.m_sUserReferenceNumber;
              bGotSourceName = true;
              break;
            }
              }
              if( !bGotSourceName && m_sr.m_sAutomatedRecordId != null && m_sr.m_sAutomatedRecordId != "" )
              {
            sName += m_sr.m_sAutomatedRecordId;
              }
              else if( !bGotSourceName )
              {
            sName += m_sr.m_xref;
              }
            }
            f.m_sw.WriteLine(String.Concat("            <h1>",EscapeHTML(sName,false ),"</h1>"));

            // Add repository information
            foreach( CSourceRepositoryCitation src in m_sr.m_alSourceRepositoryCitations )
            {
              string xrefRepo = src.m_xrefRepo;
              CRepositoryRecord rr = m_gedcom.GetRepositoryRecord( xrefRepo );
              if( rr != null )
              {
              if (rr.m_sNameOfRepository != null && rr.m_sNameOfRepository != "")
              {
                  f.m_sw.WriteLine(String.Concat("            <h2>", EscapeHTML(rr.m_sNameOfRepository, false), "</h2>"));
              }
            if( rr.m_alNoteStructures != null && rr.m_alNoteStructures.Count > 0 )
            {
              foreach( CNoteStructure ns in rr.m_alNoteStructures )
              {
                string noteText;
                if( MainForm.s_config.m_bObfuscateEmails )
                {
                  noteText = ObfuscateEmail( ns.Text );
                }
                else
                {
                  noteText = ns.Text;
                }
                f.m_sw.WriteLine(String.Concat("            <p>", EscapeHTML( noteText, false ), "</p>" ) );
              }
            }
              }
              if( src.m_alNoteStructures != null && src.m_alNoteStructures.Count > 0 )
              {
            foreach( CNoteStructure ns in src.m_alNoteStructures )
            {
              string noteText;
              if( MainForm.s_config.m_bObfuscateEmails )
              {
                noteText = ObfuscateEmail( ns.Text );
              }
              else
              {
                noteText = ns.Text;
              }

              f.m_sw.WriteLine(String.Concat("            <p>", EscapeHTML( noteText, false ), "</p>" ) );
            }
              }

            }

            // Add Publication Information
            string sPubFacts;
            if( MainForm.s_config.m_bObfuscateEmails )
            {
              sPubFacts = ObfuscateEmail( m_sr.m_sSourcePublicationFacts );
            }
            else
            {
              sPubFacts = m_sr.m_sSourcePublicationFacts;
            }
            if( sPubFacts != null && sPubFacts != "" )
            {
              if( sPubFacts.Length > 7 && sPubFacts.ToUpper().Substring(0,7) == "HTTP://" )
              {
            f.m_sw.WriteLine(String.Concat("            <h2>","<a href=\"", sPubFacts, "\">", EscapeHTML(sPubFacts,false), "</a>","</h2>"));
              }
              else
              {
            f.m_sw.WriteLine(String.Concat("            <h2>",EscapeHTML(sPubFacts,false),"</h2>"));
              }
            }

            f.m_sw.WriteLine("          </div> <!-- names -->");
            f.m_sw.WriteLine("        </div> <!-- summary -->");

            // Collect together multimedia links.
            if( MainForm.s_config.m_bAllowMultimedia && m_sr.m_alUniqueFileRefs != null )
            {
              m_sr.m_alUniqueFileRefs.Sort( new CMultimediaFileReference.OrderComparer() );

              // Fill m_alMultimediaList:
              AddMultimedia( null, m_sr.m_alUniqueFileRefs, String.Concat(m_sr.m_xref,"mms"), String.Concat(m_sr.m_xref,"mos"), MainForm.s_config.m_uMaxSourceImageWidth, MainForm.s_config.m_uMaxSourceImageHeight, stats );
            }

            // Add pics
            OutputMultimedia(f);

            // Add textFromSource
            string sCleanText = m_sr.m_sTextFromSource;
            CGedcom.ParseWhitespace( ref sCleanText );
            if( MainForm.s_config.m_bObfuscateEmails )
            {
              sCleanText = ObfuscateEmail( sCleanText );
            }
            if( sCleanText != null && sCleanText != "" )
            {
              f.m_sw.WriteLine("        <div id=\"text\">");
              f.m_sw.WriteLine("          <h1>Text</h1>");
              f.m_sw.WriteLine("          <p class=\"pretext\">");
              f.m_sw.WriteLine( EscapeHTML( sCleanText,false) );
              f.m_sw.WriteLine("            </p>");
              f.m_sw.WriteLine("        </div> <!-- text -->");
            }

            // Add notes
            if( m_sr.m_alNoteStructures.Count > 0 )
            {
              // Generate notes list into a local array before adding header title. This is to cope with the case where all notes are nothing but blanks.
              ArrayList alNoteStrings = new ArrayList(m_sr.m_alNoteStructures.Count);

              foreach( CNoteStructure ns in m_sr.m_alNoteStructures )
              {
            if( ns.Text != null && ns.Text.Length > 0 )
            {
              string sNoteText;
              if( MainForm.s_config.m_bObfuscateEmails )
              {
                sNoteText = ObfuscateEmail( ns.Text );
              }
              else
              {
                sNoteText = ns.Text;
              }

              string sourceRefs = "";
              alNoteStrings.Add( String.Concat("          <li>",EscapeHTML(sNoteText,false),sourceRefs,"</li>") );
            }
              }

              if( alNoteStrings.Count > 0 )
              {
            f.m_sw.WriteLine("        <div id=\"notes\">");
            f.m_sw.WriteLine("          <h1>Notes</h1>");
            f.m_sw.WriteLine("          <ul>");

            foreach( string note_string in alNoteStrings )
            {
              f.m_sw.WriteLine(note_string);
            }

            f.m_sw.WriteLine("          </ul>");
            f.m_sw.WriteLine("        </div> <!-- notes -->");
              }
            }

            if( MainForm.s_config.m_bSupressBackreferences == false )
            {
              if( m_sr.m_alBackreferences != null && m_sr.m_alBackreferences.Count > 0 )
              {
            f.m_sw.WriteLine("        <div id=\"citations\">" );
            f.m_sw.WriteLine("          <h1>Citations</h1>");
            f.m_sw.WriteLine("          <ul>");

            Hashtable htBackrefs = m_sr.MakeBackRefList();

            IDictionaryEnumerator enumerator = htBackrefs.GetEnumerator();
            while( enumerator.MoveNext() )
            {
              CIndividualRecord ir = (CIndividualRecord)(enumerator.Value);
              if( ir != null && !ir.Restricted )
              {
                string link = MakeLink(ir);
                if( link != "" )
                {
                  f.m_sw.WriteLine( String.Concat( "            <li>", link, "</li>" ) );
                }
              }
            }

            f.m_sw.WriteLine("          </ul>");
            f.m_sw.WriteLine("        </div> <!-- citations -->");

              }
            }

            f.m_sw.WriteLine("      </div> <!-- main -->");

            // Add footer (Record date, W3C sticker, GEDmill credit etc.)
            OutputFooter( f, m_sr );

            f.m_sw.WriteLine("    </div> <!-- page -->");
              }
              catch( IOException e )
              {
            LogFile.TheLogFile.WriteLine( LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught IO Exception(6) : " + e.ToString() );
              }
              catch( ArgumentException e )
              {
            LogFile.TheLogFile.WriteLine( LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught Argument Exception(6) : " + e.ToString() );
              }
              finally
              {
            if( f != null )
            {
              f.Close(); // Adds standard footer to the file
            }
              }
              return true;
        }
        // The main method that causes the front page to be created.
        public void Create()
        {
            string sPageDescription = "GEDmill GEDCOM to HTML family history website";
              string sKeywords = "family tree history " + MainForm.s_config.m_sOwnersName;
              string sTitle = MainForm.s_config.m_sTitle;

              CHTMLFile f = null;
              try
              {
            f = new CHTMLFile( MainForm.s_config.FrontPageURL, sTitle, sPageDescription, sKeywords ); // Creates a new file, and puts standard header html into it.
            f.m_sw.WriteLine("  <div id=\"page\"> <!-- page -->");
            f.m_sw.WriteLine("    <div id=\"cover\"> <!-- cover -->");

            f.m_sw.WriteLine(String.Concat("       <h1>", EscapeHTML(sTitle,false ), "</h1>"));

            if( MainForm.s_config.m_sFrontPageImageFilename != "" )
            {
              Rectangle newArea = new Rectangle( 0,0,0,0 );
              string pictureFile = CopyMultimedia( MainForm.s_config.m_sFrontPageImageFilename, "", 0, 0, ref newArea, null );
              if( pictureFile != null && pictureFile != "" )
              {
            f.m_sw.WriteLine(String.Concat("       <p><img src=\"" + pictureFile + "\" alt=\"Front page image\" /></p>"));
              }
            }

            if( MainForm.s_config.m_sCommentaryText!=null && MainForm.s_config.m_sCommentaryText!="" )
            {
              if( MainForm.s_config.m_bCommentaryIsHtml )
              {
            f.m_sw.WriteLine(String.Concat("       <p>", MainForm.s_config.m_sCommentaryText, "</p>" ));
              }
              else
              {
            f.m_sw.WriteLine(String.Concat("       <p>", EscapeHTML( MainForm.s_config.m_sCommentaryText, false ), "</p>" ));
              }
            }

            if( MainForm.s_config.m_bFrontPageStats )
            {
              string sIndividuals;
              if( m_stats.m_unIndividuals == 0 )
              {
            sIndividuals = "no";
              }
              else
              {
            sIndividuals = m_stats.m_unIndividuals.ToString();
              }
              sIndividuals += " individual";
              if( m_stats.m_unIndividuals != 1 )
              {
            sIndividuals += "s";
              }

              string sSources;
              if( m_stats.m_unSources == 0 )
              {
            sSources = "";
              }
              else
              {
            sSources = String.Concat(", cross-referenced to ", m_stats.m_unSources.ToString(), " source" );
              }
              if( m_stats.m_unSources > 1 )
              {
            sSources += "s";
              }

              string sMultimedia;
              string sFileType;
              if( m_stats.m_bNonPicturesIncluded )
              {
            sFileType = "multimedia file";
              }
              else
              {
            sFileType = "image";
              }
              if( m_stats.m_unMultimediaFiles == 0 )
              {
            sMultimedia = "";
              }
              else
              {
            sMultimedia = String.Concat(". There are links to ", m_stats.m_unMultimediaFiles.ToString(), " ", sFileType );
              }
              if( m_stats.m_unMultimediaFiles > 1 )
              {
            sMultimedia += "s";
              }

              f.m_sw.WriteLine(String.Concat("       <p>This website contains records on ",sIndividuals,sSources,sMultimedia, ".</p>" ));
            } // End front page stats

            f.m_sw.WriteLine("       <div id=\"links\"> <!-- links -->");
            f.m_sw.WriteLine(String.Concat("         <p><a href=\"individuals1.",MainForm.s_config.m_sHtmlExtension,"\">", MainForm.s_config.m_sIndexTitle, "</a></p>"));
            f.m_sw.WriteLine("       </div> <!-- links -->");
            if( MainForm.s_config.m_alKeyIndividuals != null && MainForm.s_config.m_alKeyIndividuals.Count > 0 )
            {
              // Although in theory you might want a restricted individual as a key individual, (they still form part of the tree), in practice this isn't allowed:
              ArrayList alCensoredKeyIndividuals = new ArrayList(MainForm.s_config.m_alKeyIndividuals.Count);

              foreach( string keyXref in MainForm.s_config.m_alKeyIndividuals )
              {
            CIndividualRecord air = m_gedcom.GetIndividualRecord( keyXref );
            if( air != null )
            {
              alCensoredKeyIndividuals.Add( MakeLink(air) );
            }
              }

              if( alCensoredKeyIndividuals.Count > 0 )
              {
            string plural = "";
            if( alCensoredKeyIndividuals.Count > 1 )
            {
              plural = "s";
            }
            f.m_sw.WriteLine( "         <div id=\"keyindividuals\">");
            f.m_sw.WriteLine(String.Concat("           <p>Key Individual",plural,":</p>"));
            f.m_sw.WriteLine( "           <ul>");
            foreach( string air_link in alCensoredKeyIndividuals )
            {
              f.m_sw.WriteLine( String.Concat("             <li>", air_link, "</li>") );
            }
            f.m_sw.WriteLine( "           </ul>");
            f.m_sw.WriteLine( "         </div> <!-- keyindividuals -->");
              }
            }

            string byEmail = "";
            // Email contact address
            if( MainForm.s_config.m_sUserEmailAddress != null && MainForm.s_config.m_sUserEmailAddress.Length > 0  )
            {
              byEmail = String.Concat(" by <a href=\"mailto:",MainForm.s_config.m_sUserEmailAddress,"\">",EscapeHTML(MainForm.s_config.m_sUserEmailAddress, false),"</a>" );
            }

            // Add brand and contact label
            f.m_sw.WriteLine(String.Concat("       <p>Website created",byEmail," using GEDmill.</p>"));
            // Add last update string
            if( MainForm.s_config.m_bAddHomePageCreateTime )
            {
              DateTime dt = DateTime.Now;
              string update_date_string = dt.ToString("dd MMMM yyyy", DateTimeFormatInfo.InvariantInfo);

              f.m_sw.WriteLine(String.Concat("       <p>Created on ",update_date_string,".</p>"));
            }

            // Add link to users main website
            if( MainForm.s_config.m_sMainWebsiteLink != "" )
            {
              f.m_sw.WriteLine( String.Concat("    <p><a href=\"", MainForm.s_config.m_sMainWebsiteLink, "\">Return to main site</a></p>") );
            }

            f.m_sw.WriteLine("    </div> <!-- cover -->");
            f.m_sw.WriteLine("  </div> <!-- page -->");
              }
              catch( IOException e )
              {
            LogFile.TheLogFile.WriteLine( LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught IO Exception(7) : " + e.ToString() );
              }
              catch( ArgumentException e )
              {
            LogFile.TheLogFile.WriteLine( LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught Argument Exception(7) : " + e.ToString() );
              }
              finally
              {
            if( f != null )
            {
              // Add standard footer to the file
              f.Close();
            }
              }
        }
        // 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();
            }
              }
        }
        // Creates a file and writes into it the HTML for the individual's page.
        private void OutputHTML( string title )
        {
            CHTMLFile f = null;
              string pageDescription = "GEDmill GEDCOM to HTML page for " + m_sName;
              string keywords = "family tree history " + m_sName;
              string relativeFilename = GetIndividualHTMLFilename(m_ir);
              string fullFilename = String.Concat(MainForm.s_config.m_sOutputFolder, "\\", relativeFilename);

              try
              {
            f = new CHTMLFile(fullFilename, title, pageDescription, keywords); // Creates a new file, and puts standard header html into it.

            if (f != null)
            {
              OutputPageHeader(f.m_sw, m_sPreviousChildLink, m_sNextChildLink, true, true);

              if (MainForm.s_config.m_bShowMiniTrees)
              {
            OutputMiniTree(f);
              }
              f.m_sw.WriteLine("    <div class=\"hr\" />");
              f.m_sw.WriteLine("");
              f.m_sw.WriteLine("    <div id=\"page\"> <!-- page -->");

              OutputMultimedia(f);

              f.m_sw.WriteLine("      <div id=\"main\">");

              f.m_sw.WriteLine("        <div id=\"summary\">");
              OutputNames(f);
              OutputIndividualSummary(f);
              f.m_sw.WriteLine("        </div> <!-- summary -->");

              if (!MainForm.s_config.m_bShowMiniTrees)
              {
            OutputParentNames(f);
              }

              if (!m_bConcealed)
              {
            m_alEventList.Sort();
            OutputEvents(f);

            OutputAttributes(f);
            OutputNotes(f);
            OutputSourceReferences(f);
              }

              f.m_sw.WriteLine("      </div> <!-- main -->");

              f.m_sw.WriteLine("");

              // Add footer (Record date, W3C sticker, GEDmill credit etc.)
              OutputFooter( f, m_ir );

              f.m_sw.WriteLine("    </div> <!-- page -->");
            }
              }
              catch (IOException e)
              {
            LogFile.TheLogFile.WriteLine(LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught IO Exception(4) : " + e.ToString());
              }
              catch (ArgumentException e)
              {
            LogFile.TheLogFile.WriteLine(LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught Argument Exception(4) : " + e.ToString());
              }
              finally
              {
            if (f != null)
            {
              // Close adds the standard footer to the file
              f.Close();
            }
              }
        }
        // The main method that causes the help page to be created.
        public void Create()
        {
            FileStream fsHelpSource = null;
              StreamReader srHelpSource = null;
              try
              {
            fsHelpSource = new FileStream( MainForm.s_config.m_sApplicationPath + "\\helpsource.html", FileMode.Open );
            srHelpSource = new StreamReader( fsHelpSource, System.Text.Encoding.UTF8 );
              }
              catch( IOException e )
              {
            LogFile.TheLogFile.WriteLine( LogFile.DT_HTML, LogFile.EDebugLevel.Error, String.Format("Caught io exception while loading help file source: {0}", e.ToString() ) );
            fsHelpSource = null;
            srHelpSource = null;
              }

              if( fsHelpSource != null && srHelpSource != null )
              {

            string sPageDescription = "GEDmill GEDCOM to HTML family history website";
            string sKeywords = "family tree history " + MainForm.s_config.m_sOwnersName;
            string sTitle = MainForm.s_config.m_sTitle;

            CHTMLFile f = null;
            try
            {
              // Create a new file and put standard header html into it.
              f = new CHTMLFile( MainForm.s_config.HelppageURL, sTitle, sPageDescription, sKeywords );

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

              f.m_sw.WriteLine("  <div id=\"page\"> <!-- page -->");

              // Copy in the help html source
              string sHelpLine;
              while( null!= (sHelpLine = srHelpSource.ReadLine()) )
              {
            f.m_sw.WriteLine( sHelpLine );
              }

              f.m_sw.WriteLine("  </div> <!-- page -->");
            }
            catch( IOException e )
            {
              LogFile.TheLogFile.WriteLine( LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught IO Exception : " + e.ToString() );
            }
            catch( ArgumentException e )
            {
              LogFile.TheLogFile.WriteLine( LogFile.DT_HTML, LogFile.EDebugLevel.Error, "Caught Argument Exception : " + e.ToString() );
            }
            finally
            {
              if( f != null )
              {
            // Add standard footer to the file
            f.Close();
              }
            }
              }
              if( srHelpSource != null )
              {
            srHelpSource.Close();
              }
              if( fsHelpSource != null )
              {
            fsHelpSource.Close();
              }
        }