using System;
using System.Text;
using System.IO;
using System.Collections;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Web;
using System.Xml;

#pragma warning disable 0642


namespace miew.Html
{
	using String = System.String;

	public static class Extensions
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static string EncodeForPreTag(this String s)
		{
			return s.Replace("&", "&amp;").Replace("\"", "&quot;").EscapeGtLt();
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static unsafe String EscapeGtLt(this String s)
		{
			fixed (Char* pp = s)
			{
				Char* p_src = pp;
				Char* p_end = p_src + s.Length;
				while (p_src < p_end)
				{
					if (*p_src == '<' || *p_src == '>')
						goto first_esc;
					p_src++;
				}
				return s;

			first_esc:
				int ok_chars = (int)(p_src - pp);
				int c_ent = 1;

				while (p_src < p_end)
				{
					if (*p_src == '<' || *p_src == '>')
						c_ent++;
					p_src++;
				}
				p_src = pp + ok_chars;

				Char[] buf = new Char[s.Length + (c_ent * 4)];
				Marshal.Copy((IntPtr)pp, buf, 0, ok_chars);
				fixed (Char* _buf = buf)
				{
					Char* p_base = _buf;
					Char* p_dst = p_base + ok_chars;
					while (p_src < p_end)
					{
						/*if (ch==0x00A0)			// ok_TIS620==false because >7F
						{
							*p_dst++ = '&';
							*p_dst++ = 'n';
							*p_dst++ = 'b';
							*p_dst++ = 's';
							*p_dst++ = 'p';
							*p_dst++ = ';';
						}
						else */
						if (*p_src == '<')
						{
							*p_dst++ = '&';
							*p_dst++ = 'l';
							*p_dst++ = 't';
							*p_dst++ = ';';
						}
						else if (*p_src == '>')
						{
							*p_dst++ = '&';
							*p_dst++ = 'g';
							*p_dst++ = 't';
							*p_dst++ = ';';
						}
						else
							*p_dst++ = *p_src;
						p_src++;
					}
					return new String(p_base, 0, (int)(p_dst - p_base));
				}
			}
		}

#if false
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 
        /// </summary>
        ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static String GetTagContent(this String s, String tag)
		{
			Char ch;
			int j = s.IndexOf("<" + tag);
			if (j == -1 || ((ch = s[++j + tag.Length]) != '>' && ch != ' '))
				return String.Empty;

			int i_start = s.IndexOf('>', j);
			if (i_start == -1)
				return String.Empty;
			i_start++;

			if ((j = s.IndexOf("</" + tag + ">",i_start)) == -1)
				return String.Empty;

			return s.Substring(i_start,j - i_start);
		}
#endif

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static void Redirect302(this HttpResponse r, String location)
		{
			r.BufferOutput = true;			// to capture the HTML body and enable non-chunked transfer-encoding...
			r.Redirect(location, false);	// that this generates... (btw don't generate ThreadAborts)
			r.ClearContent();				// and discard it
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static String CleanForFormValue(this String s)
		{
			if (String.IsNullOrEmpty(s))
				return String.Empty;
			return new String(s.Where(e => e != '\"' && e != '<' && e != '>').ToArray());
		}


		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static String StripTrimStraightenLowerCondense(this String s, HashSet<Char> strip)
		{
			Char[] buf = s.ToCharArray();

			bool f_condensing = false;
			bool f_started = false;
			int j = 0;
			int idx;
			for (int i = 0; i < buf.Length; i++)
			{
				Char ch = buf[i];

				if (ch == '‘' || ch == '’')
					ch = '\'';
				else if (ch == '“' || ch == '”')
					ch = '\"';
				if (ch == '&' && i + 3 < buf.Length && buf[i + 2] == 't' && buf[i + 3] == ';')
				{
					ch = (buf[i + 1] == 'l') ? '<' : '>';
					i += 3;
				}

				if (ch == '\x200b')
					;
				else if (Char.IsWhiteSpace(ch) || strip.Contains(ch) ||
					((ch == ',' || ch == ':') && i > 0 && !Char.IsNumber(buf[i - 1])))
					f_condensing = f_started;
				else if (ch == '<' && ((idx = s.IndexOf('>', i + 1)) != -1))
				{
					if (s.Substring(i + 1, 2) == "br")
						f_condensing = f_started;
					i = idx;
				}
				else
				{
					if (f_condensing)
					{
						buf[j++] = ' ';
						f_condensing = false;
					}
					buf[j++] = Char.ToLower(ch);
					f_started = true;
				}
			}
			return new String(buf, 0, j);
		}


	};


}


namespace glue.Xml
{
	public static class Extensions
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static void AddAttribute(this XmlElement e, XmlDocument xmldoc, String attr, String value)
		{
			XmlAttribute a = xmldoc.CreateAttribute(attr);
			a.Value = value;
			e.Attributes.Append(a);
		}

#if false
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static string EncodeForXml(this String s)
		{
			StringBuilder sb = new StringBuilder(s);

			sb = sb.Replace("&", "&amp;");		// obviously, must be the first one
			sb = sb.Replace("<", "&lt;");
			sb = sb.Replace(">", "&gt;");
			sb = sb.Replace("'", "&apos;");
			sb = sb.Replace("\"", "&quot;");

			return sb.ToString();
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static String GetXPathText(this XmlDocument xd, String xpath)
		{
			XmlNode xn = xd.SelectSingleNode(xpath);
			return (xn == null) ? String.Empty : xn.InnerXml.Trim();
		}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		public static String TryGetAttribute(this XmlElement e, String attr)
		{
			XmlAttribute a = e.Attributes[attr];
			if (a == null)
				return null;
			return a.InnerText;
		}
#endif
	}

}