using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Misc
{
    /// <summary>
    /// 
    /// 用于备份！！！
    /// <para>流程：</para>
    /// 
    /// <para>系统启动：</para>
    /// 
    /// <para>BackupFile.Add("profile.xml", func_isFileOK);</para>
    /// <para>BackupFile.Add("initparam.xml", func_isFileOK);</para>
    /// <para>BackupFile.Add("renzijiascan.xml", func_isFileOK);</para>
    /// <para />
    /// <para>CheckResult cr = BackupFile.Check()//检测，并处理</para>
    /// <para>switch(cr)//根据结果显示在界面</para>
    ///  </summary>
    public class BackupFile
    {
        public delegate bool IsFileOKHandler(string filepath);

        class FileInfo
        {
            public int groupno;
            public string Path;
            public string FileName;
            public IsFileOKHandler func_isFileOK;
            public bool hasCheck = false;
            public CheckResult cr = CheckResult.OK;
            public void Backup()
            {
                hasCheck = true;
                if (!Directory.Exists("backup"))
                    Directory.CreateDirectory("backup");

                if (File.Exists(Path))
                {
                    string sourceFileName = Path;
                    string destFileName = @"backup\" + FileName;
                    System.IO.FileInfo fi_s = new System.IO.FileInfo(sourceFileName);
                    System.IO.FileInfo fi_d = new System.IO.FileInfo(destFileName);
                    if (fi_d.Exists)
                    {
                        if (fi_d.LastWriteTime == fi_s.LastWriteTime) //文件已经备份了，跳过
                            return;
                    }
                    //他们有一样的LastWriteTime
                    File.Copy(sourceFileName, destFileName, true);
                }
                cr = CheckResult.OK;
            }

            /// <summary>
            /// 恢复所有文件 (调取 backup 文件夹 内的文件出来）
            /// </summary>
            /// <returns></returns>
            public bool Restore()
            {
                hasCheck = true;
                if (!Directory.Exists("backup"))
                {
                    cr = CheckResult.ERR_RESTORE;
                    return false;
                }
                try
                {
                    string destFileName = Path;
                    string sourceFileName = @"backup\" + FileName;

                    if (File.Exists(sourceFileName))
                    {
                        //他们有一样的LastWriteTime
                        File.Copy(sourceFileName, destFileName, true);
                        cr = CheckResult.RESTORE;
                        return true;
                    }
                    else
                    {
                        cr = CheckResult.ERR_RESTORE;
                        return false;
                    }
                }
                catch
                {
                    cr = CheckResult.ERR_RESTORE;
                    return false;
                }
            }
        }
        /// <summary>
        /// 路径， 文件名 
        /// </summary>
        static List<FileInfo> fileinfos = new List<FileInfo>();
        static BackupFile() 
        {
            
        }


        /// <summary>
        /// 加入需要备份的文件路径
        /// </summary>
        /// <param name="path"></param>
        public static void Add(string path, IsFileOKHandler func_isFileOK) 
        {
            Add(-1, path, func_isFileOK);
        }
        public static void Add(int groupno, string path, IsFileOKHandler func_isFileOK) 
        {
            if ((from fi in fileinfos where fi.Path == path select fi).Count() > 0)//已经存在
                return;
            

            string filename = System.IO.Path.GetFileName(path);
            string fn = filename;
            //当已经有重名，在这个名字后面加数字。
            int i = 1;
            bool b;
            while (true)
            {
                b = (from fi in fileinfos where fi.FileName == fn select fi).Count() > 0;
                if (b == true)
                {
                    fn = filename + i.ToString();
                    i++;
                }
                else
                {
                    break;
                }
            }


            fileinfos.Add(
                new FileInfo()
                {
                    groupno = groupno,
                    FileName = fn,
                    Path = path,
                    func_isFileOK = func_isFileOK
                });
        }


        public static  bool xml_isFileOK (string p)
        {
            try
            {
                System.Xml.Linq.XElement root = System.Xml.Linq.XElement.Load(p);
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }
        public static bool csv_isFileOK(string p)
        {
            try
            {
                //System.Xml.Linq.XElement root = System.Xml.Linq.XElement.Load(p);
                //第1行 必须找一个逗号
                using (StreamReader sw = new StreamReader(p, Encoding.GetEncoding("GB2312")))
                {
                    while (!sw.EndOfStream)
                    {
                        string item;
                        item = sw.ReadLine();
                        if (item.Contains(','))
                            return true;
                        else
                            return false;
                    }
                }
                return false;
            }
            catch (Exception e)
            {
                return false;
            }
        }
        public enum CheckResult 
        {
            /// <summary>
            /// 文件都没问题
            /// </summary>
            OK,
            /// <summary>
            /// 文件有问题，已经成功恢复
            /// </summary>
            RESTORE,
            /// <summary>
            /// 文件有问题,  恢复不成功
            /// </summary>
            ERR_RESTORE
        }
        /// <summary>
        /// 检测 文件 是否完整,；完整则备份；有问题，还原
        /// </summary>
        /// <returns></returns>
        public static CheckResult Check() 
        {
            foreach (FileInfo fi in fileinfos) 
            {
                if(fi.hasCheck)
                    continue;
                //找到同组的其它fi
                if (fi.groupno != -1)
                {
                    var v = from fi1 in fileinfos where fi1.groupno == fi.groupno select fi1;
                    if (v.All(fi1 => (fi1.func_isFileOK != null) && (fi1.func_isFileOK(fi1.Path))))
                    {
                        //没问题，备份
                        foreach (FileInfo fi1 in v)
                            fi1.Backup();
                    }
                    else 
                    {
                        //其中一个有问题, 同组的全部还原
                        foreach (FileInfo fi1 in v)
                            fi1.Restore();
                    }
                }
                else 
                {
                    if (fi.func_isFileOK(fi.Path))
                    {
                        //没问题，备份
                        fi.Backup();
                    }
                    else 
                    {
                        //有问题, 还原
                        fi.Restore();
                    }
                }
            }
            if (fileinfos.All(fi => fi.cr == CheckResult.OK))
                return CheckResult.OK;
            else if (fileinfos.Any(fi => fi.cr == CheckResult.ERR_RESTORE))
                return CheckResult.ERR_RESTORE;
            else
                return CheckResult.RESTORE;
        }

        /// <summary>
        /// 文件都完整， 备份 所有文件 (备份到 backup  文件夹）
        /// </summary>
        public static void Backup() 
        {
            foreach (FileInfo fi in fileinfos)
            {
                fi.Backup();
            }
        }
        /// <summary>
        /// 恢复所有文件 (调取 backup/ 文件夹 内的文件出来）
        /// </summary>
        public static bool Restore()
        {
            foreach (FileInfo fi in fileinfos)
            {
                fi.Restore();
            }
            if (fileinfos.Any(fi => fi.cr == CheckResult.ERR_RESTORE))
                return false;
            else
                return true;
        }

    }
}
