using System.Collections.Generic;
using System;
using System.Drawing;
using System.Diagnostics;
using System.Data;
using System.Collections;
using System.Windows.Forms;
using System.IO;
using System.Text;
using AR;
using System.Reflection;

namespace vmsnet
{
    public class CFDB
    {
        // ..\Database\volt /* 전압 */
        string _BaseDir;

        System.Text.StringBuilder[] StrBuf; ////데이터버퍼
        DateTime[] LastTime; ////데이터시간
        System.IO.FileInfo[] File; ////데이터파일정보
        int MaxCount = 10;
        public bool IsReady { get; private set; }

        public CFDB(params string[] dirarrays)
        {
            var dir = System.IO.Path.Combine(dirarrays);
            _BaseDir = dir;

            StrBuf = new System.Text.StringBuilder[MaxCount];
            LastTime = new DateTime[MaxCount];
            File = new System.IO.FileInfo[MaxCount];

            if (System.IO.Directory.Exists(_BaseDir) == false)
            {

                try
                {

                    System.IO.Directory.CreateDirectory(_BaseDir);
                    IsReady = true;
                }
                catch
                {
                    IsReady = false;
                }

            }
            else IsReady = true;


            ////Data Initialize
            for (int i = 0; i < MaxCount; i++)
            {
                StrBuf[i] = new System.Text.StringBuilder();
                LastTime[i] = DateTime.Now;
                File[i] = null;
            }
        }

        ////지정한 기간내 파일의 존재여부를 확인합니다.
        //public int GetfileCount(string table, DateTime sd, DateTime ed)
        //{
        //	return GetfileS(table, sd, ed).Count;
        //}


