/*
 * 由SharpDevelop创建。
 * 用户： Administrator
 * 日期: 2018-10-20
 * 时间: 11:34
 *
 * 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
 */

using System;
using System.Collections.Generic;
using System.Threading;
using System.Xml;
using GameData;
using GameDAL.FriendRoom;
using GameDAL.ServerInfo;
using MrWu.Debug;
using Newtonsoft.Json.Linq;
using Server.Config;
using Server.Data;
using Server.Data.Module;
using Server.DB.Redis;
using Server.Module;
using Server.MQ;
using Server.Pack;
using System.Threading.Tasks;
using MrWu.RabbitMQ;
using System.Linq;
using System.Text;
using Game.Robot;
using Game.Player;
using System.IO;
using System.Reflection;
using ActorCore;
using GameDAL;
using GameFramework;
using GameMessage;
using NetWorkMessage;
using Server.Core;
using GameConfig = Server.Config.GameConfig;

namespace Server
{
    /// <summary>
    /// 子游戏模块管理
    /// </summary>
    public abstract partial class GameBase : GlobalManager
    {
        /// <summary>
        /// 游戏实例
        /// </summary>
        public static GameBase gamebase
        {
            get { return GlobalManager.instance as GameBase; }
        }

        /// <summary>
        /// 游戏数据
        /// </summary>
        public static GameDataTab gameData;
        
        public GameBaseMainActor MainActor { get; private set; }

        /// <summary>
        /// 创建游戏工厂
        /// </summary>
        /// <returns></returns>
        protected virtual GameUtilFactory CreateFactory()
        {
            return new GameUtilFactory();
        }
        
        
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected override ConfigHead GetConfigHead()
        {
            ConfigHead cg = base.GetConfigHead();
            cg.style = 2;
            JObject obj = new JObject();
            cg.data = obj;

            GameConfig config = ServerConfigManager.Instance.GameConfig;
            obj["serid"] = config.GameId;
            obj["clientid"] = config.ClientId;
            obj["moduleid"] = ServerConfigManager.Instance.NodeId;
            obj["style"] = config.GameStyle;
            obj["gamename"] = config.GameName;
            obj["openFriend"] = config.OpenFriend;
            obj["openGold"] = config.OpenGold;
            obj["gameMode"] = config.GameMode;
            obj["activezt"] = 1;

            obj["webPort"] = ServerConfigManager.Instance.WebSocketPort;
            obj["ip"] = Convert.ToBase64String(
                Utility.Encryption.GetXorBytes(Encoding.ASCII.GetBytes("192.168.0.197"), KeyCosnt.IpKey));

            //Debug.Info($"得到ip地址:{config.modeuleInfo.ip} {obj["ip"]}");
            CaCheManager.instance.SetHash(RedisDictionary.AllServerConfig, $"GameModule-{myUtil.id}-{myUtil.nodeNum}",
                JsonPack.GetJson(obj));
            cg.data = obj;
            return cg;
        }

        /// <summary>
        /// 发送配置包
        /// </summary>
        protected override void SendConfigPack()
        {
            PackHead head = PackHead.Create();
            head.packlx = ServerPackAgreement.ConfigPack;
            Debug.Info("发送配置包裹!");
            GlobalMQ.instance.DeliveryAll((int)ModuleType.ConfigModule,
                GlobalMQ.CreateMessage(head, ClientConfig, FailTags.ConfigSendFail, myUtil.id, myUtil.nodeNum), true);
            head.Dispose();
        }

        /// <summary>
        /// 检查网络
        /// </summary>
        /// <returns></returns>
        private bool CheckNet()
        {
            return true;
        }

