<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using Bloom.ToPalaso.Experimental;
using Bloom.Api;
using Bloom.Book;
using Newtonsoft.Json.Linq;
using SIL.Code;
using SIL.Extensions;
using Gecko;
using Gecko.WebIDL;
using Newtonsoft.Json;
using SIL.IO;
using SIL.Reporting;
using SIL.Xml;
using File = System.IO.File;

namespace Bloom.Edit
{
	/// <summary>
	/// Manages configuration UI and settings for templates that contain setup scripts
	/// </summary>
	public class Configurator
	{
		private readonly string _folderInWhichToReadAndSaveCollectionSettings;
		private readonly NavigationIsolator _isolator;
		public delegate Configurator Factory(string folderInWhichToReadAndSaveCollectionSettings);//autofac uses this

		public Configurator(string folderInWhichToReadAndSaveCollectionSettings, NavigationIsolator isolator)
		{
			_folderInWhichToReadAndSaveCollectionSettings = folderInWhichToReadAndSaveCollectionSettings;
			_isolator = isolator;
			PathToCollectionJson = _folderInWhichToReadAndSaveCollectionSettings.CombineForPath("configuration.txt");
			RequireThat.Directory(folderInWhichToReadAndSaveCollectionSettings).Exists();
			LocalData = string.Empty;
		}

		public static bool IsConfigurable(string folderPath)
		{
			//enhance: would make sense to just work with books, but setting up books in tests is currently painful.
			//When we make a class to make that easy, we should switch this.
			//BookStorage storage = new BookStorage(folderPath, null);
			//return (null != FindConfigurationPage(dom));

			return RobustFile.Exists(Path.Combine(folderPath, "configuration.html"));
		}

		public DialogResult ShowConfigurationDialog(string folderPath)
		{
			using (var dlg = new ConfigurationDialog(Path.Combine(folderPath, "configuration.html"), GetCollectionData(), _isolator))
			{
				var result = dlg.ShowDialog(null);
				if (result == DialogResult.OK)
				{
					CollectJsonData(dlg.FormData);
				}
				return result;
			}
		}

		/// <summary>
		/// Before calling this, ConfigurationData has to be loaded. E.g., by running ShowConfigurationDialog()
		/// </summary>
		/// <param name="bookPath"></param>
		public void ConfigureBook(string bookPath)
		{
			using (var dlg = new ProgressDialogForeground())
			{
				dlg.Text = L10NSharp.LocalizationManager.GetString("CollectionTab.ConfiguringBookMessage", "Building...");
				dlg.ShowAndDoWork((progress) => ConfigureBookInternal(bookPath));
			}
		}

		public static void AddScriptFile(XmlDocument doc, string src)
		{
			var head = doc.SelectSingleNode("//head") as XmlElement;
			if (head.SelectSingleNode($"./script[@type='text/javascript' and @src='{src}']") != null)
				return; // already have it
			var script = doc.CreateElement("script");
			script.SetAttribute("src", src);
			script.SetAttribute("type", "text/javascript");
			head.AppendChild(script);
		}
		public static void AddScriptText(XmlDocument doc, string id, string text)
		{
			var head = doc.SelectSingleNode("//head") as XmlElement;
			var script = head.SelectSingleNode($"./script[@type='text/javascript' and @id='{id}']") as XmlElement;
			if (script == null)
			{
				script = doc.CreateElement("script");
				script.SetAttribute("type", "text/javascript");
				script.SetAttribute("id", id);
				head.AppendChild(script);
			}
			script.InnerText = text;
		}

