// **********************************************************************************************************
//    ConfigurationHelper.cs
//    7/5/2022
//    NGI - Next Generation Interceptor
//    
//    Contract No. HQ0856-21-C-0003/1022000209
//    
//    THIS DOCUMENT DOES NOT CONTAIN TECHNOLOGY OR TECHNICAL DATA CONTROLLED UNDER EITHER THE U.S. 
//    INTERNATIONAL TRAFFIC IN ARMS REGULATIONS OR THE U.S. EXPORT ADMINISTRATION REGULATIONS.
//    
//    RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION PROPRIETARY TO RAYTHEON 
//    COMPANY AND IS RESTRICTED TO USE ONLY BY PERSONS AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. 
//    DISCLOSURE TO UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL COMPETITIVE HARM TO RAYTHEON 
//    COMPANY'S BUSINESS POSITION. NEITHER SAID DOCUMENT NOR ITS CONTENTS SHALL BE FURNISHED OR DISCLOSED 
//    TO OR COPIED OR USED BY PERSONS OUTSIDE RAYTHEON COMPANY WITHOUT THE EXPRESS WRITTEN APPROVAL OF 
//    RAYTHEON COMPANY.
//    
//    UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
//    
//    DESTRUCTION NOTICE: FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN DOD 5220.22-M, 
//    NATIONAL INDUSTRIAL SECURITY PROGRAM OPERATING MANUAL, FEBRUARY 2006, 
//    INCORPORATING CHANGE 1, MARCH 28, 2013, CHAPTER 5, SECTION 7, OR DODM 5200.01-VOLUME 3, 
//    DOD INFORMATION SECURITY PROGRAM: PROTECTION OF CLASSIFIED INFORMATION, ENCLOSURE 3, 
//    SECTION 17. FOR CONTROLLED UNCLASSIFIED INFORMATION FOLLOW THE PROCEDURES IN DODM 5200.01-VOLUME 4, 
//    INFORMATION SECURITY PROGRAM: CONTROLLED UNCLASSIFIED INFORMATION.
//    
//    CONTROLLED BY: MISSILE DEFENSE AGENCY
//    CONTROLLED BY: GROUND-BASED MIDCOURSE DEFENSE PROGRAM OFFICE
//    CUI CATEGORY: CTI 
//    DISTRIBUTION/DISSEMINATION CONTROL: F 
//    POC: Alex Kravchenko (1118268)
// **********************************************************************************************************

using Raytheon.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Raytheon.Instruments
{
    /// <summary>
    /// type conversion utility with a special case for enums
    /// </summary>
    public static class TypeConverter
    {
        public static T ChangeType<T>(object value)
        {
            return typeof(T).IsEnum ? (T)Enum.Parse(typeof(T), value.ToString()) : (T)ChangeType(typeof(T), value);
        }

        public static object ChangeType(Type t, object value)
        {
            System.ComponentModel.TypeConverter tc = TypeDescriptor.GetConverter(t);
            return tc.ConvertFrom(value);
        }

        public static void RegisterTypeConverter<T, TC>() where TC : System.ComponentModel.TypeConverter
        {
            TypeDescriptor.AddAttributes(typeof(T), new TypeConverterAttribute(typeof(TC)));
        }
    }

    /// <summary>
    /// Helper class contains extention fuctions for reading types other than strings from configuration,
    /// as well as reading lists of values
    /// </summary>
    public static class ConfigurationHelper
    {
        /// <summary>
        /// template function for reading different types from configuration
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static T GetConfigurationValue<T>(this IConfiguration configuration, string section, string key, string defaultValue)
        {
            var tmpResult = configuration.GetConfigurationValue(section, key, defaultValue);
            return !string.IsNullOrEmpty(tmpResult) ? TypeConverter.ChangeType<T>(tmpResult) : default;
        }

        /// <summary>
        /// returns multivalue result (list of T) from configuration
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static List<T> GetConfigurationListValue<T>(this IConfiguration configuration, string section, string key, List<T> defaultValue)
        {
            var tmpResult = configuration.GetXmlConfiguration(section);
            if (string.IsNullOrEmpty(tmpResult))
            {
                var xmlStr = new StringBuilder();
                xmlStr.Append($"<{key}s>");
                foreach (var item in defaultValue)
                {
                    xmlStr.Append($"<{key}>");
                    xmlStr.Append(item.ToString());
                    xmlStr.Append($"</{key}>");
                }
                xmlStr.Append($"</{key}s>");

                configuration.SetXmlConfiguration(section, xmlStr.ToString());
                return defaultValue;
            }
            else
            {
                var stringRes = BuildElementListFromXml(tmpResult, key);
                return new List<T>(stringRes.Select(x => TypeConverter.ChangeType<T>(x)));
            }
        }

        /// <summary>
        /// returns values from XML section converted to string list
        /// </summary>
        /// <param name="data"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private static List<string> BuildElementListFromXml(string data, string key)
        {
            XElement doc = XElement.Parse(data);
            IEnumerable<XElement> xmlMessages = from m
                                                in doc.Elements($"{key}s").Elements(key)
                                                select m;
            var messages = xmlMessages.Select(x => x.Value);
            return messages?.ToList();
        }
    }
}
