context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using LamestWebserver.JScriptBuilder;
  using LamestWebserver.Core;
  
  namespace LamestWebserver.UI
  {
      public class HLinkSearchBox : HElement
      {
          public string Value = "";
          public string Placeholder = "";
          private readonly string _pageUrl;
          private readonly Func<SessionData, string, IEnumerable<Tuple<string, string>>> _func;
          public string ContainerID;
  
          public HLinkSearchBox(Func<SessionData, string, IEnumerable<Tuple<string, string>>> responseFunction, string responseUrl = null, string placeholder = null)
          {
              if (responseUrl == null)
                  responseUrl = SessionContainer.GenerateUnusedHash();
  
              _pageUrl = responseUrl;
              _func = responseFunction;
              ContainerID = responseUrl;
              Placeholder = placeholder;
  
              if (responseUrl != null)
                  InstantPageResponse.AddInstantPageResponse(_pageUrl, GetResponse);
          }
  
          /// <inheritdoc />
          public override string GetContent(SessionData sessionData)
          {
              var input = new JSInput(HInput.EInputType.text, Name, Value) { Class = Class, Style = Style, Title = Title };
  
              if (!string.IsNullOrWhiteSpace(Placeholder))
                  input.DescriptionTags = "placeholder='" + Placeholder + "' ";
  
              if (!string.IsNullOrWhiteSpace(ID))
                  input.ID = ID;
              else
                  input.ID = Hash.GetHash();
  
              var container = new HContainer() { ID = ContainerID, Style = "display:none;" };
              input.onclick = JSFunctionCall.DisplayElementByID(container.ID);
              input.onfocus = input.onclick;
              input.oninput = input.SetInnerHTMLWithNameValueAsync(JSElement.GetByID(container.ID), "/" + _pageUrl, JSFunctionCall.DisplayElementByID(container.ID));
              input.onfocusout = new JSIf(JSElement.GetByID(input.ID)["value"].IsEqualTo(new JSRawStringValue("")), JSFunctionCall.HideElementByID(container.ID));
  
              return input + container;
          }
  
          /// <summary>
          /// Retrieves the response-functions answer to the browser in a usable format.
          /// </summary>
          /// <param name="sessionData">the current sessionData</param>
          /// <returns>the responded message</returns>
          protected string GetResponse(SessionData sessionData)
          {
              string param = "";
  
              if (sessionData is HttpSessionData)
              {
                  param = sessionData.GetHttpHeadValue("value");
              }
  
              if (param == null)
                  param = "";
  
              var entries = _func(sessionData, param).ToArray();
  
              string ret = "";
  
              for (int i = 0; i < entries.Length; i++)
              {
                  ret += new HLink(entries[i].Item1, entries[i].Item2)
                  {
                      DescriptionTags = "onmousedown='" + new JScript(JSValue.CurrentBrowserURL.Set((JSStringValue)entries[i].Item2), JSElement.GetByID(ContainerID).Hide) + "'"
                  };
  
                  if (i + 1 < entries.Length)
                      ret += new HNewLine();
              }
  
              return ret;
          }
      }
  
      public class HSearchBox : HElement
      {
          public string Value = "";
          public string Placeholder = "";
          private readonly string _pageUrl;
          private readonly Func<SessionData, string, IEnumerable<string>> _func;
          public string ContainerID;
  
          public HSearchBox(Func<SessionData, string, IEnumerable<string>> responseFunction, string placeholder = null, string responseUrl = null)
          {
              if (responseUrl == null)
                  responseUrl = SessionContainer.GenerateUnusedHash();
  
              _pageUrl = responseUrl;
              _func = responseFunction;
              ContainerID = responseUrl;
              Placeholder = placeholder;
  
              if (responseUrl != null)
                  InstantPageResponse.AddInstantPageResponse(_pageUrl, GetResponse);
          }
  
          /// <inheritdoc />
          public override string GetContent(SessionData sessionData)
          {
              var input = new JSInput(HInput.EInputType.text, Name, Value) { Class = Class, Style = Style, Title = Title };
  
              if (!string.IsNullOrWhiteSpace(Placeholder))
                  input.DescriptionTags = "placeholder='" + Placeholder + "' ";
  
              if (!string.IsNullOrWhiteSpace(ID))
                  input.ID = ID;
              else
                  input.ID = Hash.GetHash();
  
              var container = new HContainer() { ID = ContainerID, Style = "display:none;" };
              input.onclick = JSFunctionCall.DisplayElementByID(container.ID);
              input.onfocus = input.onclick;
              input.oninput = input.SetInnerHTMLWithNameValueAsync(JSElement.GetByID(container.ID), "/" + _pageUrl, JSFunctionCall.DisplayElementByID(container.ID));
              input.onfocusout = new JSIf(JSElement.GetByID(input.ID)["value"].IsEqualTo(new JSRawStringValue("")), JSFunctionCall.HideElementByID(container.ID));
  
              return input + container;
          }
  
          /// <summary>
          /// Retrieves the response-functions answer to the browser in a usable format.
          /// </summary>
          /// <param name="sessionData">the current sessionData</param>
          /// <returns>the responded message</returns>
          protected string GetResponse(SessionData sessionData)
          {
              string param = "";
  
              if (sessionData is HttpSessionData)
              {
                  param = sessionData.GetHttpHeadValue("value");
              }
  
              if (param == null)
                  param = "";
  
              var entries = _func(sessionData, param).ToArray();
  
              string ret = "";
  
              for (int i = 0; i < entries.Length; i++)
              {
                  ret += new HText(entries[i]);
  
                  if (i + 1 < entries.Length)
                      ret += new HNewLine();
              }
  
              return ret;
          }
      }
  
      /// <summary>
      /// A button that cycles through multiple distinct states on click.
      /// </summary>
      public class HMultipleValuesButton : HElement
      {
          public string DescriptionTags = "";
  
          private List<Tuple<string, IEnumerable<HElement>>> Values;
          private string hiddenElementID = Hash.GetHash();
  
          private string _pageURL;
  
          public HMultipleValuesButton(string name)
          {
              Name = name;
              ID = Hash.GetHash();
              Values = new List<Tuple<string, IEnumerable<HElement>>>();
          }
  
          public HMultipleValuesButton(string name, params Tuple<string, string>[] values) : this(name)
          {
              foreach (Tuple<string, string> value in values)
              {
                  Values.Add(new Tuple<string, IEnumerable<HElement>>(value.Item1, new[] {(HElement) new HString(value.Item2)}));
              }
          }
  
          public HMultipleValuesButton(string name, params Tuple<string, HElement>[] values) : this(name)
          {
              foreach (Tuple<string, HElement> value in values)
              {
                  Values.Add(new Tuple<string, IEnumerable<HElement>>(value.Item1, new[] {value.Item2}));
              }
          }
  
          public HMultipleValuesButton(string name, params Tuple<string, IEnumerable<HElement>>[] values)
          {
              Name = name;
              ID = Hash.GetHash();
              Values = values.ToList();
          }
  
          public void AddValue(string value, string text)
          {
              Values.Add(new Tuple<string, IEnumerable<HElement>>(value, new[] {(HElement) new HString(text)}));
          }
  
          public void AddValue(string value, params HElement[] element)
          {
              Values.Add(new Tuple<string, IEnumerable<HElement>>(value, element));
          }
  
          public string GetCurrentValue(SessionData sessionData)
          {
              if (!(sessionData is HttpSessionData))
                  return null;
              else
                  return ((HttpSessionData) sessionData).GetHttpPostValue(Name);
          }
  
          /// <inheritdoc />
          public override string GetContent(SessionData sessionData)
          {
              if (Values == null || Values.Count == 0)
                  Logger.LogExcept(new ArgumentException($"No Values given to cycle through."));
  
              string defaultContents = "";
  
              foreach (var element in Values.First().Item2)
  
gt:                 defaultContents += element.GetContent(sessionData);