//ライセンス情報はAgeOnフォルダのLISENCEフォルダを参照してください
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;
using System.Net;
using System.IO;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;

namespace nispi
{
    /// <summary>
    /// 最新の生存スレッドに関して整理して作成した画像を返す
    /// また、１日前のログに関しては変動しないと考えられるので作成した画像を保存し、
    /// 要求に合わせて画像を読み込んで返す
    /// </summary>
    /// 

    class MarkPointInfo
    {
        public List<Point> list;
        public byte powerNum;

        public MarkPointInfo(List<Point> list, byte powerNum)
        {
            this.list = list.ToList();
            this.powerNum = powerNum;
        }
    }

    class FillPointInfo
    {
        public List<Point> list;
        public byte powerNum;

        public FillPointInfo(List<Point> list, byte powerNum)
        {
            this.list = list.ToList();
            this.powerNum = powerNum;
        }
    }

    class GetScreeningImage : DrawToMap
    {
        Bitmap drawnImage;
        string frontFile;
        Object thisLock = new Object();
        string fileName;

        PlusTime plusTime = null;
        string withInTime = "";
        string withInFileName = "";
        string withInInfoFileName = "";


        Bitmap fillImage;
        Bitmap pointImage;

        Dictionary<string, KokkaData> nameDic;
        Dictionary<string, KokkaData> colorDic;

        //時間抽出関係
        public int containKakoLog = 0;
        public int withInNum = 0;
        public string pinPointData = "";
        public string pinPointJPDate = "";

        public GetScreeningImage(string frontFile, string fileName, Dictionary<string, KokkaData> nameDic, Dictionary<string, KokkaData> colorDic)
        {
            this.frontFile = frontFile;
            this.fileName = fileName;
            this.nameDic = nameDic;
            this.colorDic = colorDic;
        }

        //解析範囲を時間指定する場合のメソッド
        public BitmapSets GetSurviveThreadImage(int containKakoLog, PlusTime plusTime, string pinPointData)
        {

            this.containKakoLog = containKakoLog;
            this.plusTime = plusTime;
            this.pinPointData = pinPointData;

            if (this.plusTime != null)
            {
                //plusTime = this.GetHourByNum(withInNum);
                //ファイルの基準でUnix時間を得る
                withInTime = UnixTime.GetUnixTimeByPlusTime(plusTime).ToString();
                //範囲から最大の日にちのファイル名を得る
                withInFileName = UnixTime.GetFileNameByPlusTime(plusTime);
                //インフォファイルを得る
                withInInfoFileName = UnixTime.GetInfoFileNameByPlusTime(plusTime);
            }
            else if (this.pinPointData.Length > 0)
            {
                withInFileName = this.pinPointData + ".txt";
                withInInfoFileName = this.pinPointData + ".info.txt";
            }

            drawnImage = new Bitmap(
                Const.CurrentDir + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + this.frontFile);
            fillImage = new Bitmap(drawnImage);
            Thread t = new Thread(new ThreadStart(Draw));
            t.IsBackground = true;
            t.Start();

            t.Join();

            BitmapSets bitmapSets;
            if ((fillImage != null) && (pointImage != null) && (drawnImage != null))
                bitmapSets = new BitmapSets(fillImage, pointImage, drawnImage);
            else
                bitmapSets = null;
            return bitmapSets;
        }
        //全生存ファイルが解析対象の場合のメソッド
        public BitmapSets GetSurviveThreadImage()
        {
            drawnImage = new Bitmap(Const.CurrentDir + Path.DirectorySeparatorChar + "data" + Path.DirectorySeparatorChar + this.frontFile);
            fillImage = new Bitmap(drawnImage);
            Thread t = new Thread(new ThreadStart(Draw));
            t.IsBackground = true;
            t.Start();

            t.Join();

            BitmapSets bitmapSets;
            if ((fillImage != null) && (pointImage != null) && (drawnImage != null))
                bitmapSets = new BitmapSets(fillImage, pointImage, drawnImage);
            else
                bitmapSets = null;
            return bitmapSets;
        }

