using System;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Xml;

namespace ZionVault.Util
{
    public class Xml : XmlDocument
    {
        private string Encrypt(string content)
        {
            using (MD5 hash = MD5.Create())
            {
                return Convert.ToBase64String(Encoding.UTF8.GetBytes(
                    Convert.ToBase64String(hash.ComputeHash(UTF8Encoding.UTF8.GetBytes(content)))));
            }
        }

        public void Load(string filename, string content = null, bool check = true, bool encrypted = true)
        {
            string fileContent = string.Empty;

            /*try
            {
                using (var fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read,
                    System.IO.FileShare.Read))
                {
                    using (var sr = new System.IO.StreamReader(fs, Encoding.UTF8))
                    {
                        fileContent = sr.ReadToEnd();
                    }
                }
            }
            catch (Exception)
            {
                Thread.Sleep(300);
                this.Load(filename, content, check, encrypted);
            }*/

            try
            {
                using (var fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read,
                    System.IO.FileShare.Read))
                {
                    using (var sr = new System.IO.StreamReader(fs, Encoding.UTF8))
                    {
                        fileContent = sr.ReadToEnd();
                    }
                }

                if (encrypted)
                {
                    this.LoadXml(
                        Encoding.UTF8.GetString(
                            Convert.FromBase64String(
                                Encoding.UTF8.GetString(Convert.FromBase64String(fileContent))
                            )
                        )
                    );
                }
                else
                {
                    this.LoadXml(fileContent);
                }
            }
            catch (Exception ex)
            {
                if (ex is System.IO.IOException)
                {
                    Thread.Sleep(300);
                    this.Load(filename, content, check, encrypted);
                }
                else
                {
                    var a = ex.GetType().FullName;
                    /*System.IO.File.WriteAllText(filename, Convert.ToBase64String(Encoding.UTF8.GetBytes(
                        Convert.ToBase64String(Encoding.UTF8.GetBytes(fileContent)))));*/

                    this.LoadXml(fileContent);
                    /*if (encrypted)
                        Save(filename, content, true, System.IO.File.GetAttributes(filename).HasFlag(System.IO.FileAttributes.Hidden));*/
                }
            }
        }

        public void Save(string fullpath, string content = null, bool encrypt = true, bool hide = false)
        {
            var textBytes = Encoding.UTF8.GetBytes(this.InnerXml);

            XmlNode header = this.GetElementsByTagName(content)?[0] ?? this.CreateElement(content);

            if (encrypt)
            {
                if (this.DocumentElement.Attributes["timestamp"] == null)
                {
                    this.DocumentElement.Attributes.Append(this.CreateAttribute("timestamp"));
                }
                if (this.DocumentElement.Attributes["key"] == null)
                {
                    this.DocumentElement.Attributes.Append(this.CreateAttribute("key"));
                }

                string time = DateTime.Now.ToString("yyyyMMddHHmmssffff");

                var attr = this.DocumentElement.Attributes["timestamp"];
                attr.Value = time;
                var a = this.GetElementsByTagName(content)?[0].InnerXml;

                this.DocumentElement.Attributes["key"].Value = Encrypt(this.GetElementsByTagName(content)?[0].InnerXml
                    + time);
            }

            string textEncrypt = System.Text.Encoding.UTF8.GetString(textBytes); 
            
            System.IO.File.Delete(fullpath);
            if (encrypt) {
                System.IO.File.WriteAllText(fullpath, textEncrypt , Encoding.UTF8);
            } else
            {
                base.Save(fullpath);
            }
            if (hide)
                System.IO.File.SetAttributes(fullpath, System.IO.FileAttributes.Hidden);
        }

        public bool Verify(string key, string content)
        {
            if (key != this.Encrypt(content))
                return false;
            return true;
        }

        public XmlElement Tag(XmlDocument context, string name, string text = null)
        {
            XmlElement tag = context.CreateElement(name);
            tag.InnerText = text;
            return tag;
        }
    }
}
