<commit_before>using System;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using Bloom.Api;
using Newtonsoft.Json;

namespace Bloom.Edit
{
	/// <summary>
	/// Handles api request dealing with the page manipulation controls at the bottom of the WebThumbnailList
	/// (left side of Edit tab screen).
	/// </summary>
	public class PageControlsApi
	{
		private const string kApiUrlPart = "edit/pageControls/";
		private const string kWebsocketStateId = "edit/pageControls/state";
		private readonly BloomWebSocketServer _webSocketServer;
		private readonly EditingModel _editingModel;
		private DateTime _lastButtonClickedTime = DateTime.Now; // initially, instance creation time

		public PageControlsApi(EditingModel model)
		{
			_editingModel = model;
			_webSocketServer = _editingModel.EditModelSocketServer;
			_editingModel.PageSelectModelChangesComplete += PageSelectModelChangesCompleteHandler;
		}

		private void PageSelectModelChangesCompleteHandler(object sender, EventArgs e)
		{
			UpdateState(); // tell React model that the C# state changed
		}


		// kick off an operation that typically will refresh the current page.
		// We want to post success BEFORE we proceed with an operation that will unload the page that sent
		// the request, otherwise, we tend to get spurious error messages, depending on just how unloaded
		// the page is by the time the post success message arrives.
		// Most of these operations also need to happen on the UI thread, so the BeginInvoke
		// serves a double purpose by achieving that and delaying the action.
		// Note that we never try to call EndInvoke. This is OK for control.BeingInvoke;
		// any unhandled exceptions will be sent to the unhandled event hander eventually.
		void ClaimSuccessThenDo(ApiRequest request, Action doSomething)
		{
			request.PostSucceeded();
			if (Program.RunningUnitTests)
			{
				doSomething();
				return;
			}

			var syncForm = Application.OpenForms.Cast<Form>().Last();
			if (syncForm != null)
			{
				syncForm.BeginInvoke(doSomething);
				return;
			}
			// strange situation...maybe we can still do it?
			doSomething();
		}

		public void RegisterWithServer(EnhancedImageServer server)
		{
			server.RegisterEndpointHandler(kApiUrlPart + "requestState", request =>
			{
				if (request.HttpMethod == HttpMethods.Get)
				{
					request.ReplyWithJson(CurrentStateString);
				}
				else // post
				{
					Debug.Fail("We shouldn't ever be using the 'post' version.");
					request.PostSucceeded();
				}
			}, true);

			server.RegisterEndpointHandler(kApiUrlPart + "addPage", request =>
			{
				ClaimSuccessThenDo(request, () => AddPageButton_Click());
			}, false);

			server.RegisterEndpointHandler(kApiUrlPart + "duplicatePage", request =>
			{
				ClaimSuccessThenDo(request, () =>_editingModel.OnDuplicatePage());
			}, false);

			server.RegisterEndpointHandler(kApiUrlPart + "deletePage", request =>
			{
				ClaimSuccessThenDo(request, () =>
				{
					if (ConfirmRemovePageDialog.Confirm())
						_editingModel.OnDeletePage();
				});
			}, false);

			server.RegisterEndpointHandler(kApiUrlPart + "lockBook", request =>
			{
				_editingModel.SaveNow(); // BL-5421 lock and unlock lose typing
				_editingModel.CurrentBook.TemporarilyUnlocked = false;<commit_msg>Revert "BL-6100 return success code before refreshing page"<commit_after>using System;
using System.Diagnostics;
using System.Windows.Forms;
using Bloom.Api;
using Newtonsoft.Json;

namespace Bloom.Edit
{
	/// <summary>
	/// Handles api request dealing with the page manipulation controls at the bottom of the WebThumbnailList
	/// (left side of Edit tab screen).
	/// </summary>
	public class PageControlsApi
	{
		private const string kApiUrlPart = "edit/pageControls/";
		private const string kWebsocketStateId = "edit/pageControls/state";
		private readonly BloomWebSocketServer _webSocketServer;
		private readonly EditingModel _editingModel;
		private DateTime _lastButtonClickedTime = DateTime.Now; // initially, instance creation time

		public PageControlsApi(EditingModel model)
		{
			_editingModel = model;
			_webSocketServer = _editingModel.EditModelSocketServer;
			_editingModel.PageSelectModelChangesComplete += PageSelectModelChangesCompleteHandler;
		}

		private void PageSelectModelChangesCompleteHandler(object sender, EventArgs e)
		{
			UpdateState(); // tell React model that the C# state changed
		}

		public void RegisterWithServer(EnhancedImageServer server)
		{
			server.RegisterEndpointHandler(kApiUrlPart + "requestState", request =>
			{
				if (request.HttpMethod == HttpMethods.Get)
				{
					request.ReplyWithJson(CurrentStateString);
				}
				else // post
				{
					Debug.Fail("We shouldn't ever be using the 'post' version.");
					request.PostSucceeded();
				}
			}, true);

			server.RegisterEndpointHandler(kApiUrlPart + "addPage", request =>
			{
				AddPageButton_Click();
				request.PostSucceeded();
			}, true);

			server.RegisterEndpointHandler(kApiUrlPart + "duplicatePage", request =>
			{
				_editingModel.OnDuplicatePage();
				request.PostSucceeded();
			}, true);

			server.RegisterEndpointHandler(kApiUrlPart + "deletePage", request =>
			{
				if (ConfirmRemovePageDialog.Confirm())
					_editingModel.OnDeletePage();
				request.PostSucceeded();
			}, true);

			server.RegisterEndpointHandler(kApiUrlPart + "lockBook", request =>
			{
				_editingModel.SaveNow(); // BL-5421 lock and unlock lose typing
				_editingModel.CurrentBook.TemporarilyUnlocked = false;
{'fraction_non_alphanumeric': 0.09398768562115176, 'fraction_numerical': 0.0021731256791017745, 'mean_word_length': 4.025477707006369, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 21, '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': '5378798', 'n_tokens_mistral': 1827, 'n_tokens_neox': 1534, 'n_words': 426}