/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Saves the sty file.
		/// </summary>
		/// <param name="LangProjectName">Name of the language project.</param>
		/// <param name="writer">The writer.</param>
		/// <param name="ws">The HVO of the writing system for the current export.</param>
		/// ------------------------------------------------------------------------------------
		public void SaveStyFile(string LangProjectName, FileWriter writer, int ws)
		{
			ConnectStyles();

			writer.WriteLine("## Stylesheet for exported TE project " + LangProjectName + " ##");
			writer.WriteLine(string.Empty, true);

			// Write out the style sheet entries
			foreach (UsfmStyEntry entry in Values)
			{
				entry.Serialize(ws, writer);
				writer.WriteLine(string.Empty, true);
			}
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Serializes this object to the specified writer.
		/// </summary>
		/// <param name="ws">HVO of the writing system whose properties should be used for
		/// figuring out which set of font properties to use (FW allows for overrides based on
		/// WS).
		/// </param>
		/// <param name="writer">The writer.</param>
		/// ------------------------------------------------------------------------------------
		internal void Serialize(int ws, FileWriter writer)
		{
			writer.WriteLine(@"\Marker " + P6Marker);
			if (m_name != null)
				writer.WriteLine(@"\TEStyleName " + m_name);
			if (Endmarker != null)
				writer.WriteLine(@"\Endmarker " + Endmarker);
			writer.WriteLine(@"\Name " + (P6Name == null ? m_name : P6Name));
			if (m_usage != null)
				writer.WriteLine(@"\Description " + m_usage);
			if (OccursUnder != null)
				writer.WriteLine(@"\OccursUnder " + OccursUnder);
			if (Rank > 0)
				writer.WriteLine(@"\Rank " + Rank);
			if (NotRepeatable)
				writer.WriteLine(@"\NotRepeatable");
			writer.WriteLine(@"\TextType " + TextType);
			writer.WriteLine(@"\TextProperties " + TextProperties);
			writer.WriteLine(@"\StyleType " + StyleType);

			FontInfo fontInfo = FontInfoForWs(ws);
			if (fontInfo.m_italic.ValueIsSet && fontInfo.m_italic.Value)
				writer.WriteLine(@"\Italic");
			if (fontInfo.m_underline.ValueIsSet && fontInfo.m_underline.Value != FwUnderlineType.kuntNone)
				writer.WriteLine(@"\Underline");
			if (fontInfo.m_bold.ValueIsSet && fontInfo.m_bold.Value)
				writer.WriteLine(@"\Bold");
			if (fontInfo.m_superSub.ValueIsSet && fontInfo.m_superSub.Value == FwSuperscriptVal.kssvSuper)
				writer.WriteLine(@"\Superscript");
			if (!fontInfo.m_fontName.IsInherited) // TODO (TE-5185): This isn't good enough - if a char style inherits from another char style that sets a specific font, the derived char style also needs to output that font spec in the sty file because the sty file doesn't handle inheritance.
				writer.WriteLine(@"\FontName " + RealFontNameForWs(ws));
			// Write out the font size, converting it from millipoints to points
			if (fontInfo.m_fontSize.ValueIsSet)
				writer.WriteLine(@"\FontSize " + fontInfo.m_fontSize.Value / 1000);
			if (fontInfo.m_fontColor.ValueIsSet && fontInfo.m_fontColor.Value != Color.Black)
				writer.WriteLine(@"\Color " + ColorUtil.ConvertColorToBGR(fontInfo.m_fontColor.Value));

			if (m_alignment.ValueIsSet)
			{
				switch (m_alignment.Value)
				{
					case FwTextAlign.ktalCenter:
						writer.WriteLine(@"\Justification Center");
						break;
					case FwTextAlign.ktalLeading:
						break;
					case FwTextAlign.ktalJustify:
						writer.WriteLine(@"\Justification Both");
						break;
					case FwTextAlign.ktalTrailing:
						writer.WriteLine(@"\Justification Right"); // "right" really means "trailing" in Paratext
						break;
					case FwTextAlign.ktalLeft:
						if (m_rtl.Value == TriStateBool.triTrue)
							writer.WriteLine(@"\Justification Right"); // "right" really means "trailing" in Paratext
						break;
					case FwTextAlign.ktalRight:
						if (m_rtl.Value != TriStateBool.triTrue)
							writer.WriteLine(@"\Justification Right"); // "right" really means "trailing" in Paratext
						break;
				}
			}

			if (m_firstLineIndent.ValueIsSet && m_firstLineIndent.Value > 0)
				writer.WriteLine(@"\FirstLineIndent " + (((double)m_firstLineIndent.Value)/72000).ToString("#.000"));
			if (m_leadingIndent.ValueIsSet && m_leadingIndent.Value > 0)
				writer.WriteLine(@"\LeftMargin " + (((double)m_leadingIndent.Value)/72000).ToString("#.000"));
			if (m_trailingIndent.ValueIsSet && m_trailingIndent.Value > 0)
				writer.WriteLine(@"\RightMargin " + (((double)m_trailingIndent.Value)/72000).ToString("#.000"));
			if (m_spaceBefore.ValueIsSet && m_spaceBefore.Value > 0)
				writer.WriteLine(@"\SpaceBefore " + m_spaceBefore.Value / 1000); // convert from millipoints to points
			if (m_spaceAfter.ValueIsSet && m_spaceAfter.Value > 0)
				writer.WriteLine(@"\SpaceAfter " + m_spaceAfter.Value / 1000); // convert from millipoints to points

			if (XmlTag != null)
				writer.WriteLine(@"\XMLTag " + XmlTag);
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Saves the ssf file.
		/// </summary>
		/// <param name="format">the prefix, scheme, suffix, extension</param>
		/// <param name="sShortName">The short name of the Paratext project</param>
		/// <param name="styleSheetFile">The style sheet file.</param>
		/// <param name="projPath">The path where the project is located</param>
		/// <param name="writer">The file writer.</param>
		/// <param name="ws">The HVO of the writing system for the current export.</param>
		/// ------------------------------------------------------------------------------------
		public void SaveSsfFile(FileNameFormat format, string sShortName, string styleSheetFile,
			string projPath, FileWriter writer, int ws)
		{
			ComputeSettings(format, projPath, ws);
			writer.WriteLine("<ScriptureText>");
			writer.WriteLine("<BooksPresent>" + BooksPresent + "</BooksPresent>");
			writer.WriteLine("<Copyright></Copyright>");
			writer.WriteLine("<Directory>" + m_projPath + "</Directory>");
			writer.WriteLine("<Editable>T</Editable>");
			writer.WriteLine("<Encoding>" + kUnicodeEncoding + "</Encoding>");
			writer.WriteLine("<FileNameForm>" + m_fileScheme + "</FileNameForm>");
			writer.WriteLine("<FileNamePostPart>" + m_sPostPart + "</FileNamePostPart>");
			writer.WriteLine("<FileNamePrePart>" + m_sPrePart + "</FileNamePrePart>");
			writer.WriteLine("<FullName>" + m_cache.ProjectId.Name + "</FullName>");
			writer.WriteLine("<Language>" + m_wsName + "</Language>");
			writer.WriteLine("<LeftToRight>" + m_LtoR + "</LeftToRight>");
			writer.WriteLine("<Name>" + sShortName + "</Name>");
			writer.WriteLine("<StyleSheet>" + styleSheetFile + "</StyleSheet>");
			writer.WriteLine("<Versification>" + m_versification + "</Versification>");
			writer.WriteLine(NamingNode);
			writer.WriteLine("</ScriptureText>");
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// writes the contents of the LDS file.
		/// </summary>
		/// <param name="ldsFileName">name of the Paratext LDS to be saved.</param>
		/// <param name="normalStyle">The normal style.</param>
		/// <param name="ws">The HVO of the writing system for the current export.</param>
		/// <param name="fileWriterLds">file writer for the Paratext LDS file</param>
		/// ------------------------------------------------------------------------------------
		private void WriteLdsFileContents(string ldsFileName, UsfmStyEntry normalStyle, int ws,
			FileWriter fileWriterLds)
		{
			Debug.Assert(fileWriterLds != null);
			fileWriterLds.Open(ldsFileName);

			ComputeSettings(normalStyle, ws);

			fileWriterLds.WriteLine("[General]");
			fileWriterLds.WriteLine("codepage=65001");
			fileWriterLds.WriteLine("RTL=" + m_RtoL);
			fileWriterLds.WriteLine("font=" + m_fontName);
			fileWriterLds.WriteLine("name=" + m_wsName);
			fileWriterLds.WriteLine("size=" + m_fontSize);
			fileWriterLds.WriteLine(string.Empty, true);
			fileWriterLds.WriteLine("[Checking]");
			fileWriterLds.WriteLine(string.Empty, true);
			fileWriterLds.WriteLine("[Characters]");
			fileWriterLds.WriteLine(string.Empty, true);
			fileWriterLds.WriteLine("[Punctuation]");
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Writes the contents of the general section.
		/// </summary>
		/// <param name="writer">The writer.</param>
		/// <param name="fHasCodePage">Indicates whether code page entry has been written.</param>
		/// <param name="fHasFont">Indicates whether font entry has been written.</param>
		/// <param name="fHasFontSize">Indicates whether font size entry has been written.</param>
		/// <param name="fHasName">Indicates whether name entry has been written.</param>
		/// <param name="fHasRTL">Indicates whether RTL entry has been written.</param>
		/// ------------------------------------------------------------------------------------
		private void WriteGeneralSection(FileWriter writer, ref bool fHasCodePage,
			ref bool fHasFont, ref bool fHasFontSize, ref bool fHasName, ref bool fHasRTL)
		{
			if (!fHasCodePage)
			{
				writer.WriteLine("codepage=65001");
				fHasCodePage = true;
			}
			if (!fHasFont)
			{
				writer.WriteLine("font=" + m_fontName);
				fHasFont = true;
			}
			if (!fHasFontSize)
			{
				writer.WriteLine("size=" + m_fontSize);
				fHasFontSize = true;
			}
			if (!fHasName)
			{
				writer.WriteLine("name=" + m_wsName);
				fHasName = true;
			}
			if (!fHasRTL)
			{
				writer.WriteLine("RTL=" + m_RtoL);
				fHasRTL = true;
			}
		}
		/// ------------------------------------------------------------------------------------
		/// <summary>
		/// Updates the lds file which describes the writing system in Paratext.
		/// </summary>
		/// <param name="ldsContents">Contents of the existing LDS file.</param>
		/// <param name="normalStyle">The normal style.</param>
		/// <param name="ws">The writing system</param>
		/// <param name="writer">The file writer for the Paratext LDS file</param>
		/// ------------------------------------------------------------------------------------
		public void UpdateLdsContents(string ldsContents, UsfmStyEntry normalStyle,
			int ws, FileWriter writer)
		{
			ComputeSettings(normalStyle, ws);

			string [] lines = ldsContents.Split(new string[] { Environment.NewLine },
				StringSplitOptions.RemoveEmptyEntries);

			// Read lines of text from the file, updating it as necessary.
			bool fInGeneralSection = false;
			bool fInOtherSection = false;
			bool fHasGeneralSection = false;
			bool fHasCodePage = false;
			bool fHasFont = false;
			bool fHasFontSize = false;
			bool fHasName = false;
			bool fHasRTL = false;
			foreach (string line in lines)
			{
				if (line.StartsWith("[General]"))
				{
					if (fInOtherSection)
					{
						fInOtherSection = false;
						writer.WriteLine();
					}
					fInGeneralSection = true;
					fHasGeneralSection = true;
				}
				else if (line.StartsWith("["))
				{
					if (fInGeneralSection)
					{
						WriteGeneralSection(writer, ref fHasCodePage, ref fHasFont,
							ref fHasFontSize, ref fHasName, ref fHasRTL);

						fInGeneralSection = false;
						writer.WriteLine();
					}
					else if (fInOtherSection)
						writer.WriteLine();

					fInOtherSection = true;
				}

				if (fInGeneralSection)
				{
					string replaceString = string.Empty;

					// Check line for fields that must be updated
					if (line.StartsWith("codepage="))
					{
						replaceString = "codepage=65001";
						fHasCodePage = true;
					}
					else if (line.StartsWith("font="))
					{
						replaceString = "font=" + m_fontName;
						fHasFont = true;
					}
					else if (line.StartsWith("size="))
					{
						replaceString = "size=" + m_fontSize;
						fHasFontSize = true;
					}
					else if (line.StartsWith("name="))
					{
						replaceString = "name=" + m_wsName;
						fHasName = true;
					}
					else if (line.StartsWith("RTL="))
					{
						replaceString = "RTL=" + m_RtoL;
						fHasRTL = true;
					}
					if (replaceString != string.Empty)
						writer.WriteLine(replaceString); // Add updated line to file contents list
					else
						writer.WriteLine(line); // Add line, without changes, to file contents list
				}
				else
					writer.WriteLine(line);
			}

			if (!fHasGeneralSection)
			{
				if (fInOtherSection)
				{
					fInOtherSection = false;
					writer.WriteLine();
				}
				// General section not found. Write it.
				writer.WriteLine("[General]");
			}
			WriteGeneralSection(writer, ref fHasCodePage, ref fHasFont, ref fHasFontSize,
				ref fHasName, ref fHasRTL);
		}