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

namespace nispi
{
    class BoardViewTimeExtraction
    {
        //日時を指定
        public string pinPointFile = null;

        string boardID;
        string boardType;
        string boardUrl;

        public int containKakoLog = 0;
        public int withInNum = 0;
        public string pinPointData = "";
        public string pinPointJPDate = "";

        public ListViewItem[] items = new ListViewItem[1000];
        public int itemSize = 0;
        public ThreadInfo threadInfo;
        public BoardViewCommon boardView;

        public BoardViewTimeExtraction(BoardViewCommon boardView)
        {
            this.boardView = boardView;
        }

        //日時、範囲で絞って表示する大元メソッド
        public void SetData(string boardUrl, int containKakoLog, int withInNum, string pinPointData)
        {
            try
            {
                if (threadInfo.threadDataList.Count > 0)
                    threadInfo.threadDataList.Clear();
                threadInfo = null;
            }
            catch (System.Exception ex)
            {
                //Const.debugForm.OutPutDebug("BoarddList", ex);
            }

            this.boardUrl = boardUrl;
            this.boardType = Util.BoardUrlToBoardTypeName(this.boardUrl);
            this.boardID = Util.BoardUrlToBoardID(this.boardUrl);

            this.containKakoLog = containKakoLog;
            this.withInNum = withInNum;
            this.pinPointData = pinPointData;

            MakeExtractionThreadInfo();
            //boardView.worker();
            Const.form.mainForm.Invoke(new Action(this.boardView.Write_List_Dele));
        }

        public void MakeExtractionThreadInfo()
        {
            if ((this.containKakoLog == 0) && (this.withInNum == 0) && (this.pinPointData.Length == 0))
                return;
            PlusTime plusTime = null;
            string withInTime = "";
            string withInFileName = "";
            string fromPoint = "";
            string toPoint = "";

            Const.form.mainForm.Invoke((Action)(() => plusTime = boardView.boardListControls.withInCBoxParts.GetTimeStructure()));
            //plusTime = boardView.boardListControls.withInCBoxParts.GetTimeStructure();//コンボボックスのメソッドを使う;
            //ファイルの基準でUnix時間を得る
            withInTime = UnixTime.GetUnixTimeByPlusTime(plusTime).ToString();
            //範囲から最大の日にちのファイル名を得る
            withInFileName = UnixTime.GetFileNameByPlusTime(plusTime);

            //過去ログも読み込む
            if (this.containKakoLog == 1)
            {
                //「以内」のデータあり
                if ((this.withInNum > 0) && (this.pinPointData.Length == 0))
                {
                    threadInfo = GetFileListFromDate(withInFileName, withInTime);
                }
                else if ((this.withInNum == 0) && (this.pinPointData.Length > 0))
                {
                    threadInfo = GetPinPointLogFile();
                }
                //この場合は両方がオフと考える
                else
                {
                    if (threadInfo != null)
                        if (threadInfo.threadDataList.Count > 0)
                            threadInfo.threadDataList.Clear();
                    threadInfo = null;
                }
            }
            //過去ログは読み込まない
            else if (this.containKakoLog == 0)
            {
                //「以内」のデータあり
                if ((this.withInNum > 0) && (this.pinPointData.Length == 0))
                {
                    threadInfo = GetFileListFromLiveDate(withInTime);
                    //return;
                }
                else if ((this.withInNum == 0) && (this.pinPointData.Length > 0))
                {
                    //日にち指定
                    UnixTime.GetPinPointDate(pinPointData, ref fromPoint, ref toPoint);
                    threadInfo = GetPinPointListFromLiveDate(fromPoint, toPoint); ;
                }
                //この場合は両方がオフと考える
                else
                {
                    //過去ログすべてを表示する
                    if (threadInfo != null)
                        if (threadInfo.threadDataList.Count > 0)
                            threadInfo.threadDataList.Clear();
                    threadInfo = null;
                }
            }
        }

        public ThreadInfo GetPinPointLogFile()
        {
            //ピンポイントの日時のファイル名にゼロを入れて変える
            string pinPointData2 = UnixTime.ChangeDateFormat(pinPointData);

            string str = ReadLogStringByTime(pinPointData2 + ".txt");
            if (str.Length > 0)
            {
                ThreadInfo threadInfoTemp = SubjectUtil.ParseSubjectInfoLines(str, pinPointData + ".txt");
                return threadInfoTemp;
            }
            else
                return null;
        }