        /// <summary>
        /// 데이터를 기록합니다.
        /// </summary>
        /// <param name="time">기록시간(파일명이 결정됨)</param>
        /// <param name="table">기록할테이블명(파일명)</param>
        /// <param name="buffer">기록할데이터(열데이터가 틀려서 고정할 수 없다)</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public bool InsertData(DateTime time, string table, StringBuilder buffers)
        { // volt 파일생성
            string DayStr = time.ToString("yyyyMMdd");
            byte TableIndex = byte.Parse(table.Substring(5));

            ////해당데이터의 시간과 파일정보를 기록
            LastTime[TableIndex - 1] = time;

            // 파일명 : (time.Hour ).ToString("00") + "_" + table + ".txt"
            File[TableIndex - 1] = new System.IO.FileInfo(_BaseDir + "\\" + DayStr.Substring(0, 4) + "\\" + DayStr.Substring(4, 2) + "\\" + DayStr.Substring(6) + "\\" + (time.Hour ).ToString("00") + "_" + table + ".txt");
            if (!File[TableIndex - 1].Directory.Exists)
                File[TableIndex - 1].Directory.Create();

            ////각테이블별로 시작 열번호를 넣는다.
            int si = 1 + 160 * (TableIndex - 1);
            int ei = si + (160 - 1);

            ////파일이 없다면 제목줄을 생성해준다.
            if (!File[TableIndex - 1].Exists)
            {
                ////헤더를 추가해야한다.
                var Header = new System.Text.StringBuilder();
                Header.Append("\t" + "TIME");
                for (int j = si; j <= ei; j++)
                {
                    Header.Append("\t" + "C" + j.ToString("000"));
                }
                //Header.Append(vbTab + "KA")
                Header.AppendLine(); ////제목줄을 한칸띄운다

                // 파일에 헤더 쓰기
                //File[TableIndex - 1].WriteText(Header);   // 이전 단독모드
                /* 작성자: 이재웅, 작성일: 2024-09-23, 작성내용: 접근모드를 공유모드로 전환 */
                using (FileStream fs = new FileStream(File[TableIndex - 1].FullName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                using (StreamWriter writer = new StreamWriter(fs))
                { writer.Write(Header.ToString()); }
            }

            StrBuf[TableIndex - 1].AppendLine("\t" + time.ToFileTime().ToString() + buffers.ToString());

            ////4kb 단위로 파일을 기록한다.
            if (StrBuf[TableIndex - 1].Length > 4096) ////실제파일 기록은 ★5초마다★ 한다.
            {
                //File[TableIndex - 1].AppendText(StrBuf[TableIndex - 1]);  // 이전은 단독모드
                /* 작성자: 이재웅, 작성일: 2024-09-23, 작성내용: 접근모드를 공유모드로 전환 */
                using (FileStream fs = new FileStream(File[TableIndex - 1].FullName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                using (StreamWriter writer = new StreamWriter(fs))
                { writer.Write(StrBuf[TableIndex - 1].ToString()); }

                StrBuf[TableIndex - 1].Clear();
            }
            return true;
        }

        ~CFDB()
        {
            ////버퍼에 남아잇는 데이터를 기록한다.
            for (int i = 0; i < MaxCount; i++)
            {
                if (StrBuf[i].Length > 0)
                {
                    try
                    {
                        using (var writer = new StreamWriter(File[i].FullName, true, System.Text.Encoding.Default))
                            writer.Write(StrBuf[i].ToString());//
                    }
                    catch { }
                }
                StrBuf[i].Clear();
            }
        }

        /// <summary>
        /// 저장폴더내에 존재하는 날짜정보를 반환합니다.
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        //public List<string> GetDateList()
        //{
        //	List<string> REtval = new List<string>();

        //	System.IO.DirectoryInfo BDI = new System.IO.DirectoryInfo(_BaseDir);
        //	foreach (System.IO.DirectoryInfo Fd_Year in BDI.GetDirectories())
        //	{
        //		foreach (System.IO.DirectoryInfo FD_Mon in Fd_Year.GetDirectories())
        //		{
        //			foreach (System.IO.DirectoryInfo Fd_Day in FD_Mon.GetDirectories())
        //			{
        //				if (Fd_Day.GetFiles().Length > 0)
        //				{
        //					REtval.Add(Fd_Year.Name + FD_Mon.Name + Fd_Day.Name);
        //				}
        //			}
        //		}
        //	}
        //	REtval.Sort();
        //	return REtval;
        //}

        //public enum eTableList
        //{
        //	DATAB1 = 1,
        //	DATAB2 = 2,
        //	DATAB3 = 3,
        //	DATAB4 = 4,
        //	DATAB5 = 5
        //}

        /// <summary>
        /// 저장폴더내에 존재하는 날짜정보를 반환합니다.
        /// </summary>
        /// <param name="tablename">찾고자하는테이블명(파일은 시_테이블명.txt로 되어있다.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        //public List<string> GetDateList(eTableList tablename)
        //{
        //	List<string> REtval = new List<string>();

        //	System.IO.DirectoryInfo BDI = new System.IO.DirectoryInfo(_BaseDir);
        //	foreach (System.IO.DirectoryInfo Fd_Year in BDI.GetDirectories())
        //	{
        //		foreach (System.IO.DirectoryInfo FD_Mon in Fd_Year.GetDirectories())
        //		{
        //			foreach (System.IO.DirectoryInfo Fd_Day in FD_Mon.GetDirectories())
        //			{
        //				if (Fd_Day.GetFiles("*_" + tablename.ToString() +".txt").Length > 0)
        //				{
        //					REtval.Add(Fd_Year.Name + FD_Mon.Name + Fd_Day.Name);
        //				}
        //			}
        //		}
        //	}
        //	REtval.Sort();
        //	return REtval;
        //}

        public List<(int Year, int Month)> GetAvailableDates()
        {
            var availableDates = new List<(int Year, int Month)>();

            if (!Directory.Exists(_BaseDir))
                return availableDates;

            // Get all year directories
            foreach (var yearDir in Directory.GetDirectories(_BaseDir))
            {
                if (int.TryParse(Path.GetFileName(yearDir), out int year))
                {
                    // Get all month directories within the year directory
                    foreach (var monthDir in Directory.GetDirectories(yearDir))
                    {
                        if (int.TryParse(Path.GetFileName(monthDir), out int month))
                        {
                            availableDates.Add((year, month));
                        }
                    }
                }
            }

            return availableDates;
        }

        ////기간내 존재하는 파일을 반환합니다(테이블단위)
        public List<string> GetfileS(string table, DateTime sd, DateTime ed)
        {
            List<string> REtval = new List<string>();
            int SttYear = sd.Year;
            int EndYear = ed.Year;
            if (EndYear < SttYear) return REtval;

            int SttMonth = sd.Month;
            int EndMonth = ed.Month;

            int SttDay = sd.Day;
            int EndDay = ed.Day;

            int si = int.Parse(sd.ToString("yyyyMMdd"));
            int ei = int.Parse(ed.ToString("yyyyMMdd"));
            bool SameDay = si == ei ? true : false;

            //for (int dayinfo = si; dayinfo <= ei; dayinfo++)
            //{
            //    string dayStr = dayinfo.ToString();
            //    string dirname = Path.Combine(_BaseDir, dayStr.Substring(0, 4), dayStr.Substring(4, 2), dayStr.Substring(6));
            //    var dir = new DirectoryInfo(dirname);
            //    if (!dir.Exists) continue;

            //    int startHour = (dayinfo == si) ? int.Parse(sd.ToString("HH")) : 0;
            //    int endHour = (dayinfo == ei) ? int.Parse(ed.ToString("HH")) : 23;

            //    // 동일 날짜인 경우
            //    if (SameDay)
            //    {
            //        startHour = int.Parse(sd.ToString("HH"));
            //        endHour = int.Parse(ed.ToString("HH"));
            //    }

            //    for (int hourinfo = startHour; hourinfo <= endHour; hourinfo++)
            //    {
            //        string filename = Path.Combine(dir.FullName, $"{hourinfo:00}_{table}.txt");
            //        if (System.IO.File.Exists(filename))
            //        {
            //            REtval.Add(filename);
            //        }
            //    }
            //}


            ////20140101
            for (int dayinfo = si; dayinfo <= ei; dayinfo++)
            {
                string DayStr = dayinfo.ToString();
                var dirname = Path.Combine(_BaseDir, DayStr.Substring(0, 4), DayStr.Substring(4, 2), DayStr.Substring(6));
                var dir = new System.IO.DirectoryInfo(dirname);
                if (!dir.Exists) continue;

                ////폴더가 존재하므로 해당 테이블파일이 존재하는지 확인한다
                if (SameDay)
                {
                    ////동일날짜라면 해당 시간대만 조회하면됨
                    for (int hourinfo = int.Parse(sd.ToString("HH")); hourinfo <= int.Parse(ed.ToString("HH")); hourinfo++)
                    {
                        string fn = dir.FullName + "\\" + (hourinfo).ToString("00") + "_" + table + ".txt";
                        if (System.IO.File.Exists(fn))
                            REtval.Add(fn);
                    }
                }
                else
                {
                    if (dayinfo == si) ////시작일이라면 시작시간부터 24시까지 이다.
                    {
                        for (int hourinfo = int.Parse(sd.ToString("HH")); hourinfo <= 23; hourinfo++)
                        {
                            string fn = dir.FullName + "\\" + (hourinfo).ToString("00") + "_" + table + ".txt";
                            if (System.IO.File.Exists(fn))
                                REtval.Add(fn);
                        }
                    }
                    else if (dayinfo == ei) ////종료일이라면 1~ 종료시까지이다.
                    {
                        for (int hourinfo = 0; hourinfo <= int.Parse(ed.ToString("HH")); hourinfo++)
                        {
                            string fn = dir.FullName + "\\" + (hourinfo).ToString("00") + "_" + table + ".txt";
                            if (System.IO.File.Exists(fn))
                                REtval.Add(fn);
                        }
                    }
                    else
                    {
                        ////중간에 끼어있는 날짜라면 1~24모두가 속한다.
                        for (int hourinfo = 0; hourinfo <= 23; hourinfo++)
                        {
                            string fn = dir.FullName + "\\" + (hourinfo).ToString("00") + "_" + table + ".txt";
                            if (System.IO.File.Exists(fn))
                                REtval.Add(fn);
                        }
                    }
                }
            }
            REtval.Sort();
            return REtval;
        }

    }

}
