namespace Universal;

public class XmlFileHelper
{
    public static bool ReadFile<T>(string filePath, out T? output)
    {
        output = default;
        if (string.IsNullOrEmpty(filePath))
            return false;

        if (!File.Exists(filePath))
            return false;

        try
        {
            using StreamReader sr = new(filePath);
            XmlSerializer xz = new(typeof(T));

            if (xz.Deserialize(sr) is not T temp)
                return false;
            output = temp;
        }
        catch
        {
            return false;
        }

        return true;
    }

    public static bool WriteFile(string filePath, object input)
    {
        if (input == null)
            return false;

        if (string.IsNullOrEmpty(filePath))
            return false;

        try
        {
            FileInfo file = new(filePath);

            if (!Directory.Exists(file.Directory!.FullName))
                Directory.CreateDirectory(file.Directory!.FullName);

            using StreamWriter sw = file.CreateText();
            sw.Write(XmlHelper.SerializeXml(input));
        }
        catch
        {
            return false;
        }



        return true;
    }
}


public class XmlHelper
{
    public static string SerializeXml(object objectToConvert)
    {
        XmlDocument xmlDocument = new();
        XmlSerializer xmlSerializer = new(objectToConvert.GetType());
        using (MemoryStream xmlStream = new())
        {
            xmlSerializer.Serialize(xmlStream, objectToConvert);
            xmlStream.Position = 0;
            xmlDocument.Load(xmlStream);
        }
        return xmlDocument.InnerXml;
    }

    public static bool DeserializeXml<T>(string s, out T? output)
    {
        output = default;

        try
        {
            using StreamReader sr = new(s, Encoding.UTF8);
            XmlSerializer xz = new(typeof(T));
            if (xz.Deserialize(sr) is not T t)
                return false;

            output = t;
        }
        catch
        {
            return false;
        }

        return true;
    }
}

/// <summary>
/// Dictionary(支持 XML 序列化)
/// </summary>
/// <typeparam name="TKey">键类型</typeparam>
/// <typeparam name="TValue">值类型</typeparam>
[XmlRoot("XmlDictionary")]
[Serializable]
public class XmlDictionary<TKey, TValue> : Dictionary<TKey, TValue>, IXmlSerializable where TKey : notnull
{
    #region 构造函数
    public XmlDictionary()
    { }

    public XmlDictionary(IDictionary<TKey, TValue> dictionary) : base(dictionary)
    { }

    public XmlDictionary(IEqualityComparer<TKey> comparer) : base(comparer)
    { }

    public XmlDictionary(int capacity) : base(capacity)
    { }

    public XmlDictionary(int capacity, IEqualityComparer<TKey> comparer) : base(capacity, comparer)
    { }

    #endregion 构造函数

    #region IXmlSerializable Members
    public XmlSchema? GetSchema() => null;

    /// <summary>
    ///     从对象的 XML 表示形式生成该对象(反序列化)
    /// </summary>
    /// <param name="xr"></param>
    public void ReadXml(XmlReader xr)
    {
        if (xr.IsEmptyElement)
            return;
        var ks = new XmlSerializer(typeof(TKey));
        var vs = new XmlSerializer(typeof(TValue));
        xr.Read();
        while (xr.NodeType != XmlNodeType.EndElement)
        {
            xr.ReadStartElement("Item");
            xr.ReadStartElement("Key");
            var key = (TKey)ks.Deserialize(xr)!;
            xr.ReadEndElement();
            xr.ReadStartElement("Value");
            var value = (TValue)vs.Deserialize(xr)!;
            xr.ReadEndElement();
            Add(key, value);
            xr.ReadEndElement();
            xr.MoveToContent();
        }
        xr.ReadEndElement();
    }

    /// <summary>
    ///     将对象转换为其 XML 表示形式(序列化)
    /// </summary>
    /// <param name="xw"></param>
    public void WriteXml(XmlWriter xw)
    {
        var ks = new XmlSerializer(typeof(TKey));
        var vs = new XmlSerializer(typeof(TValue));
        foreach (var key in Keys)
        {
            xw.WriteStartElement("Item");
            xw.WriteStartElement("Key");
            ks.Serialize(xw, key);
            xw.WriteEndElement();
            xw.WriteStartElement("Value");
            vs.Serialize(xw, this[key]);
            xw.WriteEndElement();
            xw.WriteEndElement();
        }
    }
    #endregion IXmlSerializable Members
}
