
using System;
using System.IO;
using System.Web;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.ComponentModel;

using Newtonsoft.Json;
using Legalsoft.Workflow.Engine;

//namespace Legalsoft.Workflow.Engine
//{
    public static class XBaby
    {
        public static string Company = "BEIJING LEGALSOFT LTD.";
        public static string Software = "FLOWSTUDIO 2017";
        public static string Release = "0.8.8.8";
        public static string EncoderName = "utf-8";
        public static string DataPath = WebHelper.Server.MapPath("/app_resource/");
        public static string LocalUrl = "http://" + WebHelper.HttpHost + "/api/v1/";
        public static string RemoteUrl = "";

        public static string Summary()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<span class=\"information\" id=\"api_info\">");
            sb.AppendLine("Charactor Encoder Name = " + EncoderName + "<br>");
            sb.AppendLine("LocalUrl = " + LocalUrl + "<br>");
            sb.AppendLine("RemoteUrl = " + RemoteUrl + "<br>");
            sb.AppendLine("</span>");
            return sb.ToString();
        }
    }

    public static class Commands
    {
        private static string _err = "";
        public static string Err() { string e = _err; _err = ""; return e; }
        private static bool CanSave = true;

        private static Queue Outbox = new Queue();
        public static void Send(CommandInfo cmd) { Outbox.Enqueue(cmd); }

        private static Queue Inbox = new Queue();
        public static void Receive(CommandInfo cmd) { Inbox.Enqueue(cmd); }

        private static string ENCRYPT(string buf) { return buf; }
        private static string DECRYPT(string buf) { return buf; }

        private static string PrintError(string rsl, string msg)
        {
            return ("{ \"result\" , \"" + rsl + "\",  \"message\" : \"" + msg.Replace("\"", "&#34;") + "\" }");
        }

        public static string Page(HttpRequest Request)
        {
            if (Request["json"] == null) { return PrintError("error", "[Commands.Page]form error:no json data"); }
            string memo = DECRYPT(Request["json"].ToString());
            if (Request["md5"] == null) { return PrintError("error", "[Commands.Page]form error:no md5 data"); }
            string md5 = Request["md5"].ToString();

            return Receiving(memo, md5, false);
        }

        public static string Receiving(string json, string md5, bool synchronous)
        {
            try
            {
                if (json.Length < 1)
                {
                    return PrintError("error", "[Commands.Receiving]no json data");
                }
                string memo = DECRYPT(json);
                if (md5.Length < 1)
                {
                    return PrintError("error", "[Commands.Receiving]no md5 data");
                }
                if (String.Compare(CryptHelper.MD5(memo), md5) != 0)
                {
                    return PrintError("error", "[Commands.Receiving]:invalid md5");
                }

                // 清除错误信息
                string err = Flows.Err();
                CommandInfo cmd = JsonConvert.DeserializeObject<CommandInfo>(memo);
                if (XBaby.RemoteUrl.Length < 1) XBaby.RemoteUrl = cmd.LocalUrl;

                Receive(cmd);

                // 执行命令
                Flows.Returns.Clear();
                if (cmd.Operation == "create") { Flows.Create(cmd); }
                if (cmd.Operation == "forward") { Flows.Forward(cmd, cmd.NodeId); }
                if (cmd.Operation == "backward") { Flows.Backward(cmd, cmd.NodeId); }
                if (cmd.Operation == "cancel") { Flows.Cancel(cmd, cmd.NodeId); }

                err = Flows.Err();
                if (err.Length > 0) { return PrintError("error", "[Commands.Receiving]:" + err); }

                for (int i = 0; i < Flows.Returns.Count; i++)
                {
                    Send(Flows.Returns[i]);
                    Flows.Returns.RemoveAt(i);
                    i--;
                }

                // 如果是同步模式，直接输出json格式的CommandInfo
                if (synchronous)
                {
                    return JsonConvert.SerializeObject(cmd);
                }
                else
                {
                    // 这里添加保存历史纪录的代码！
                    Save();
                    return PrintError("ok", "");
                }
            }
            catch (Exception ex)
            {
                return PrintError("error", "[Commands.Receiving]" + ex.Message);
            }
        }

        public static void Save()
        {
            try
            {
                if (!CanSave) return;
                string memo = JsonConvert.SerializeObject(Outbox);
                File.WriteAllText(XBaby.DataPath + "/outbox.json", memo, Encoding.GetEncoding("utf-8"));

                string meme = JsonConvert.SerializeObject(Inbox);
                File.WriteAllText(XBaby.DataPath + "/inbox.json", meme, Encoding.GetEncoding("utf-8"));
            }
            catch (Exception ex)
            {
                CanSave = false;
                _err = "[Commands.Save]" + ex.Message;
                return;
            }
        }

        private static string UrlEncode(string inputData)
        {
            return HttpUtility.UrlEncode(inputData);
        }

        public static void Sending()
        {
            if (Outbox.Count < 1) return;
            // 默认情况下发送一条；
            // 如果数量很大，是不是一次性多发几条？
            CommandInfo cmd = (CommandInfo)Outbox.Dequeue();
            try
            {
                string json = JsonConvert.SerializeObject(cmd);
                string memo = ENCRYPT(json);
                string url = XBaby.RemoteUrl + "?json=" + UrlEncode(memo) + "&md5=" + CryptHelper.MD5(json);
                _err = NetworkHelper.Download(url, XBaby.EncoderName, 30);
                Tracer.Append("send to " + cmd.RemoteUrl + " " + _err);
            }
            catch (Exception ex)
            {
                Outbox.Enqueue(cmd);
                _err = "[Commands.Sending]" + ex.Message;
                Tracer.Append(_err);
            }
        }

        public static string Summary()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<span class=\"information\" id=\"commands_info\">");
            sb.AppendLine("There are " + Outbox.Count + " commands to send.<br>");
            if (Outbox.Count > 0)
            {
                sb.AppendLine("<table width=\"0%\" border=1>");
                sb.AppendLine("<tr style=\"background-color:#EEEEFF;\"><td colspan=2>Flow</td><td>Node</td><td colspan=2>Role</td><td>Member</td><td>Opr</td></tr>");
                foreach (CommandInfo cx in Outbox)
                {
                    sb.AppendLine("<tr>");
                    sb.AppendLine("<td>" + cx.FlowName + "</td>");
                    sb.AppendLine("<td>" + cx.FlowId + "</td>");
                    sb.AppendLine("<td>" + cx.NodeId + " " + cx.NodeName + "</td>");
                    sb.AppendLine("<td>" + cx.LastRole + "</td>");
                    sb.AppendLine("<td>" + cx.Role + "</td>");
                    sb.AppendLine("<td>" + cx.MemberId + " " + cx.MemberName + "</td>");
                    sb.AppendLine("<td>" + cx.Operation + "</td>");
                    sb.AppendLine("</tr>");
                }
                sb.AppendLine("</table>");
                sb.AppendLine("<br>");
            }
            sb.AppendLine("There are " + Inbox.Count + " commands have received.<br>");
            if (Inbox.Count > 0)
            {
                sb.AppendLine("<table width=\"0%\" border=1>");
                sb.AppendLine("<tr style=\"background-color:#EEEEFF;\"><td colspan=2>Flow</td><td>Node</td><td colspan=2>Role</td><td>Member</td><td>Opr</td></tr>");
                foreach (CommandInfo cx in Inbox)
                {
                    sb.AppendLine("<tr class=\"btr\">");
                    sb.AppendLine("<td>" + cx.FlowName + "</td>");
                    sb.AppendLine("<td>" + cx.FlowId + "</td>");
                    sb.AppendLine("<td>" + cx.NodeId + " " + cx.NodeName + "</td>");
                    sb.AppendLine("<td>" + cx.LastRole + "</td>");
                    sb.AppendLine("<td>" + cx.Role + "</td>");
                    sb.AppendLine("<td>" + cx.MemberId + " " + cx.MemberName + "</td>");
                    sb.AppendLine("<td>" + cx.Operation + "</td>");
                    sb.AppendLine("</tr>");
                }
                sb.AppendLine("</table>");
            }
            sb.AppendLine("</span>");
            return sb.ToString();
        }
    }

    public static class Tracer
    {
        private static List<string> Items = new List<string>();
        public static void Append(string su)
        {
            Items.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " " + su);
        }
        public static string Summary()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("<span class=\"information\" id=\"tracer_info\">");
            sb.AppendLine("History summary<br>");
            foreach (string su in Items)
            {
                string sk = su;
                while (sk.Length > 80)
                {
                    sb.AppendLine(sk.Substring(0, 80) + "<br>");
                    sk = sk.Substring(80);
                }
                sb.AppendLine(sk + "<br>");
            }
            sb.AppendLine("</span>");
            return sb.ToString();
        }
    }
//}
