using MongoDB.Bson;
using MongoDB.Driver;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace LolDataRequestLib
{
    /// <summary>
    /// 데이터를 관리하기위한 매니저객체.
    /// 
    /// 데이터 공유의 편의성을 위해 Singleton을 사용.
    /// 
    /// 모든 데이터를 요청하고 관리한다.
    /// </summary>
    public class DataManager
    {

        #region 싱글턴&생성자

        private static DataManager mInstance = null;

        private static object mSingletonLocker = new object();

        internal MongoClient mDBClient = null;

        public bool isNewBanPick = false;

        public static DataManager getInstance()
        {

            lock (mSingletonLocker)
            {
                if (mInstance == null)
                {
                    mInstance = new DataManager();
                }
            }

            return mInstance;

        }


        private DataManager()
        {

            init();

        }

        #endregion

        #region 라이브데이터변수

        /// <summary>
        /// 실시간 업데이트 데이터 크리티컬세션 관리용 락커.
        /// </summary>
        private object mDataAccessObjectLocker = new object();

        /// <summary>
        /// 벤픽에 관련된 데이터
        /// </summary>
        private BsonValue m밴픽데이터 = null;

        /// <summary>
        /// 벤픽에 관련된 데이터 게터&세터
        /// </summary>
        internal BsonValue 밴픽데이터
        {
            get
            {

                lock (mDataAccessObjectLocker)
                {
                    return m밴픽데이터;
                }

            }
            set
            {

                lock (mDataAccessObjectLocker)
                {
                    m밴픽데이터 = value;
                }

            }
        }


        /// <summary>
        /// 경기데이터에 관련된 데이터
        /// </summary>
        private BsonValue m경기데이터 = null;

        /// <summary>
        /// 경기데이터(status_update)에 관련된 데이터 게터&세터
        /// </summary>
        internal BsonValue 경기데이터
        {
            get
            {

                lock (mDataAccessObjectLocker)
                {
                    return m경기데이터;
                }

            }
            set
            {

                lock (mDataAccessObjectLocker)
                {
                    m경기데이터 = value;
                }

            }
        }

        /// <summary>
        /// 모든 오브젝트에 관련된 데이터
        /// </summary>
        private BsonValue m오브젝트데이터 = null;

        /// <summary>
        /// 오브젝트데이터에 관련된 데이터 게터&세터
        /// </summary>
        internal BsonValue 오브젝트데이터
        {
            get
            {
                lock (mDataAccessObjectLocker)
                {
                    return m오브젝트데이터;
                }

            }
            set
            {

                lock (mDataAccessObjectLocker)
                {
                    m오브젝트데이터 = value;
                }

            }
        }

        /// <summary>
        /// 드래곤리스폰에 관련된 데이터
        /// </summary>
        private BsonValue m드래곤리스폰 = null;


        /// <summary>
        /// 드래곤리스폰에 관련된 데이터 게터&세터
        /// </summary>
        internal BsonValue 드래곤리스폰
        {
            get
            {

                lock (mDataAccessObjectLocker)
                {
                    return m드래곤리스폰;
                }

            }
            set
            {

                lock (mDataAccessObjectLocker)
                {
                    m드래곤리스폰 = value;
                }

            }
        } 
        /*
        private BsonValue m아타칸리스폰 = null;


        /// <summary>
        /// 드래곤리스폰에 관련된 데이터 게터&세터
        /// </summary>
        internal BsonValue 아타칸리스폰
        {
            get
            {

                lock (mDataAccessObjectLocker)
                {
                    return m아타칸리스폰;
                }

            }
            set
            {

                lock (mDataAccessObjectLocker)
                {
                    m아타칸리스폰= value;
                }

            }
        }
        */
        /// <summary>
        /// 건물파괴에 관련된 데이터
        /// </summary>
        private BsonValue m건물데이터 = null;

        /// <summary>
        /// 건물파괴에 관련된 데이터 게터&세터
        /// </summary>
        internal BsonValue 건물데이터
        {
            get
            {

                lock (mDataAccessObjectLocker)
                {
                    return m건물데이터;
                }

            }
            set
            {

                lock (mDataAccessObjectLocker)
                {
                    m건물데이터 = value;
                }

            }
        }
        /// <summary>
        /// 건물파괴에 관련된 골드 데이터
        /// </summary>
        private BsonValue m타워골드데이터 = null;

        /// <summary>
        /// 건물파괴에 관련된 데이터 게터&세터
        /// </summary>
        internal BsonValue 타워골드데이터
        {
            get
            {

                lock (mDataAccessObjectLocker)
                {
                    return m타워골드데이터;
                }

            }
            set
            {

                lock (mDataAccessObjectLocker)
                {
                    m타워골드데이터 = value;
                }

            }
        }


        #endregion

        /// <summary>
        /// 라이브데이터를 업데이트하는 인스턴스 리스트
        /// </summary>
        List<ARequestData> mRequestDataList = null;

        /// <summary>
        /// 매니저 초기화.
        /// 필요한 Request들을 생성하고 RequestWorker를 실행한다..
        /// </summary>
        private void init()
        {
            //라이브워커 준비
            IsupdateWorkersWork = true;

            mRequestDataList = new List<ARequestData>();

            mRequestDataList.Add(ARequestData.createRequestFactory(DBDefine.RequestDataType.BAN_AND_PICK));
            mRequestDataList.Add(ARequestData.createRequestFactory(DBDefine.RequestDataType.GAME_STATUS));
            mRequestDataList.Add(ARequestData.createRequestFactory(DBDefine.RequestDataType.OBJECT_EVENT));
            mRequestDataList.Add(ARequestData.createRequestFactory(DBDefine.RequestDataType.STRUCT_EVENT));
            mRequestDataList.Add(ARequestData.createRequestFactory(DBDefine.RequestDataType.STRUCT_GOLD_EVENT));
            mRequestDataList.Add(ARequestData.createRequestFactory(DBDefine.RequestDataType.DRAGON_RESPAWN));
            mRequestDataList.Add(ARequestData.createRequestFactory(DBDefine.RequestDataType.ATAKHAN_RESPAWN));

            //기초데이터(밴순서, 챔피언매핑, 룬매핑) 만들기.
            mDBClient = new MongoClient(DBDefine.MONGODB주소);
            밴데이터만들기(false);
            setChampionDataMapping();
            setRuneDataMapping();


        }

        /// <summary>
        /// DB주소를 변경하고 MongodbClient를 초기화
        /// </summary>
        /// <param name="가져온디비주소"></param>
        public void resetDBAddress(string 가져온디비주소)
        {
            DBDefine.디비변경(가져온디비주소);

            lock (mDataAccessObjectLocker)
            {
                mDBClient = new MongoClient(DBDefine.MONGODB주소);

                foreach (ARequestData item in mRequestDataList)
                {

                    item.resetDBAddress();
                }
            }

            밴픽데이터 = null;
            오브젝트데이터 = null;
            드래곤리스폰 = null;
            //아타칸리스폰 = null;
            경기데이터 = null;
            건물데이터 = null;
            타워골드데이터 = null;
        }

        /// <summary>
        /// 챔피언ID-챔피언이름 영문 매핑
        /// </summary>
        //public Dictionary<int, string> mChampionTable = null;
        public Dictionary<int, ChampionInfoVO> mChampionTable = null;

        public class ChampionInfoVO
        {
            public int ID;
            public string champNameKOR;
            public string champNameENG;

        }


        /// <summary>
        /// 챔피언매핑데이터를 가져와서 세팅한다.
        /// </summary>
        void setChampionDataMapping()
        {


            //IMongoDatabase eventDataBase = mDBClient.GetDatabase("basic_data_lol");

            //var filter = Builders<BsonDocument>.Filter.Eq("type", "champion");

            //var projection = Builders<BsonDocument>.Projection
            //    .Exclude("_id");

            //List<BsonDocument> documents = eventDataBase.GetCollection<BsonDocument>("campion_raw")
            //    .Find(filter)
            //    .Project(projection)
            //    .ToList();


            BsonDocument documents = null;

            if (!BsonDocument.TryParse((File.ReadAllText(DBDefine.챔피언데이터파일경로)), out documents))
            {
                throw new Exception("챔피언 데이터 파일에서 데이터를 가져올 수 없습니다.");
            }

            BsonDocument bufChampionDataArray = documents["data"].AsBsonDocument;

            /*
             * 20230106 챔피언 정보 업데이트 수정
            mChampionTable = new Dictionary<int, string>();


            foreach (BsonElement item in bufChampionDataArray)
            {
                mChampionTable.Add(Convert.ToInt32(item.Value["key"].AsString), item.Name.Replace(" ", ""));
            }
            */

            mChampionTable = new Dictionary<int, ChampionInfoVO>();


            foreach (BsonElement item in bufChampionDataArray)
            {

                ChampionInfoVO bufChampionInfo = new ChampionInfoVO();
                 
                    
                try
                {
                    bufChampionInfo.ID = Convert.ToInt32(item.Value["key"].AsString);
                    bufChampionInfo.champNameENG = item.Value["id"].AsString.Replace(" ", "");
                    bufChampionInfo.champNameKOR = item.Value["name"].AsString.Replace(" ", "");
                    
                }
                catch(Exception ex)
                {
                }
                finally
                {
                    mChampionTable.Add(Convert.ToInt32(item.Value["key"].AsString), bufChampionInfo);
                }
                    
                
            }

        }



        public Dictionary<int, string> mRuneTable = null;


        void setRuneDataMapping()
        {


            BsonArray documents = null;

            //JObject ddd = JObject.Parse(File.ReadAllText(DBDefine.룬데이터파일경로));


            try
            {
                documents = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonArray>(File.ReadAllText(DBDefine.룬데이터파일경로));
            }
            catch (Exception)
            {

                throw new Exception("룬데이터를 가져오는데 오류가 발생했습니다");
            }
            
            //documents = BsonArray.Parse();



            mRuneTable = new Dictionary<int, string>();

            foreach (BsonDocument item in documents)
            {
                
                mRuneTable.Add(item["id"].ToInt32(), item["name"].AsString);

                BsonArray innerRunes = item["slots"].AsBsonArray;

                foreach (BsonValue innerItem in innerRunes)
                {

                    BsonArray innerSubRunes = innerItem["runes"].AsBsonArray;

                    foreach (BsonValue innerSubItem in innerSubRunes)
                    {
                        mRuneTable.Add(innerSubItem["id"].ToInt32(), innerSubItem["name"].AsString.Replace(" ", ""));
                    }

                }

            }

        }

        internal Dictionary<int, int> 밴픽순서테이블 = new Dictionary<int, int>();
      
         
        public void 밴데이터만들기(bool isRedBan)
        {

            밴픽순서테이블 = new Dictionary<int, int>();

            if (!isRedBan)
            {
                밴픽순서테이블.Add(101, 1);
                밴픽순서테이블.Add(202, 2);
                밴픽순서테이블.Add(103, 3);
                밴픽순서테이블.Add(204, 4);
                밴픽순서테이블.Add(105, 5);
                밴픽순서테이블.Add(206, 6);
                밴픽순서테이블.Add(201, 7);
                밴픽순서테이블.Add(102, 8);
                밴픽순서테이블.Add(203, 9);
                밴픽순서테이블.Add(104, 10);
            }
            else
            {
                밴픽순서테이블.Add(201, 1);
                밴픽순서테이블.Add(102, 2);
                밴픽순서테이블.Add(203, 3);
                밴픽순서테이블.Add(104, 4);
                밴픽순서테이블.Add(205, 5);
                밴픽순서테이블.Add(106, 6);
                밴픽순서테이블.Add(101, 7);
                밴픽순서테이블.Add(202, 8);
                밴픽순서테이블.Add(103, 9);
                밴픽순서테이블.Add(204, 10);
            }
        }

        public bool IsupdateWorkersWork = false;

        //public string mPlatformGameID = "ESPORTSTMNT06_1720762";

        /// <summary>
        /// DB에서 라이브로 데이터를 가져올 게임의 PlatformID
        /// </summary>
        //public string mPlatformGameID = "ESPORTSTMNT02_1923726";
        public string platformGameID = "sr fakegod's game";
        //public string mPlatformGameID = "ESPORTSTMNT06_1721059";



        public object platformIDLocker = new object();
        /// <summary>
        /// 경기가 리게임 되었을때를 대비해 platformID가 바뀔경우 상시업데이트인덱스를 setter에서 초기화한다.
        /// </summary>
        public string mPlatformGameID
        {
            get
            {
                lock (mDataAccessObjectLocker)
                {
                    return platformGameID;
                }
            }

            set
            {

                lock (mDataAccessObjectLocker)
                {
                    foreach (ARequestData item in mRequestDataList)
                    {
                        item.initIndex();
                    }

                    platformGameID = value;

                }

            }
        }

        public int 리퀘스트인터벌밀리초 = 400;





        /// <summary>
        /// 라이브로 연결해서 나갈 데이터를 파싱해서 리턴한다.
        /// </summary>
        /// <param name="요청데이터타입"></param>
        /// <returns></returns>
        public DataSet 라이브데이터요청(DBDefine.요청데이터분류 요청데이터타입)
        {

            IResponseData bufInstance = null;

            DataSet rtnValue = new DataSet();

            try
            {

                switch (요청데이터타입)
                {
                    case DBDefine.요청데이터분류.밴데이터:
                        bufInstance = new ResponseData.밴데이터();
                        break;
                    case DBDefine.요청데이터분류.팟지:
                        bufInstance = new ResponseData.팟지선수();
                        break;
                    case DBDefine.요청데이터분류.픽데이터:
                        bufInstance = new ResponseData.픽데이터();
                        break;
                    case DBDefine.요청데이터분류.현재골드량선수:
                        bufInstance = new ResponseData.골드획득량선수();
                        break;
                    case DBDefine.요청데이터분류.현재데미지량선수:
                        bufInstance = new ResponseData.누적데미지선수();
                        break;
                    case DBDefine.요청데이터분류.경험치레벨:
                        bufInstance = new ResponseData.경험치레벨선수();
                        break;
                    case DBDefine.요청데이터분류.룬데이터:
                        bufInstance = new ResponseData.룬데이터();
                        break;
                    case DBDefine.요청데이터분류.오브젝트킬:
                        bufInstance = new ResponseData.오브젝트킬전체(false);
                        break;
                    case DBDefine.요청데이터분류.골드차이팀:
                        bufInstance = new ResponseData.골드차이팀();
                        break;
                    case DBDefine.요청데이터분류.타워철거전체:
                        bufInstance = new ResponseData.타워파괴전체();
                        break;
                    case DBDefine.요청데이터분류.타워골드데이터:
                        bufInstance = new ResponseData.타워골드데이터();
                        break;
                    case DBDefine.요청데이터분류.용리스폰:
                        bufInstance = new ResponseData.용데이터();
                        break;
                    //case DBDefine.요청데이터분류.아타칸리스폰:
                    //    bufInstance = new ResponseData.아타칸데이터();
                    //    break;
                    case DBDefine.요청데이터분류.퀘스트완료여부:
                        bufInstance = new ResponseData.퀘스트완료여부();
                        break;
                    case DBDefine.요청데이터분류.킬뎃어시:
                        bufInstance = new ResponseData.KDA선수();
                        break;
                    case DBDefine.요청데이터분류.경기종료정보:

                        IResponseData bufGameEndData = new ResponseData.경기종료정보();

                        DataTable bufResult = bufGameEndData.디비데이터를데이터테이블로만듬();

                        if (bufResult == null || bufResult.Rows.Count == 0)
                        {
                            return rtnValue;
                        }
                        else
                        {
                            rtnValue.Tables.Add(bufResult);
                        }

                        IResponseData bufKDAData = new ResponseData.KDA선수();
                        rtnValue.Tables.Add(bufKDAData.디비데이터를데이터테이블로만듬());

                        IResponseData bufTowerData = new ResponseData.타워파괴전체();
                        rtnValue.Tables.Add(bufTowerData.디비데이터를데이터테이블로만듬());

                        IResponseData bufTowerGoldData = new ResponseData.타워골드데이터();
                        rtnValue.Tables.Add(bufTowerGoldData.디비데이터를데이터테이블로만듬());

                        IResponseData bufObjectData = new ResponseData.오브젝트킬전체(true);
                        rtnValue.Tables.Add(bufObjectData.디비데이터를데이터테이블로만듬());

                        IResponseData bufBanData = new ResponseData.밴데이터();
                        rtnValue.Tables.Add(bufBanData.디비데이터를데이터테이블로만듬());

                        IResponseData bufDamageData = new ResponseData.누적데미지선수();
                        rtnValue.Tables.Add(bufDamageData.디비데이터를데이터테이블로만듬());

                        IResponseData bufGoldTeamData = new ResponseData.골드차이팀();
                        rtnValue.Tables.Add(bufGoldTeamData.디비데이터를데이터테이블로만듬());

                        return rtnValue;

                }

                rtnValue.Tables.Add(bufInstance.디비데이터를데이터테이블로만듬());

                return rtnValue;

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                DataSet ddd = new DataSet();
                ddd.Tables.Add(new DataTable("데이터없음"));
                return ddd;
            }



        }

        public DataSet 한타딜량요청(int 시작초, int 종료초)
        {
            if (시작초 == 0)
            {
                return null;
            }

            IResponseData bufInstance = new ResponseData.한타딜량범위(시작초, 종료초);

            DataSet rtnValue = new DataSet();

            rtnValue.Tables.Add(bufInstance.디비데이터를데이터테이블로만듬());

            return rtnValue;

        }

        #region 서버와의통신부분

        public void requestServerForUpdateRemoveAll(string serverIP)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
               "http://" + serverIP + ":60003/"
               + "RemoveAll");
            request.Method = "GET";
            request.Timeout = 30 * 1000; 
            try
            {

                using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
                {

                    lock (mDataAccessObjectLocker)
                    {
                        foreach (ARequestData item in mRequestDataList)
                        {
                            item.initIndex();
                        }
                    } 
                    HttpStatusCode status = resp.StatusCode;  

                    Stream respStream = resp.GetResponseStream();
                    using (StreamReader sr = new StreamReader(respStream))
                    { 
                    }

                } 

            }
            catch (Exception)
            { 
            }
        }

        public string requestServerForGameInfo(string serverIP)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
                "http://" + serverIP + ":60003/GameInfoGet");
            request.Method = "GET";
            request.Timeout = 30 * 1000;

            string responseText = "";
            try
            {

                using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
                { 

                    HttpStatusCode status = resp.StatusCode;

                    //Console.WriteLine(status);  // 정상이면 "OK"


                    Stream respStream = resp.GetResponseStream();
                    using (StreamReader sr = new StreamReader(respStream))
                    {
                        responseText = sr.ReadToEnd();
                    }

                }
                
                if (responseText.Contains(Environment.NewLine))
                {
                    return responseText;
                }

            }
            catch (Exception)
            {  
            }

            return "";
        }

        public DBDefine.서버의답변 requestServerForUpdateGameKey(string serverIP, string gameKey, bool isTest)
        {

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
                "http://" + serverIP + ":60003/"
                + (isTest ? "TEST" : "REAL")
                + ("/ConnectionGameKey")
                + ":" + gameKey);
            request.Method = "GET";
            request.Timeout = 30 * 1000;

            string responseText = "";
            try
            {

                using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
                {

                    lock (mDataAccessObjectLocker)
                    {
                        foreach (ARequestData item in mRequestDataList)
                        {
                            item.initIndex();
                        }
                    }


                    HttpStatusCode status = resp.StatusCode;

                    //Console.WriteLine(status);  // 정상이면 "OK"


                    Stream respStream = resp.GetResponseStream();
                    using (StreamReader sr = new StreamReader(respStream))
                    {
                        responseText = sr.ReadToEnd();
                    }

                }

                string[] responseServerData = responseText.Split('_');

                string statusServer = responseServerData[0];
                if (statusServer == "1")
                {

                    mPlatformGameID = responseServerData[1] + "_" + responseServerData[2];
                    return DBDefine.서버의답변.방을찾았고업데이트를시작함;

                }
                else if (statusServer == "2")
                {
                    mPlatformGameID = responseServerData[1] + "_" + responseServerData[2];
                    return DBDefine.서버의답변.이미방을업데이트중임;
                }
                else if (statusServer == "3")
                {
                    return DBDefine.서버의답변.방을못찾아서업데이트를못함;
                }
                else if (statusServer == "4")
                {
                    return DBDefine.서버의답변.명령이틀림;
                }

                return DBDefine.서버의답변.서버와의연결이이상함;

            }
            catch (Exception)
            {

                return DBDefine.서버의답변.서버와의연결이이상함;
            }

        }


        public DBDefine.서버의답변 requestServerForUpdate(string serverIP, string gameName, bool isTest)
        {
            

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
                "http://" + serverIP + ":60003/"
                + (isTest ? "TEST" : "REAL")
                + ":" + gameName);
            request.Method = "GET";
            request.Timeout = 30 * 1000;

            string responseText = "";
            try
            {

                using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
                {

                    lock (mDataAccessObjectLocker)
                    {
                        foreach (ARequestData item in mRequestDataList)
                        {
                            item.initIndex();
                        }
                    }


                    HttpStatusCode status = resp.StatusCode;

                    //Console.WriteLine(status);  // 정상이면 "OK"


                    Stream respStream = resp.GetResponseStream();
                    using (StreamReader sr = new StreamReader(respStream))
                    {
                        responseText = sr.ReadToEnd();
                    }

                }

                string[] responseServerData = responseText.Split('_');

                string statusServer = responseServerData[0];
                if (statusServer == "1")
                {

                    mPlatformGameID = responseServerData[1] + "_" + responseServerData[2];
                    return DBDefine.서버의답변.방을찾았고업데이트를시작함;

                }
                else if (statusServer == "2")
                {
                    mPlatformGameID = responseServerData[1] + "_" + responseServerData[2];
                    return DBDefine.서버의답변.이미방을업데이트중임;
                }
                else if (statusServer == "3")
                {
                    return DBDefine.서버의답변.방을못찾아서업데이트를못함;
                }
                else if (statusServer == "4")
                {
                    return DBDefine.서버의답변.명령이틀림;
                }

                return DBDefine.서버의답변.서버와의연결이이상함;

            }
            catch (Exception)
            {

                return DBDefine.서버의답변.서버와의연결이이상함;
            }

        }

        #endregion

        #region 게임타이머관련

        /*0603 라이브게임 타이머 개발
         * 
         * Form Timer로 진행시에 UI스레드에서 밀리는 현상이 발생할때 대책이 없다. 
         * 
         * 
         * 따라서 따로 SystemTimer를 사용해서 초가 바뀔경우에 Data를 Interface로 드롭하는 방식을 사용한다.
         * 
         */

        /// <summary>
        /// 경기시간을 스레드로 보호하기위한 Locker
        /// </summary>
        private static object gameTimeLocker = new object();

        /// <summary>
        /// 경기시간(초)
        /// </summary>
        internal int mGameTime = 0;


        /// <summary>
        /// 경기시간(초) 게터세터
        /// </summary>
        internal int 경기시간
        {
            get
            {

                lock (gameTimeLocker)
                {
                    return mGameTime;
                }

            }
            set
            {

                lock (gameTimeLocker)
                {
                    mGameTime = value;
                }

            }
        }

        System.Timers.Timer m라이브시간계산용타이머 = new System.Timers.Timer();

        /// <summary>
        /// 시간 이벤트 콜백
        /// </summary>
        IGameTimeEventDrop mCallback = null;

        public void setCallback(IGameTimeEventDrop recvCallback)
        {
            this.mCallback = recvCallback;
        }

        DateTime lastUpdateTime = new DateTime();

        public void timerStart()
        {

            if (m라이브시간계산용타이머.Enabled)
            {
                m라이브시간계산용타이머.Stop();
                m라이브시간계산용타이머.Elapsed -= timerTick;
            }

            lastUpdateTime = DateTime.Now;
            m라이브시간계산용타이머 = new System.Timers.Timer();
            m라이브시간계산용타이머.Interval = 300;
            m라이브시간계산용타이머.Elapsed += timerTick;
            m라이브시간계산용타이머.Start();
        }

        public void timerStop()
        {
            if (m라이브시간계산용타이머.Enabled)
            {
                m라이브시간계산용타이머.Stop();
                m라이브시간계산용타이머.Elapsed -= timerTick;
            }
        }

        public void setGameTime(int 초)
        {
            경기시간 = 초;
        }

        void timerTick(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (lastUpdateTime.AddSeconds(1) < DateTime.Now)
            {
                lastUpdateTime = lastUpdateTime.AddSeconds(1);
                경기시간 += 1;
                eventTimerWork();
                if (mCallback != null)
                {
                    mCallback.현재게임시간(경기시간);
                }
            }

        }

        void eventTimerWork()
        {
            try
            {
                ThreadPool.QueueUserWorkItem(o => 오브젝트체크());
                ThreadPool.QueueUserWorkItem(o => 드래곤체크());
                //ThreadPool.QueueUserWorkItem(o => 아타칸체크());
                ThreadPool.QueueUserWorkItem(o => 억제기체크());
                ThreadPool.QueueUserWorkItem(o => 한타딜량());
                ThreadPool.QueueUserWorkItem(o => 라인퀘스트체크());
            }
            catch(Exception ex) { } 
        }

        private readonly Dictionary<int, bool> _roleBoundQuestCompleteCache = new Dictionary<int, bool>();
        void 라인퀘스트체크()
        {
            try
            {
                DataTable dataTable = 라이브데이터요청(DBDefine.요청데이터분류.퀘스트완료여부).Tables[DBDefine.요청데이터분류.퀘스트완료여부.GetStringValue()];

                mCallback.라인퀘스트정보(dataTable);
            }
            catch(Exception ex)
            {

            } 
           
        }
         

        public void 초당한타딜량리턴시작()
        {
            is한타딜량체크 = true;
        }

        public void 초당한타딜량리턴종료()
        {
            is한타딜량체크 = false;
        }

        private bool is한타딜량체크 = false;

        private DataTable 한타초기딜량 = null;

        int 엘더파워플레이시작차이 = 0;
        int 바론파워플레이시작차이 = 0;

        void 오브젝트체크()
        {

            DataTable 오브젝트데이터 = 라이브데이터요청(DBDefine.요청데이터분류.오브젝트킬).Tables[DBDefine.요청데이터분류.오브젝트킬.GetStringValue()];

            IEnumerable<DataRow> 전령스폰데이터 = null;

            IEnumerable<DataRow> 바론스폰데이터 = null;

            IEnumerable<DataRow> 엘더드래곤데이터 = null;

            IEnumerable<DataRow> 공허유충데이터 = null;

            //IEnumerable<DataRow> 아타칸데이터 = null;


            if (오브젝트데이터 != null)
            {
                전령스폰데이터 = 오브젝트데이터
                .AsEnumerable().Where(r => r.Field<string>("오브젝트타입").Contains("riftHerald"));

                바론스폰데이터 = 오브젝트데이터
                .AsEnumerable().Where(r => r.Field<string>("오브젝트타입").Contains("baron"));

                엘더드래곤데이터 = 오브젝트데이터
                .AsEnumerable().Where(r => r.Field<string>("오브젝트타입").Contains("dragon") && r.Field<string>("드래곤종류").Contains("elder"));

                공허유충데이터 = 오브젝트데이터
                .AsEnumerable().Where(r => r.Field<string>("오브젝트타입").Contains("VoidGrub"));
                 
                //아타칸데이터 = 오브젝트데이터
                //.AsEnumerable().Where(r => r.Field<string>("오브젝트타입").Contains("Atakhan")); 
            }

            if (엘더드래곤데이터.Count() != 0)
            {
                foreach (DataRow item in 엘더드래곤데이터)
                {
                    int 젠타임 = (Convert.ToInt32(item["킬시간"]) / 1000) + 360 - 경기시간;

                    if (젠타임 >= 210 && 젠타임 < 361)
                    {

                        if (젠타임 == 360)
                        {
                            엘더파워플레이시작차이 = getGoldGapForPowerPlay((DBDefine.팀구분)((item["잡은팀"].ToString() == "블루") ? 100 : 200), 경기시간);
                        }
                        else if (젠타임 < 210)
                        {
                            엘더파워플레이시작차이 = 0;
                        }

                        if (mCallback != null)
                        {
                            mCallback.오브젝트버프시간(item["잡은팀"].ToString(), "elder", 젠타임 - 210, getGoldGapForPowerPlay((DBDefine.팀구분)((item["잡은팀"].ToString() == "블루") ? 100 : 200), 경기시간) - 엘더파워플레이시작차이);
                        }

                    }

                }
            }

            //전령처리
            if (900 - 경기시간 >= 0)
            {
                if (mCallback != null)
                {
                    mCallback.오브젝트리스폰시간("첫전령", "riftHerald", 900 - 경기시간);
                }
            }
            ////아타칸
            //if (1200 - 경기시간 >= 0)
            //{
            //    if (mCallback != null)
            //    {
            //        mCallback.오브젝트리스폰시간("아타칸", "atakhan", 1200 - 경기시간);
            //    }
            //}
            ////아타칸 잡은 정보
            //if (아타칸데이터.Count() > 0)
            //{
            //    foreach (DataRow item in 아타칸데이터)
            //    {
            //        if (mCallback != null)
            //        {
            //            int 킬시간 = Convert.ToInt32(item["킬시간"]) / 1000;
            //            if (킬시간 - 경기시간 <=5 && 킬시간 - 경기시간 >= -5)
            //            {
            //                mCallback.오브젝트리스폰시간(item["잡은팀"].ToString(), item["오브젝트타입"].ToString(), 킬시간);
            //            }
                        
            //        }
            //    }
            //}
            /*
            if (전령스폰데이터.Count() == 0)
            {
               
            }
            else if (전령스폰데이터.Count() == 1)
            { 
                foreach (DataRow item in 전령스폰데이터)
                {

                    int 젠타임 = (Convert.ToInt32(item["킬시간"]) / 1000) + 360 - 경기시간;

                    if (젠타임 >= 0 && 젠타임 < 361)
                    {
                        if (mCallback != null)
                        {
                            mCallback.오브젝트리스폰시간(item["잡은팀"].ToString(), "riftHerald", 젠타임);
                        }
                    }

                } 
            } 
            */


            //바론처리
            if (1200 - 경기시간 >= 0)
            {
                if (mCallback != null)
                { 
                    mCallback.오브젝트리스폰시간("첫바론", "baron", 1200 - 경기시간);
                }
            }
            else
            {
                foreach (DataRow item in 바론스폰데이터)
                {
                    /*
                    int 젠타임 = (Convert.ToInt32(item["킬시간"]) / 1000) + 360 - 경기시간;

                    if (젠타임 >= 0 && 젠타임 < 361)
                    {
                        if (mCallback != null)
                        {
                            mCallback.오브젝트리스폰시간(item["잡은팀"].ToString(), item["오브젝트타입"].ToString(), 젠타임);
                        }
                    }

                    if (젠타임 >= 180 && 젠타임 < 361)
                    {

                        if (젠타임 == 360)
                        {
                            바론파워플레이시작차이 = getGoldGapForPowerPlay((DBDefine.팀구분)((item["잡은팀"].ToString() == "블루") ? 100 : 200), 경기시간);
                        }
                        else if (젠타임 < 180)
                        {
                            바론파워플레이시작차이 = 0;
                        }

                        if (mCallback != null)
                        {
                            mCallback.오브젝트버프시간(item["잡은팀"].ToString(), "baron", 젠타임 - 180, getGoldGapForPowerPlay((DBDefine.팀구분)((item["잡은팀"].ToString() == "블루") ? 100 : 200), 경기시간) - 바론파워플레이시작차이);

                        }

                    }
                    */
                    int 젠타임 = (Convert.ToInt32(item["킬시간"]) / 1000) + 360 - 경기시간;

                    if (젠타임 >= 0 && 젠타임 < 361)
                    {
                        if (mCallback != null)
                        {
                            mCallback.오브젝트리스폰시간(item["잡은팀"].ToString(), item["오브젝트타입"].ToString(), 젠타임);
                        }
                    }

                    if (젠타임 >= 180 && 젠타임 < 361)
                    {

                        if (젠타임 == 360)
                        {
                            바론파워플레이시작차이 = getGoldGapForPowerPlay((DBDefine.팀구분)((item["잡은팀"].ToString() == "블루") ? 100 : 200), 경기시간);
                        }
                        else if (젠타임 < 180)
                        {
                            바론파워플레이시작차이 = 0;
                        }

                        if (mCallback != null)
                        {
                            mCallback.오브젝트버프시간(item["잡은팀"].ToString(), "baron", 젠타임 - 180, getGoldGapForPowerPlay((DBDefine.팀구분)((item["잡은팀"].ToString() == "블루") ? 100 : 200), 경기시간, Convert.ToInt32(item["킬시간"]) / 1000));

                        }

                    }



                }
            }


            //아타칸처리
            /*
            if (아타칸데이터.Count() == 0)
            {

            }
            else
            {
                foreach (DataRow item in 아타칸데이터)
                {
                    if (mCallback != null)
                    {
                        mCallback.오브젝트리스폰시간("아타칸", item["오브젝트타입"].ToString(), 360 - 경기시간);
                    }                        
                }
            }
            */
          
            //공허유충시간
            if (공허유충데이터.Count() < 3)
            {
                if (480 - 경기시간 >= 0)
                {
                    if (mCallback != null)
                    {
                        mCallback.오브젝트리스폰시간("첫유충", "horde", 480 - 경기시간);
                    }
                }
            }
            if (공허유충데이터.Count() > 0)
            {
                int 블루팀공허유충 = 0;
                int 레드팀공허유충 = 0;

                if (공허유충데이터.Count() == 3)
                {
                    /*
                    int 젠타임 = -1;

                    foreach (DataRow item in 공허유충데이터)
                    {
                        int 젠타임체크 = (Convert.ToInt32(item["킬시간"]) / 1000) + 240 - 경기시간;

                        if (젠타임체크 > 젠타임) 젠타임 = 젠타임체크;
                    }

                    if (젠타임 >= 0 && 젠타임 < 241)
                    {
                        if (mCallback != null)
                        {
                            mCallback.오브젝트리스폰시간("", "horde", 젠타임);
                        }
                    }
                    */
                }
                foreach (DataRow item in 공허유충데이터)
                {
                    if (item["잡은팀"].ToString() == "블루") 블루팀공허유충++;
                    else 레드팀공허유충++;
                }

                if (mCallback != null)
                {
                    mCallback.공허유충정보(블루팀공허유충, 레드팀공허유충);
                }
            }
                


            
        }

        void 드래곤체크()
        {
            DataTable dragonSpawnData = 라이브데이터요청(DBDefine.요청데이터분류.용리스폰).Tables[DBDefine.요청데이터분류.용리스폰.GetStringValue()];

            foreach (DataRow item in dragonSpawnData.Rows)
            {

                int 젠타임 = Convert.ToInt32(item["리스폰타임"]) - 경기시간;

                int 오버되는젠타임 = (item["용정보"].ToString() == "elder" ? 361 : 301);


                if (젠타임 >= 0 && 젠타임 < 오버되는젠타임)
                {
                    if (mCallback != null)
                    {
                        mCallback.드래곤리스폰시간(item["용정보"].ToString(), 젠타임);
                    }
                }
                else if (젠타임 >= 0)//이상상황이므로 라이브로 추정
                {
                    if (mCallback != null)
                    {
                        mCallback.드래곤리스폰시간(item["용정보"].ToString(), 0);
                    }
                }
            }

        }

        //void 아타칸체크()
        //{
        //    DataTable atakhanSpawnData = 라이브데이터요청(DBDefine.요청데이터분류.아타칸리스폰).Tables[DBDefine.요청데이터분류.아타칸리스폰.GetStringValue()];

        //    int 인덱스값 = 0;
        //    string rtnValue = "";
            
        //    foreach (DataRow item in atakhanSpawnData.Rows)
        //    {
        //        if (인덱스값 < Convert.ToInt32(item["리스폰타임"]))
        //        {
        //            인덱스값 = Convert.ToInt32(item["리스폰타임"]);
        //            rtnValue = item["아타칸정보"].ToString();
        //        }
        //    }

        //    if (atakhanSpawnData.Rows.Count > 0)
        //    {
        //        if (mCallback != null)
        //        {
        //            mCallback.아타칸리스폰정보(rtnValue, 인덱스값);
        //        }
        //    }

        //}

        void 억제기체크()
        {
            try
            {

                IEnumerable<DataRow> 가져온정보 = 라이브데이터요청(DBDefine.요청데이터분류.타워철거전체).Tables[DBDefine.요청데이터분류.타워철거전체.GetStringValue()].AsEnumerable()
                                                    .Where(r => r.Field<string>("타워종류").Contains("inhibitor") || (r.Field<string>("타워종류").Contains("turret") && r.Field<string>("터렛티어").Contains("nexus")));

                if (가져온정보.Count() == 0)
                {
                    return;
                }

                DataTable 억제기데이터 = 가져온정보.CopyToDataTable();

                DataTable 억제기리스폰정보 = new DataTable();

                억제기리스폰정보.Columns.Add("타워부서진팀");
                억제기리스폰정보.Columns.Add("파괴된라인");
                억제기리스폰정보.Columns.Add("넥서스타워");
                억제기리스폰정보.Columns.Add("타워위치");
                억제기리스폰정보.Columns.Add("남은시간(초)");

                foreach (DataRow item in 억제기데이터.Rows)
                {
                    
                    int 젠타임 = Convert.ToInt32(item["경기시간(초)"]) + 300 - 경기시간;

                    if (item["타워종류"].ToString() == "turret")
                    {
                        젠타임 = Convert.ToInt32(item["경기시간(초)"]) + 180 - 경기시간;

                        if (젠타임 >= 0 && 젠타임 < 181)
                        {
                            DataRow bufRow = 억제기리스폰정보.NewRow();

                            bufRow["타워부서진팀"] = item["타워부서진팀"].ToString();
                            bufRow["파괴된라인"] = item["파괴된라인"].ToString();
                            bufRow["남은시간(초)"] = 젠타임;
                            bufRow["넥서스타워"] = item["넥서스타워"].ToString();
                            bufRow["타워위치"] = item["타워위치"].ToString();


                            억제기리스폰정보.Rows.Add(bufRow);
                        }
                    }
                    else
                    {
                        if (젠타임 >= 0 && 젠타임 < 301)
                        {
                            DataRow bufRow = 억제기리스폰정보.NewRow();

                            bufRow["타워부서진팀"] = item["타워부서진팀"].ToString();
                            bufRow["파괴된라인"] = item["파괴된라인"].ToString();
                            bufRow["남은시간(초)"] = 젠타임;
                            bufRow["넥서스타워"] = "";
                            bufRow["타워위치"] = ""; 

                            억제기리스폰정보.Rows.Add(bufRow);
                        }
                    }
                    
                }

                if (mCallback != null && 억제기리스폰정보.Rows.Count != 0)
                {
                    mCallback.억제기리스폰시간(억제기리스폰정보);
                }

            }
            catch (Exception ex) { }
            
        }

        void 한타딜량()
        {
            if (is한타딜량체크)
            {
                getDamageDealtForTeamFight(경기시간);

                if (mCallback != null)
                {
                    mCallback.한타딜량실시간(한타초기딜량);
                }
            }
            else
            {
                한타초기딜량 = null;
            }
        }


        int getGoldGapForPowerPlay(DBDefine.팀구분 오브젝트잡은팀, int 가져온초, int 킬시간)
        {
            int rtnValue = 0;

            //var subfilter1 = Builders<BsonDocument>.Filter.Eq("RequestGameID", DataManager.getInstance().mPlatformGameID);

            var subFilter2NowTime = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{'eventDocument.gameTime' : {$gt : " + (킬시간 - 1) * 1000 + ", $lt : " + 가져온초 * 1000 + "}}");

            //var subFilter2KillTime = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{'eventDocument.gameTime' : {$lt : " + (킬시간 - 1) * 1000 + " }}");

            //var filter1NowTime = Builders<BsonDocument>.Filter.And(subfilter1, subFilter2NowTime);
            var filter1NowTime = Builders<BsonDocument>.Filter.And(subFilter2NowTime);

            //var filter1KillTime = Builders<BsonDocument>.Filter.And(subfilter1, subFilter2KillTime);

            var projectionFilter = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{'eventDocument.teams' : 1 , 'eventDocument.gameTime' : 1 }");

            /*List<BsonDocument> 바론킬시점documents = mDBClient.GetDatabase("datalol").GetCollection<BsonDocument>("stats_update")
                .Find(filter1KillTime)
                .Project(projectionFilter)
                .SortByDescending(x => x["sequenceIndex"])
                .Limit(1)
                .ToList();

            List<BsonValue> 킬시점가져온팀데이터들 = 바론킬시점documents.Last()["eventDocument"].AsBsonDocument["teams"].AsBsonArray.ToList();

            int 킬시점블루팀골드 = 킬시점가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.블루).ToList().Last()["totalGold"].ToInt32();
            int 킬시점레드팀골드 = 킬시점가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.퍼플).ToList().Last()["totalGold"].ToInt32();

            int 잡은시점골드차 = 0;

            if (오브젝트잡은팀 == DBDefine.팀구분.블루)
            {
                잡은시점골드차 = 블루팀골드 - 레드팀골드;
            }
            else
            {
                잡은시점골드차 = 레드팀골드 - 블루팀골드;
            }
            */

            List<BsonDocument> 현재시점documents = mDBClient.GetDatabase("datalol").GetCollection<BsonDocument>("stats_update")
                .Find(filter1NowTime)
                .Project(projectionFilter)
                .SortByDescending(x => x["sequenceIndex"])
                .ToList();

            if (현재시점documents.Count > 2)
            {
                List<BsonValue> 현재시점가져온팀데이터들 = 현재시점documents.First()["eventDocument"].AsBsonDocument["teams"].AsBsonArray.ToList();
                List<BsonValue> 바론킬가져온팀데이터들 = 현재시점documents.Last()["eventDocument"].AsBsonDocument["teams"].AsBsonArray.ToList();


                int 현재블루팀골드 = 현재시점가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.블루).ToList().Last()["totalGold"].ToInt32();
                int 현재레드팀골드 = 현재시점가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.퍼플).ToList().Last()["totalGold"].ToInt32();
                int 바론킬블루팀골드 = 바론킬가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.블루).ToList().Last()["totalGold"].ToInt32();
                int 바론킬레드팀골드 = 바론킬가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.퍼플).ToList().Last()["totalGold"].ToInt32();

                int 현재골드차 = 0;
                int 킬시점골드차 = 0;

                if (오브젝트잡은팀 == DBDefine.팀구분.블루)
                {
                    현재골드차 = 현재블루팀골드 - 현재레드팀골드;
                    킬시점골드차 = 바론킬블루팀골드 - 바론킬레드팀골드;
                }
                else
                {
                    현재골드차 = 현재레드팀골드 - 현재블루팀골드;
                    킬시점골드차 = 바론킬레드팀골드 - 바론킬블루팀골드;
                }

                rtnValue = 현재골드차 - 킬시점골드차;
            }
            else if (현재시점documents.Count == 1)
            {

            }
            else
            {

            }


            return rtnValue;

        }

        int getGoldGapForPowerPlay(DBDefine.팀구분 오브젝트잡은팀, int 가져온초)
        {
            int rtnValue = 0;

            //var subfilter1 = Builders<BsonDocument>.Filter.Eq("RequestGameID", DataManager.getInstance().mPlatformGameID);

            var subFilter2 = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{'eventDocument.gameTime' : {$lt : " + 가져온초 * 1000 + " }}");

            var filter1 = Builders<BsonDocument>.Filter.And(subFilter2); //var filter1 = Builders<BsonDocument>.Filter.And(subfilter1, subFilter2);

            var projectionFilter = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{'eventDocument.teams' : 1 , 'eventDocument.gameTime' : 1 }");

            List<BsonDocument> documents = mDBClient.GetDatabase("datalol").GetCollection<BsonDocument>("stats_update")
                .Find(filter1)
                .Project(projectionFilter)
                .SortByDescending(x => x["sequenceIndex"])
                .Limit(1)
                .ToList();

            List<BsonValue> 가져온팀데이터들 = documents.Last()["eventDocument"].AsBsonDocument["teams"].AsBsonArray.ToList();

            int 블루팀골드 = 가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.블루).ToList().Last()["totalGold"].ToInt32();
            int 레드팀골드 = 가져온팀데이터들.Where(o => o["teamID"] == (int)DBDefine.팀구분.퍼플).ToList().Last()["totalGold"].ToInt32();

            if (오브젝트잡은팀 == DBDefine.팀구분.블루)
            {
                rtnValue = 블루팀골드 - 레드팀골드;
            }
            else
            {
                rtnValue = 레드팀골드 - 블루팀골드;
            }

            return rtnValue;

        }

        void getDamageDealtForTeamFight(int 가져온초)
        {

            //var subfilter1 = Builders<BsonDocument>.Filter.Eq("RequestGameID", DataManager.getInstance().mPlatformGameID);

            var subFilter2 = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{'eventDocument.gameTime' : {$lt : " + 가져온초 * 1000 + " }}");

            var filter1 = Builders<BsonDocument>.Filter.And(subFilter2); //var filter1 = Builders<BsonDocument>.Filter.And(subfilter1, subFilter2);

            var projectionFilter = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>("{'eventDocument.participants' : 1 , 'eventDocument.gameTime' : 1 }");

            List<BsonDocument> documents = mDBClient.GetDatabase("datalol").GetCollection<BsonDocument>("stats_update")
                .Find(filter1)
                .Project(projectionFilter)
                .SortByDescending(x => x["sequenceIndex"])
                .Limit(1)
                .ToList();

            List<BsonValue> 가져온팀데이터들 = documents.Last()["eventDocument"].AsBsonDocument["participants"].AsBsonArray.ToList();

            if (한타초기딜량 == null)
            {

                한타초기딜량 = new DataTable();

                한타초기딜량.Columns.Add("팀");
                한타초기딜량.Columns.Add("아이디");
                한타초기딜량.Columns.Add("챔피언");
                한타초기딜량.Columns.Add("최초딜량");
                한타초기딜량.Columns.Add("현재딜량");
                한타초기딜량.Columns.Add("딜량차이");
                한타초기딜량.Columns.Add("딜량백분율");
                한타초기딜량.Columns.Add("생존여부");

                foreach (BsonValue item in 가져온팀데이터들)
                {

                    DataRow bufRow = 한타초기딜량.NewRow();

                    bufRow["팀"] = (DBDefine.팀구분)item["teamID"].ToInt32();
                    bufRow["아이디"] = item["playerName"].ToString();
                    bufRow["챔피언"] = item["championName"].ToString();
                    bufRow["생존여부"] = item["alive"].ToBoolean();
                    bufRow["딜량차이"] = 0;
                    bufRow["딜량백분율"] = 0;
                    bufRow["최초딜량"] = item["stats"].AsBsonArray.Where(r => r["name"] == "TOTAL_DAMAGE_DEALT_TO_CHAMPIONS").Last()["value"];
                    bufRow["현재딜량"] = item["stats"].AsBsonArray.Where(r => r["name"] == "TOTAL_DAMAGE_DEALT_TO_CHAMPIONS").Last()["value"];

                    한타초기딜량.Rows.Add(bufRow);

                }

            }
            else
            {
                foreach (BsonValue item in 가져온팀데이터들)
                {

                    DataRow bufRow = 한타초기딜량.AsEnumerable().Where(r => r.Field<string>("아이디") == item["playerName"].ToString()).Last();

                    bufRow["현재딜량"] = item["stats"].AsBsonArray.Where(r => r["name"] == "TOTAL_DAMAGE_DEALT_TO_CHAMPIONS").Last()["value"];
                    bufRow["생존여부"] = item["alive"].ToBoolean();
                    bufRow["딜량차이"] = Convert.ToDouble(bufRow["현재딜량"]) - Convert.ToDouble(bufRow["최초딜량"]);
                }

                double 최대딜량 = Convert.ToDouble(한타초기딜량.AsEnumerable().OrderByDescending(r => Convert.ToDouble(r.Field<string>("딜량차이"))).First()["딜량차이"]);

                foreach (DataRow item in 한타초기딜량.Rows)
                {
                    double 딜량차이값 = Convert.ToDouble(item["딜량차이"]);

                    if (딜량차이값 != 0)
                    {
                        item["딜량백분율"] = 딜량차이값 / 최대딜량 * 100.0;
                    }
                    else
                    {
                        item["딜량백분율"] = 0.0;
                    }
                }



            }

        }


        #endregion


    }
}