        public ThreadInfo GetPinPointListFromLiveDate(string fromPoint, string toPoint)
        {
            ThreadInfo threadInfoTemp = new ThreadInfo();

            threadInfoTemp = (ThreadInfo)boardView.threadInfo.CloneObject(boardView.threadInfo);
            //threadInfoTemp.threadDataList = boardView.threadInfo.threadDataList.ToList();
            //ファイルを時間順に並び替える
            threadInfoTemp.threadDataList.Sort(BoadListSort.CompareOpenTimeRev);

            threadInfoTemp.threadDataList = threadInfoTemp.threadDataList.Where(a =>
                (String.Compare(a.openTime, fromPoint) > 0) && (String.Compare(a.openTime, toPoint) < 0)
                ).ToList();

            if (threadInfoTemp.threadDataList.Count > 0)
            {
                return threadInfoTemp;
            }
            else
            {
                return threadInfoTemp;
            }
        }

        public ThreadInfo GetFileListFromDate(string withInFileName, string withInTime)
        {
            ThreadInfo threadInfoTemp = new ThreadInfo();

            string dir = Const.DataDir + Path.DirectorySeparatorChar +
                ".ageon" + Path.DirectorySeparatorChar +
                "cache" + Path.DirectorySeparatorChar +
                this.boardType + Path.DirectorySeparatorChar +
                boardID;

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

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

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

            //infoファイルを取り除く
            List<string> folList = subFolders.Where(a => a.EndsWith("info.txt") == false).Select(a => Path.GetFileName(a)).ToList();
            //ファイルを時間順に並び替える
            folList.Sort(BoadListSort.CompareString);

            string str = "";

            //時間の範囲内のデータを得る
            foreach (string folder in folList)
            {
                //フォルダの日にちの方が大きいならば＝読み込む
                if (String.Compare(folder, withInFileName) == 1)
                {
                    str = ReadLogStringByTime(folder);
                    if (str.Length > 0)
                    {
                        ThreadInfo threadInfoTemp2 = SubjectUtil.ParseSubjectInfoLines(str, folder);
                        threadInfoTemp.threadDataList = threadInfoTemp.threadDataList.Concat(threadInfoTemp2.threadDataList).ToList();
                    }
                }
                //フォルダと範囲の日にちが等しいならば、中身を1行ずつ精査
                else if (String.Compare(folder, withInFileName) == 0)
                {
                    string temp = ReadLogStringByTime(folder);
                    if (temp.Length > 0)
                    {
                        ThreadInfo lastThreadInfo = SubjectUtil.ParseSubjectInfoLines(temp, folder);
                        //時間で絞り込む
                        lastThreadInfo.threadDataList = lastThreadInfo.threadDataList.Where(a => String.Compare(a.openTime, withInTime) > 0).ToList();
                        threadInfoTemp.threadDataList = threadInfoTemp.threadDataList.Concat(lastThreadInfo.threadDataList).ToList();
                        break;
                    }
                }
                //フォルダの日にちの方が小さいならば＝読み込まない
                else
                {
                    break;
                }
            }

            if (threadInfoTemp.threadDataList.Count > 0)
            {
                return threadInfoTemp;
            }
            else
            {
                return threadInfoTemp;
            }

        }

        public ThreadInfo GetFileListFromLiveDate(string withInTime)
        {
            ThreadInfo threadInfoTemp = new ThreadInfo();

            threadInfoTemp = (ThreadInfo)boardView.threadInfo.CloneObject(boardView.threadInfo);
            //threadInfoTemp.threadDataList = boardView.threadInfo.threadDataList.ToList();
            //ファイルを時間順に並び替える
            threadInfoTemp.threadDataList.Sort(BoadListSort.CompareOpenTimeRev);

            threadInfoTemp.threadDataList = threadInfoTemp.threadDataList.Where(a => String.Compare(a.openTime, withInTime) > 0).ToList();

            if (threadInfoTemp.threadDataList.Count > 0)
            {
                return threadInfoTemp;
            }
            else
            {
                return threadInfoTemp;
            }
        }