        private void Draw()
        {
            try
            {
                List<Point> yokoPoint = new List<Point>();
                List<Point> tatePoint = new List<Point>();
                List<Point> mapMarkPoint = new List<Point>();

                KokkaData kokkaData;
                List<FillPointInfo> fillPointInfoList = new List<FillPointInfo>();
                List<MarkPointInfo> markPointInfoList = new List<MarkPointInfo>();

                Point point;
                //int count = MapSubject.searchWordList.Count;

                string[] subFolders = Directory.GetDirectories(
                    Const.DataDir + Path.DirectorySeparatorChar +
                    ".ageon" + Path.DirectorySeparatorChar +
                    "cache" + Path.DirectorySeparatorChar +
                    "screening", "*", SearchOption.TopDirectoryOnly);

                List<string> folList = subFolders.ToList();

                folList = folList.Select(a => Path.GetFileNameWithoutExtension(a)).ToList();

                foreach (string yomi in folList)
                {
                    //マークする点の座標を得る

                    if (nameDic.ContainsKey(yomi) == false)
                        continue;
                    kokkaData = nameDic[yomi];

                    //起点を得る
                    if (kokkaData.type.Equals("Mark") == true)
                    {
                        point = new Point(kokkaData.point.X, kokkaData.point.Y);
                        mapMarkPoint.Add(point);
                    }
                    else
                    {
                        point = new Point(kokkaData.point.X, kokkaData.point.Y);
                        //addMapMarkPoint.Add(new Point(0,0));
                    }


                    //色の強さを得る
                    byte powerNum;
                    //全生存スレが対象
                    if ((withInFileName == null) || (withInFileName.Length == 0))
                        powerNum = GetPower(yomi, fileName + ".info.txt");
                    else
                        //時間の範囲が指定されている場合
                        powerNum = GetPowerByWithInTime(yomi);
                    if (powerNum == 255)
                    {
                        //色が白色(255)な時にはコンティニュー
                        mapMarkPoint.Clear();
                        yokoPoint.Clear();
                        continue;
                    }


                    if (kokkaData.type.Equals("Mark") == true)
                    {
                        //登録されたマークの座標を加える
                        SpecialPointWorld.AddMarkPoint(mapMarkPoint, yomi);
                        MarkPointInfo markPointInfo = new MarkPointInfo(mapMarkPoint, powerNum);
                        markPointInfoList.Add(markPointInfo);
                        mapMarkPoint.Clear();
                    }
                    else
                    {
                        //登録された塗りつぶす座標を加える
                        SpecialPointWorld.AddMarkPoint(mapMarkPoint, yomi);
                        MarkPointInfo markPointInfo = new MarkPointInfo(mapMarkPoint, powerNum);
                        markPointInfoList.Add(markPointInfo);
                        mapMarkPoint.Clear();

                        SpecialPointWorld.AddPoint(yokoPoint, yomi, ref point, drawnImage.Width, drawnImage.Height);
                        FillPointInfo yokoPointInfo = new FillPointInfo(yokoPoint, powerNum);
                        fillPointInfoList.Add(yokoPointInfo);
                        yokoPoint.Clear();
                    }
                }


                fillImage = DrawCruciformPointList(fillImage, fillPointInfoList.Where(a => a.list.Count > 0).ToList(), 255, 255);

                pointImage = new Bitmap(drawnImage.Width, drawnImage.Height);
                //Graphicsオブジェクト作成する
                Graphics g = Graphics.FromImage(pointImage);
                //全体を黒で塗りつぶす
                g.FillRectangle(Brushes.Black, g.VisibleClipBounds);
                g.Dispose();

                pointImage = DrawMarkPointList(pointImage, markPointInfoList.Where(a => a.list.Count > 0).ToList(), 255, 255);

                //２枚の画像を合成する
                drawnImage = ImageUtil.SynthesisImage(fillImage, pointImage);
                //初期化
                fillPointInfoList.Clear();
                markPointInfoList.Clear();
                tatePoint.Clear();
            }
            catch (System.Exception ex)
            {
                //Const.debugForm.OutPutDebug("Map", ex);
            }
        }

        public byte GetPower(string yomi, string fileName)
        {
            string str = FileIO.ReadUnicode(".ageon/cache/screening/" + yomi, fileName);

            if ((str != null) && (str.Length > 0))
            {
                string[] rows = str.Split(new char[] { '\r', '\n' });

                //rows = rows.Where(a => a.Length > 0).ToArray();

                int powerNum = 255 - Int32.Parse(rows[0]) * 4 - 50;
                if (powerNum < 0)
                    powerNum = 0;

                return (byte)powerNum;
            }
            return 255;
        }