        public override void DayInit()
        {
            base.DayInit();
            GameManager.instance.DayInit();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected override bool Init()
        {
            Debug.Info("游戏初始化!");
            
            if (!CheckNet())
            {
                Debug.Error("端口被占用!");
                Close();
                return false;
            }
            
            LuckPlayerManager.Instance.LoadData(ServerConfigManager.Instance.ClubBalance);
            GameSeridDic.instance.Add(ServerConfigManager.Instance.NodeId, ServerConfigManager.Instance.GameId);
            
            gameData = new GameDataTab(myUtil, new GameInfo(ServerConfigManager.Instance.GameConfig));
            CreateFactory().CreateManager(ServerConfigManager.Instance.GameConfig);

            FriendRoomStatistics.Instance.Start();
            //ExportConfigManager.Instance.ExportConfig(config.gameConfig.gameid);
            
            //dll初始化
            bool r = DllStart(ServerConfigManager.Instance.GameId);
            if (!r)
            {
                Debug.Error("asdasjnfajks");
                Close();
                return r;
            }

            //游戏初始化
            GameManager.instance.Init(); //获取缓存后,发送缓存变化包

            //发送游戏信息
            //SendGameInfo();

            //发送缓存数据
            CaCheManager.SendCacheChange(RedisDictionary.AllServerConfig);
            
            GameMessageManager.Instance.Start(myType, ServerConfigManager.Instance.WebSocketPort, ServerConfigManager.Instance.GameId);
            
            MessageManager.Register();
            new CodeTypes().Register();
            CodeTypes.Instance.Init(new Assembly[]{this.GetType().Assembly,typeof(ActorManager).Assembly});
            new OpcodeType().Register();
            new ActorMessageQueue().Register();
            new ActorManager().Register();
            new UserSessionManager(true).Register();
            
            byte moduleId = ServerConfigManager.Instance.NodeId; 
            byte nodeNum = ServerConfigManager.Instance.NodeNum;
            var gameCenterMainActor = new GameBaseMainActor(moduleId, nodeNum);
            MainActor = gameCenterMainActor;
            Debug.Info($"ActorId:{moduleId} {nodeNum} {gameCenterMainActor.ActorId}");
            ActorNetManager.Instance.RegisterInnerNet(gameCenterMainActor.ActorId,ServerConfigManager.Instance.InnerNetEndPoint);
            ActorManager.Instance.RegisterActor(gameCenterMainActor);
            
            if (ServerConfigManager.Instance.OuterNetEndPoint != null)
            {
                ActorNetManager.Instance.RegisterOuterNet(gameCenterMainActor.ActorId,ServerConfigManager.Instance.OuterNetEndPoint);
                ActorManager.Instance.RegisterActor(new UserNetActor(moduleId,nodeNum,ServerConfigManager.Instance.OuterNetEndPoint));
            }
            ActorManager.Instance.RegisterActor(new NetInnerActor(moduleId, nodeNum,
                ServerConfigManager.Instance.InnerNetEndPoint, ActorNetManager.Instance.GetInnerIpEndPoint));
            
            return true;
        }


        /// <summary>
        /// ZyxDll初始化
        /// </summary>
        /// <returns></returns>
        protected virtual bool DllStart(int gameid)
        {
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        public override void OnTime(int Interval)
        {
            GameManager.instance.OnTime(Interval);
        }

        protected override void Update()
        {
            base.Update();
            ActorManager.Instance.Update();
            ActorManager.Instance.LateUpdate();
            
            GameMessageManager.Instance.Update();
            LuckPlayerManager.Instance.Update();
        }

        /// <summary>
        /// 
        /// </summary>
        public override void SecondTime()
        {
            base.SecondTime();
            GameManager.instance.SecondTime();

            if (DateTime.Now > NextUpdateGameInfo)
            {
                NextUpdateGameInfo = DateTime.Now.AddMinutes(5);
                UpdateGameInfo();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public override void Close()
        {
            ActorManager.Instance.Dispose();
            ActorMessageQueue.Instance.Dispose();
            CodeTypes.Instance.Dispose();
            
            GameMessageManager.Instance.Dispose();
            LuckPlayerManager.Instance.SaveData();
            FightDataManager.Instance.Dispose();
            FightRecordManager.Instance.Dispose();
            FriendRoomStatistics.Instance.Dispose();
            GameManager.instance.Close();
            if (gameData != null)
                gameData.Close();
            GameManager.dllUtil.FreeDll();
            //GlobalMQ.RemoveFilter(ServerSocket.SocketProtocolManager.SocketManager.SocketMessageFilter);
            base.Close();
        }

        /// <summary>
        /// 处理命令
        /// </summary>
        /// <param name="msg"></param>
        protected override void DoCommand(WaitBeMsg msg)
        {
            string[] cmds = msg.head.otherString;
            bool r = true;
            switch (cmds[0])
            {
                case "showPlayer":
                    Debug.Info("收到显示玩家命令");
                    if (cmds.Length < 2)
                    {
                        Debug.Error("命令错误!");
                        return;
                    }

                    int usd = 0;
                    if (!int.TryParse(cmds[1], out usd))
                    {
                        Debug.Error("命令错误参数格式不对{0}", cmds[1]);
                        return;
                    }

                    PlayerDataAsyc pl = PlayerCollection.Instance.FindPlayerByUserId(usd);
                    if (pl == null)
                    {
                        Debug.Info("玩家不在线{0}", usd);
                        return;
                    }

                    Debug.Info("玩家信息:{0}{1}", Environment.NewLine, pl);
                    break;
                case "shanZhuo":
                    Debug.Info("收到强制散桌命令");
                    if (cmds.Length < 2)
                    {
                        Debug.Error("命令错误!");
                        return;
                    }

                    usd = 0;
                    if (!int.TryParse(cmds[1], out usd))
                    {
                        Debug.Error("命令参数错误{0}", cmds[1]);
                        return;
                    }

                    GameManager.instance.ForceOver(usd);
                    break;
                case "tinginfo":
                    Debug.Info("显示厅信息命令");
                    if (cmds.Length < 2)
                    {
                        Debug.Error("命令错误!");
                        return;
                    }

                    int tingid = 0;
                    if (!int.TryParse(cmds[1], out tingid))
                    {
                        Debug.Error("命令参数错误{0}", cmds[1]);
                        return;
                    }

                    if (tingid < 0 || tingid >= GameManager.instance.tingCnt)
                    {
                        Debug.Warning("没有这个厅tingid:{0},maxting:{1}", tingid, GameManager.instance.tingCnt);
                        return;
                    }

                    Debug.Info(
                        GameManager.instance.FindTing(tingid).ToString()
                    );
                    break;
                case "roominfo":
                    Debug.Info("显示城堡信息命令");
                    if (cmds.Length < 2)
                    {
                        Debug.Error("命令错误!");
                        return;
                    }

                    int roomid = 0;
                    if (!int.TryParse(cmds[1], out roomid))
                    {
                        Debug.Warning("命令参数错误{0}", cmds[1]);
                        return;
                    }

                    if (roomid < 0 || roomid >= GameManager.instance.roomCnt)
                    {
                        Debug.Warning("没有这个城堡roomid:{0},maxroom:{1}", roomid, GameManager.instance.roomCnt);
                        return;
                    }

                    Debug.Info(
                        GameManager.instance.FindRoom(roomid).ToString()
                    );
                    break;
                case "deskinfo":
                    Debug.Info("显示桌子信息");
                    if (cmds.Length < 3)
                    {
                        Debug.Error("命令错误!");
                        return;
                    }

                    tingid = 0;
                    int deskid = 0;
                    if (!int.TryParse(cmds[1], out tingid))
                    {
                        Debug.Warning("参数格式错误:{0}", cmds[1]);
                        return;
                    }

                    if (!int.TryParse(cmds[2], out deskid))
                    {
                        Debug.Warning("命令参数格式错误:{0}", cmds[2]);
                        return;
                    }

                    var desk = GameManager.instance.FindDesk(tingid, deskid);

                    if (desk != null)
                    {
                        Debug.Info(desk.ToString());
                    }
                    else
                    {
                        Debug.Warning($"没有这个桌子,tingid:{tingid},deskid:{deskid}");
                    }

                    break;
                case "loadfriend": //加载朋友房数据
                    Debug.Error("参数错误!");
                    break;
                default:
                    r = false;
                    break;
            }

            if (r)
                return;

            base.DoCommand(msg);
        }

        /// <summary>
        /// ReportPlayerOnLineData
        /// </summary>
        /// <param name="msg"></param>
        protected override void ReportPlayerOnLineData(WaitBeMsg msg)
        {
            var name = ServerConfigManager.Instance.GameName;
            var moduleid = ServerConfigManager.Instance.NodeId;
            var nodeNum = ServerConfigManager.Instance.NodeNum;
            
            var playerCount = PlayerCollection.Instance.PlayerCnt;
            var RobotCnt = PlayerCollection.Instance.RobotCnt;
            var roomCnt = GameManager.instance.roomCnt;
            var tingCnt = GameManager.instance.tingCnt;
            var winMoney = GameManager.instance.winmoney;
            var taxMoney = GameManager.instance.taxmoney;

            var personCount = playerCount - RobotCnt;

            var data = new
            {
                name,
                moduleid,
                nodeNum,
                personCount,
                playerCount,
                RobotCnt,
                winMoney,
                taxMoney,
                roomCnt,
                tingCnt
            };

            PackHead head = PackHead.Create(ServerPackAgreement.ReportPlayerOnLineDataResp);
            GlobalMQ.instance.DeliveryOne(msg.head.sendutil,
                GlobalMQ.CreateMessage(head, data), true);
            head.Dispose();
        }

        /// <summary>
        /// 下一次更新游戏信息的时间
        /// </summary>
        public DateTime NextUpdateGameInfo = new DateTime(2000, 01, 01);

        /// <summary>
        /// 更新游戏新
        /// </summary>
        public void UpdateGameInfo()
        {
            //把数据保存到redis中
            void SaveToRedisGameInfo(GameServerInfo info)
            {
                string value = JsonPack.GetJson(info);
                redisManager.Getdb(RedisDictionary.configDb).HashSet(RedisDictionary.GameSerinfoDetail,
                    info.node.id + "-" + info.node.nodeNum, value);
            }

            GameConfig gameConfig = ServerConfigManager.Instance.GameConfig;
            GameServerInfo gsi = new GameServerInfo();
            gsi.node = myUtil;
            gsi.gamename = gameConfig.GameName;
            gsi.winmoney = GameManager.instance.winmoney;
            gsi.taxmoney = GameManager.instance.taxmoney;
            gsi.playerCount = PlayerCollection.Instance.RealPlayerCnt;
            gsi.startTime = serverinfo.startTime;
            gsi.warCnt = GameManager.instance.warCnt;
            gsi.loginCnt = GameManager.instance.loginCnt;
            gsi.cardCnt = GameManager.instance.DelFangKa;
            gsi.DeskCnt = GameManager.instance.deskCnt;

            int len = ServerConfigManager.Instance.Castles.Length;
            gsi.rooms = new GameServerInfo.RoomInfo[len];
            for (int i = 0; i < len; i++)
            {
                gsi.rooms[i] = new GameServerInfo.RoomInfo();
                RoomManager room = GameManager.instance.FindRoom(i);

                gsi.rooms[i].PlayerCnt = room.playerCount - room.robotCount;
                gsi.rooms[i].taxMoney = room.taxmoney;
                gsi.rooms[i].winmMoney = room.winmoney;
            }

            //var socketInfo = ServerSocket.SocketProtocolManager.SocketManager.UpdateServerInfo(false);//ServerSocket
            Task.Factory.StartNew(
                () => SaveToRedisGameInfo(gsi)
            );
        }

        #region 消息路由器

        /// <summary>
        /// 游戏消息处理器
        /// </summary>
        public class GameMessageProcessor : MessageProcessor
        {
            private GameBase instance
            {
                get { return GlobalManager.instance as GameBase; }
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="msg"></param>
            /// <param name="logStringBuilder"></param>
            /// <returns></returns>
            protected override bool DoPackBase(WaitBeMsg msg, StringBuilder logStringBuilder)
            {
                PackHead head = msg.head;
                if (!base.DoPackBase(msg, logStringBuilder))
                {
                    switch (head.packlx)
                    {
                        case ServerPackAgreement.disbank: //解散房间命令
                            var kvp = JsonPack.GetData<KeyValuePair<int, int>>(msg.jsondata);
                            FriendRoomManager.instance.DisBankCmd(kvp.Key, kvp.Value);
                            break;
                        case ServerPackAgreement._domessage: //转发玩家消息
                            GameManager.instance.DoMessageData(head, msg.jsondata);
                            break;

                        case ServerPackAgreement.PlayerMemChange: //玩家数据变化包
                            break;

                        case ServerPackAgreement.GetConfigPack: //获取配置包
                            instance.SendConfigPack();
                            break;

                        case ServerPackAgreement.DisConnection:
                            GamePack gamePack = GamePack.Create(msg.head,msg.jsondata);
                            //Debug.Info("ServerPackAgreement.DisConnection:ServerPackAgreement.DisConnection:");
                            GameManager.instance.DoPack(gamePack);
                            gamePack.Dispose();
                            break;
                        case ServerPackAgreement.RechargeOrders:
                        case ServerPackAgreement.AddPlayerZiChanNum:
                        case ServerPackAgreement.GetFixedMatchData:
                        case ServerPackAgreement.GetMatchFightData:
                        case ServerPackAgreement.AddRaceConfig:
                            GameManager.instance.DoRPC(msg);
                            break;
                        // default:
                        //     return ServerSocket.SocketProtocolManager.SocketManager.DoPackBase(msg); //ServerSocket
                    }
                }

                return true;
            }


            /// <summary>
            /// 处理包
            /// </summary>
            /// <param name="msg"></param>
            /// <param name="logStringBuilder"></param>
            protected override void DoPack(WaitBeMsg msg, StringBuilder logStringBuilder)
            {
                if (!CheckClientVer(msg.head))
                {
                    Debug.Warning("检测客户端版本未通过!!!" + msg.head.packlx + "," + msg.head.transfer + "," +
                                  msg.head.clientVer + "," + msg.jsonmessage);
                    return;
                }

                PackHead head = msg.head;
#if DEBUG
                Debug.Log($"DoPack packlx:{head.packlx}");
#endif
                bool r = true;
                switch (msg.head.packlx)
                {
                    case ServerPackAgreement.TransFerPack: //中转包
                        Debug.Error($"没有中转包! {head.transfer}");
                        //ServerSocket.SocketProtocolManager.SocketManager.TransFerPack(msg.head, msg.jsondata);
                        break;

                    case GameSeverAgreement.joinFriendRoom:
                        GamePack _gamePack = GamePack.Create(msg.head, msg.jsondata);
                        GameManager.instance.DoPack(_gamePack);
                        _gamePack.Dispose();
                        break;

                    default:
                        r = false;
                        break;
                }

                if (r)
                    return;

                int temp = head.packlx / Game.Data.GameData.PackCardInt;
                int pkid = head.packlx % Game.Data.GameData.PackCardInt;
                if (temp != ServerConfigManager.Instance.NodeId)
                {
                    Debug.Warning("不是本模块的包:" + head.packlx);
                    return;
                }

                head.packlx = pkid;
                //Debug.Log("处理包basdbajksbhkasb");

                GamePack gamePack = GamePack.Create(head,msg.jsondata);
                GameManager.instance.DoPack(gamePack);
                gamePack.Dispose();
            }


            protected override bool CheckClientVer(PackHead head)
            {
                if (head.packlx != GamePackAgreement.TransFerHttp &&
                    head.packlx != GamePackAgreement.TransFerPack &&
                    head.clientVer < ServerConfigManager.Instance.MinCVer)
                {
                    head.transfer = GamePackAgreement.MandatoryUpdate;
                    var md = head.GetUtil();
                    if (md == null)
                        return true;

                    if (md.Equals(GameBase.instance.myUtil))
                    {
                        head.packlx = GamePackAgreement.MandatoryUpdate;
                        GameNet.SendPack_Userid(head.userid, head, null);
                        return false;
                    }

                    if (md.id == (int)ModuleType.HttpModule)
                        head.packlx = ServerPackAgreement.TransFerHttp;
                    else
                        head.packlx = ServerPackAgreement.TransFerPack;
                    GlobalMQ.instance.DeliveryOne(md, GlobalMQ.CreateMessage(head), true);
                    return false;
                }

                return true;
            }
        }

        #endregion
    }
}