        public string ReadLogStringByTime(string fileName)
        {
            string dir = ".ageon" + Path.DirectorySeparatorChar + "cache" + Path.DirectorySeparatorChar +
                this.boardType + Path.DirectorySeparatorChar + this.boardID;

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

        public void WriteKakoLog(ThreadInfo threadInfo, string boardUrl)
        {
            this.boardID = Util.BoardUrlToBoardID(boardUrl);
            this.boardType = Util.BoardUrlToBoardTypeName(boardUrl);
            /*Thread t2 = new Thread(new ParameterizedThreadStart(WriteKakoLogThread));
            t2.IsBackground = true;
            t2.Start((object)threadInfo);*/
            WriteKakoLogThread((object)threadInfo);
        }

        //通常の生存ログから、過去ログを作り出して書き込む
        private void WriteKakoLogThread(object threadInfoObject)
        {
            ThreadInfo threadInfo = (ThreadInfo)boardView.threadInfo.CloneObject(boardView.threadInfo);;
            //日時順に並び替える
            threadInfo.threadDataList.Sort(BoadListSort.CompareOpenTimeRev);

            int index = -1;
            string dateTime = "";
            List<List<ThreadData>> threadListList = new List<List<ThreadData>>();
            //作成された日にちごとにリストに分ける
            foreach (ThreadData threadData in threadInfo.threadDataList)
            {
                //先頭の１０文字が同じなら加える
                if (threadData.openTimeString.Substring(0, 10).Equals(dateTime) == true)
                    threadListList[index].Add(threadData);
                //違うなら新しくリストを追加して加える
                else
                {
                    index += 1;
                    threadListList.Add(new List<ThreadData>());
                    threadListList[index].Add(threadData);
                    dateTime = threadData.openTimeString.Substring(0, 10);
                }
            }

            //日にちごとにログと照会した後に、まとめて書き込む
            foreach (List<ThreadData> threadList in threadListList)
            {

                //日時にあうログを読み込む
                string fileNameOnly = threadList[0].openTimeString.Substring(0, 10).Replace('/', '_');
                string fileName = fileNameOnly + ".txt";
                string str = FileIO.ReadUnicode(
                    ".ageon" + Path.DirectorySeparatorChar +
                    "cache" + Path.DirectorySeparatorChar +
                    this.boardType + Path.DirectorySeparatorChar +
                    boardID, fileName);

                List<ThreadData> newList;

                //ログと比較して整理する
                if ((str != null) && (str.Length != 0))
                {
                    ThreadInfo oldInfo = SubjectUtil.ParseSubjectInfoLines(str, fileName);
                    //通常は新しいデータに古いデータを入れるが、ここで逆に新しいデータを古いデータに入れる
                    GetScreeningData.CompotionList(threadList, oldInfo.threadDataList);
                    newList = threadList.Concat(oldInfo.threadDataList).ToList();
                    oldInfo.threadDataList.Clear();
                    oldInfo.threadDataList = null;
                }
                else
                    newList = threadList;

                //ログを書き込む
                SaveToSubjectList(newList, this.boardID, fileName);
                //情報を書き込む
                SaveInfomation(newList.Count, this.boardID, fileNameOnly + ".info.txt");
                threadList.Clear();
                newList.Clear();
            }
        }

        public void SaveInfomation(int count, string boardID, string fileName)
        {
            FileIO.SaveUnicode(
                ".ageon" + Path.DirectorySeparatorChar +
                "cache" + Path.DirectorySeparatorChar +
                this.boardType + Path.DirectorySeparatorChar +
                boardID, fileName, count.ToString() + "\r\n");
        }

        public void SaveToSubjectList(List<ThreadData> threadList, string boardID, string fileName)
        {
            StringBuilder sb = new StringBuilder();

            foreach (ThreadData threadData in threadList)
            {
                sb.Append(SubjectUtil.MakeSubjectInfoLine(threadData));
            }
            FileIO.SaveUnicode(
                ".ageon" + Path.DirectorySeparatorChar +
                "cache" + Path.DirectorySeparatorChar +
                this.boardType + Path.DirectorySeparatorChar +
                boardID, fileName, sb.ToString());
        }
    }
}