        //ルートメソッド
        public byte GetPowerByWithInTime(string yomi)
        {
            try
            {
                List<string> files = new List<string>();
                files = GetFileList(yomi);
                if ((files == null) || (files.Count == 0)) return (byte)255;


                if (this.pinPointData.Length == 0)
                    return (byte)GetWithInPower(yomi, files);
                else
                    return (byte)GetPinPointPower(yomi, files);
            }
            catch (System.Exception ex)
            {
                //Const.debugForm.OutPutDebug("Map", ex);
                return 255;
            }
        }

        //フォルダ内のinfo.txtファイルのリストを得る
        public List<string> GetFileList(string yomi)
        {

            string dir = Const.DataDir + Path.DirectorySeparatorChar +
                ".ageon" + Path.DirectorySeparatorChar +
                "cache" + Path.DirectorySeparatorChar +
                "screening" + Path.DirectorySeparatorChar +
                yomi;

            if (System.IO.Directory.Exists(dir) == false)
            {
                System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(dir);
                di.Create();
            }

            string[] fileList = Directory.GetFiles(dir, "*", SearchOption.TopDirectoryOnly);

            if (fileList.Length == 0)
                return null;

            //時間指定されているinfoファイルを得る。
            List<string> fileList2 = fileList.Where(a => ((a.Contains("subject") == false) && (a.EndsWith("info.txt") == true))).ToList().Select(a => Path.GetFileName(a)).ToList();
            //ファイルを時間順に並び替える
            fileList2.Sort(BoadListSort.CompareString);
            return fileList2;
        }

        //スレッドの数を得る
        public int GetWithInPower(string yomi, List<string> fileList)
        {
            int powerNum = 0;

            //時間の範囲内のデータを得る
            foreach (string file in fileList)
            {
                //フォルダの日にちの方が大きいならば＝読み込む
                if (String.Compare(file, withInInfoFileName) == 1)
                {
                    powerNum += GetPowerInsider(yomi, file);
                }
                //フォルダと範囲の日にちが等しい
                else if (String.Compare(file, withInInfoFileName) == 0)
                {
                    string logFile = file.Substring(0, file.Length - 8) + "txt";
                    string temp = ReadLogStringByTime(yomi, logFile);
                    if (temp.Length > 0)
                    {
                        ThreadInfo lastThreadInfo = SubjectUtil.ParseSubjectInfoLines(temp, file);
                        //時間で絞り込む
                        lastThreadInfo.threadDataList = lastThreadInfo.threadDataList.Where(a => String.Compare(a.openTime, withInTime) > 0).ToList();
                        powerNum += lastThreadInfo.threadDataList.Count;
                        break;
                    }
                }
                //フォルダの日にちの方が小さいならば＝読み込まない
                else
                {
                    break;
                }
            }
            if (powerNum > 0)
            {
                powerNum = 255 - powerNum * 4 - 50;
                if (powerNum < 0)
                    powerNum = 0;
            }
            else
                powerNum = 255;
            return (byte)powerNum;
        }
        //スレッドの数を得る
        public int GetPinPointPower(string yomi, List<string> fileList)
        {
            int powerNum = 0;

            //時間の範囲内のデータを得る
            foreach (string file in fileList)
            {
                if (String.Compare(file, withInInfoFileName) == 0)
                {
                    powerNum += GetPowerInsider(yomi, file);
                    break;
                }
                //フォルダの日にちの方が小さいならば＝読み込まない
                else
                {
                    break;
                }
            }
            if (powerNum > 0)
            {
                powerNum = 255 - powerNum * 4 - 50;
                if (powerNum < 0)
                    powerNum = 0;
            }
            else
                powerNum = 255;
            return (byte)powerNum;
        }

        public int GetPowerInsider(string yomi, string fileName)
        {
            try
            {
                string str = FileIO.ReadUnicode(".ageon/cache/screening/" + yomi, fileName);

                if ((str != null) && (str.Length > 0))
                {
                    string[] rows = str.Split(new char[] { '\r', '\n' });

                    return Int32.Parse(rows[0]);
                }
                else
                    return 255;
            }
            catch (System.Exception ex)
            {
                //Const.debugForm.OutPutDebug("Map", ex);
                return 255;
            }
        }
        public string ReadLogStringByTime(string yomi, string fileName)
        {

            string dir = ".ageon" + Path.DirectorySeparatorChar + "cache" + Path.DirectorySeparatorChar + 
                "screening" + Path.DirectorySeparatorChar + yomi;

            string data = FileIO.ReadUnicode(dir, fileName);
            return data;
        }
    }
}