		/// <summary>
		/// Passed the contents of the configuration.html file in the book's folder
		/// (typically copied from the template from which it was made)
		/// and the configuration.txt file in the parent collection, this yields an
		/// updated configuration.html content ready to use as the source of the
		/// ConfigurationDialog.
		/// </summary>
		/// <param name="html"></param>
		/// <param name="settings"></param>
		/// <returns></returns>
		public static string SetupConfigurationHtml(string html, string settings)
		{
			var doc = XmlHtmlConverter.GetXmlDomFromHtml(html);
			AddScriptFile(doc, "jquery-1.10.1.js");
			AddScriptFile(doc, "form2object.js");
			AddScriptFile(doc, "js2form.js");
			AddScriptFile(doc, "underscore.js");
			AddScriptText(doc, "configuredScript",
				@"function gatherSettings()
					{
						var formData = form2object('form', '.', false, null);
						return JSON.stringify(formData, null, '\t');
					}
				function preloadSettings()
					{
						 x =  " + settings + @";
						var $inputs = $('#form').find('[name]');
						populateForm($inputs, x, 'name');
					}
				window.addEventListener('load', preloadSettings)");
			return XmlHtmlConverter.ConvertElementToHtml5(doc.DocumentElement);
		}

		private void ConfigureBookInternal(string bookPath)<commit_msg>Fix HTML conversion for wall calendar configuration (BL-11529)<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using Bloom.ToPalaso.Experimental;
using Bloom.Api;
using Bloom.Book;
using Newtonsoft.Json.Linq;
using SIL.Code;
using SIL.Extensions;
using Gecko;
using Gecko.WebIDL;
using Newtonsoft.Json;
using SIL.IO;
using SIL.Reporting;
using SIL.Xml;
using File = System.IO.File;

namespace Bloom.Edit
{
	/// <summary>
	/// Manages configuration UI and settings for templates that contain setup scripts
	/// </summary>
	public class Configurator
	{
		private readonly string _folderInWhichToReadAndSaveCollectionSettings;
		private readonly NavigationIsolator _isolator;
		public delegate Configurator Factory(string folderInWhichToReadAndSaveCollectionSettings);//autofac uses this

		public Configurator(string folderInWhichToReadAndSaveCollectionSettings, NavigationIsolator isolator)
		{
			_folderInWhichToReadAndSaveCollectionSettings = folderInWhichToReadAndSaveCollectionSettings;
			_isolator = isolator;
			PathToCollectionJson = _folderInWhichToReadAndSaveCollectionSettings.CombineForPath("configuration.txt");
			RequireThat.Directory(folderInWhichToReadAndSaveCollectionSettings).Exists();
			LocalData = string.Empty;
		}

		public static bool IsConfigurable(string folderPath)
		{
			//enhance: would make sense to just work with books, but setting up books in tests is currently painful.
			//When we make a class to make that easy, we should switch this.
			//BookStorage storage = new BookStorage(folderPath, null);
			//return (null != FindConfigurationPage(dom));

			return RobustFile.Exists(Path.Combine(folderPath, "configuration.html"));
		}

		public DialogResult ShowConfigurationDialog(string folderPath)
		{
			using (var dlg = new ConfigurationDialog(Path.Combine(folderPath, "configuration.html"), GetCollectionData(), _isolator))
			{
				var result = dlg.ShowDialog(null);
				if (result == DialogResult.OK)
				{
					CollectJsonData(dlg.FormData);
				}
				return result;
			}
		}

		/// <summary>
		/// Before calling this, ConfigurationData has to be loaded. E.g., by running ShowConfigurationDialog()
		/// </summary>
		/// <param name="bookPath"></param>
		public void ConfigureBook(string bookPath)
		{
			using (var dlg = new ProgressDialogForeground())
			{
				dlg.Text = L10NSharp.LocalizationManager.GetString("CollectionTab.ConfiguringBookMessage", "Building...");
				dlg.ShowAndDoWork((progress) => ConfigureBookInternal(bookPath));
			}
		}

		public static void AddScriptFile(XmlDocument doc, string src)
		{
			var head = doc.SelectSingleNode("//head") as XmlElement;
			if (head.SelectSingleNode($"./script[@type='text/javascript' and @src='{src}']") != null)
				return; // already have it
			var script = doc.CreateElement("script");
			script.SetAttribute("src", src);
			script.SetAttribute("type", "text/javascript");
			head.AppendChild(script);
		}
		public static void AddScriptText(XmlDocument doc, string id, string text)
		{
			var head = doc.SelectSingleNode("//head") as XmlElement;
			var script = head.SelectSingleNode($"./script[@type='text/javascript' and @id='{id}']") as XmlElement;
			if (script == null)
			{
				script = doc.CreateElement("script");
				script.SetAttribute("type", "text/javascript");
				script.SetAttribute("id", id);
				head.AppendChild(script);
			}
			script.InnerText = text;
		}

		/// <summary>
		/// Passed the contents of the configuration.html file in the book's folder
		/// (typically copied from the template from which it was made)
		/// and the configuration.txt file in the parent collection, this yields an
		/// updated configuration.html content ready to use as the source of the
		/// ConfigurationDialog.
		/// </summary>
		/// <param name="html"></param>
		/// <param name="settings"></param>
		/// <returns></returns>
		public static string SetupConfigurationHtml(string html, string settings)
		{
			var doc = XmlHtmlConverter.GetXmlDomFromHtml(html);
			AddScriptFile(doc, "jquery-1.10.1.js");
			AddScriptFile(doc, "form2object.js");
			AddScriptFile(doc, "js2form.js");
			AddScriptFile(doc, "underscore.js");
			AddScriptText(doc, "configuredScript",
				@"function gatherSettings()
					{
						var formData = form2object('form', '.', false, null);
						return JSON.stringify(formData, null, '\t');
					}
				function preloadSettings()
					{
						 x =  " + settings + @";
						var $inputs = $('#form').find('[name]');
						populateForm($inputs, x, 'name');
					}
				window.addEventListener('load', preloadSettings)");
			return XmlHtmlConverter.ConvertDomToHtml5(doc);
		}

		private void ConfigureBookInternal(string bookPath)
{'fraction_non_alphanumeric': 0.12204600357105345, 'fraction_numerical': 0.0026257746035080348, 'mean_word_length': 4.260773480662984, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3202553', 'n_tokens_mistral': 3195, 'n_tokens_neox': 2739, 'n_words': 702}