using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using ryCommon;
namespace RyWeb
{
    /// <summary>
    /// Http服务器类
    /// </summary>
    public class HttpServer
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void HttpRequestHandler(object sender, HttpRequest e);
        /// <summary>
        /// 当收到Get事件时激发
        /// </summary>
        [Description("当收到Get事件时激发")]
        public event HttpRequestHandler OnHandleGETRequest;
        /// <summary>
        /// 当收到Post事件时激发
        /// </summary>
        [Description("当收到Post事件时激发")]
        public event HttpRequestHandler OnHandlePOSTRequest;
        private HttpListener listener;
        private Thread httpThread;
        private volatile bool stopped = false;
        /// <summary>
        /// 监听的主机,默认是localhost
        /// </summary>
        public string ListenerHost { get; set; } = "localhost";
        private int port = 19955;
        /// <summary>
        /// 最后一次错误信息
        /// </summary>
        public string ErrorMessage { get;internal set; } = "";
        /// <summary>
        /// 在此端口建立Http服务类
        /// </summary>
        /// <param name="port">端口号</param>
        public HttpServer(int port)
        {
            isrunning = false;
            stopped = false;
            try
            {
                listener = new HttpListener();
                this.port= port;
                listener.Prefixes.Add("http://"+ ListenerHost + ":" + port + "/");
                listener.Prefixes.Add("http://127.0.0.1:" + port + "/");
                //listener.Prefixes.Add(HTTPS_PREFIX + HTTPS_PORT + "/");
                listener.Start();
                httpThread = new Thread(new ThreadStart(Run));
                httpThread.Start();
                isrunning = true;
            }
            catch(Exception ex) { ErrorMessage = ex.Message; }
        }
        private bool isrunning = false;
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool IsRunning()
        {
            return isrunning;
        }
        /// <summary>
        /// 开始服务
        /// </summary>
        public void Start()
        {
            isrunning = false;
            stopped = false;
            try
            {
                if (listener == null || !listener.IsListening)
                {
                    listener = new HttpListener();
                    listener.Prefixes.Add("http://"+ ListenerHost + ":" + port + "/");
                    listener.Prefixes.Add("http://127.0.0.1:" + port + "/");
                    //listener.Prefixes.Add(HTTPS_PREFIX + HTTPS_PORT + "/");
                    listener.Start();
                }
                if (httpThread == null || httpThread.ThreadState != ThreadState.Running)
                {
                    httpThread = new Thread(new ThreadStart(Run));
                    httpThread.Start();
                }
                isrunning = true;
            }
            catch(Exception ex) { ErrorMessage = ex.Message; }
        }
        /// <summary>
        /// 退出服务
        /// </summary>
        public void Exit()
        {
            stopped = true;
            try
            {
                if (listener != null)
                {
                    listener.Stop();
                    listener.Close();
                }
                if (httpThread != null)
                {
                    httpThread.Interrupt();
                }
                listener = null;
                httpThread = null;
            }
            catch (Exception ex) { ErrorMessage = ex.Message;  }
            isrunning = false;
        }
        /// <summary>
        /// 
        /// </summary>
        ~HttpServer()
        {
            Exit();
        }
        private void Run()
        {
            while (!stopped)
            {
                try
                {
                    var r = listener.BeginGetContext(new AsyncCallback(RequestHandler), listener);
                    r.AsyncWaitHandle.WaitOne();
                    r.AsyncWaitHandle.Close();
                }
                catch (ThreadInterruptedException e1) { ErrorMessage = e1.Message; }
                catch (HttpListenerException e2)
                {
                    ErrorMessage = e2.Message;
                }
            }
        }
        private void RequestHandler(IAsyncResult r)
        {
            try
            {
                _RequestHandler(r);
            }
            catch (Exception e)
            {
                ErrorMessage = e.Message;
            }
        }
        private void _RequestHandler(IAsyncResult r)
        {
            if (stopped) return;
            var l = (HttpListener)r.AsyncState;
            var ctx = l.EndGetContext(r);
            var req = ctx.Request;
            var resp = ctx.Response;
            var html = "";
            if(req.HttpMethod=="GET")
            {
                HttpRequest e = new HttpRequest();
                e.Url = req.Url;
                e.UrlReferrer = req.UrlReferrer;
                e.GetData = RyWeb.WebDecode.UrlToData(e.Url.AbsoluteUri);
                OnHandleGETRequest?.Invoke(this,e);
                resp.StatusCode = (int)e.StatusCode;
                html = e.ReturnHtml;
            }
            else if(req.HttpMethod=="POST")
            {
                HttpRequest e = new HttpRequest
                {
                    Url = req.Url,
                    UrlReferrer = req.UrlReferrer
                };
                var sr = new StreamReader(req.InputStream, Encoding.GetEncoding("utf-8"));
                e.PostDataStr = sr.ReadToEnd();
                e.GetData = RyWeb.WebDecode.UrlToData(e.Url.AbsoluteUri);
                e.PostData= RyWeb.WebDecode.UrlToData("f?"+e.PostDataStr);
                sr.Close();
                OnHandlePOSTRequest?.Invoke(this, e);
                resp.StatusCode = (int)e.StatusCode;
                html = e.ReturnHtml;
            }
            resp.ContentEncoding= Encoding.GetEncoding("utf-8");
            var buffer = Encoding.GetEncoding("utf-8").GetBytes(html);
            resp.ContentLength64 = buffer.Length;
            resp.Headers.Add("Content-Type:text/html; charset=utf-8");
            resp.Headers.Add("Access-Control-Allow-Origin: *");
            resp.OutputStream.Write(buffer, 0, buffer.Length);
            var outs = resp.OutputStream;
            outs.Close();
            resp.Close();
        }
    }
    /// <summary>
    /// 
    /// </summary>
    public class HttpRequest
    { 
        /// <summary>
        /// 
        /// </summary>
        public Uri Url { get; internal set; }
        /// <summary>
        /// 
        /// </summary>
        public string PostDataStr { get; internal set; } = "";
        /// <summary>
        /// 
        /// </summary>
        internal Tuple<string, IEnumerable<KeyValuePair<string, string>>> GetData { get; set; }
        /// <summary>
        /// 
        /// </summary>
        internal Tuple<string, IEnumerable<KeyValuePair<string, string>>> PostData { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string GetPostData(string Param)
        {
            return RyWeb.WebDecode.UrlDecode(PostData.Get(Param));
        }
        /// <summary>
        /// 
        /// </summary>
        public string GetPostData(string Param,string defValue)
        {
            return RyWeb.WebDecode.UrlDecode(PostData.Get(Param, defValue));
        }
        /// <summary>
        /// 
        /// </summary>
        public int GetPostData(string Param,int defValue)
        {
            return PostData.Get(Param, defValue);
        }
        /// <summary>
        /// 
        /// </summary>
        public bool GetPostData(string Param, bool defValue)
        {
            return PostData.Get(Param, defValue);
        }
        /// <summary>
        /// 
        /// </summary>
        public string GetUrlData(string Param)
        {
            return RyWeb.WebDecode.UrlDecode(GetData.Get(Param));
        }
        /// <summary>
        /// 
        /// </summary>
        public string GetUrlData(string Param, string defValue)
        {
            return RyWeb.WebDecode.UrlDecode(GetData.Get(Param, defValue));
        }
        /// <summary>
        /// 
        /// </summary>
        public int GetUrlData(string Param, int defValue)
        {
            return GetData.Get(Param, defValue);
        }
        /// <summary>
        /// 
        /// </summary>
        public bool GetUrlData(string Param, bool defValue)
        {
            return GetData.Get(Param, defValue);
        }
        /// <summary>
        /// 
        /// </summary>
        public Uri UrlReferrer { get; internal set; }
        /// <summary>
        /// 
        /// </summary>
        public string ReturnHtml { get; set; } = "";
        /// <summary>
        /// 
        /// </summary>
        public HttpStatusCode StatusCode { get; set; } = HttpStatusCode.OK;
    }
}
