// ******************************************************************************//
//  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.
//
//  THIS PROPRIETARY NOTICE IS NOT APPLICABLE IF DELIVERED TO THE U.S. GOVERNMENT
//
//  UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY.
//
//  WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA AND / OR TECHNOLOGY WHOSE
//  EXPORT OR DISCLOSURE TO NON-U.S. PERSONS, WHEREVER LOCATED, IS RESTRICTED
//  BY THE INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) (22 C.F.R. SECTION
//  120-130) OR THE EXPORT ADMINISTRATION REGULATIONS (EAR) (15 C.F.R. SECTION
//  730-774). THIS DOCUMENT CANNOT BE EXPORTED (E.G., PROVIDED TO A SUPPLIER
//  OUTSIDE OF THE UNITED STATES) OR DISCLOSED TO A NON-U.S. PERSON, WHEREVER
//  LOCATED, UNTIL A FINAL JURISDICTION AND CLASSIFICATION DETERMINATION HAS
//  BEEN COMPLETED AND APPROVED BY RAYTHEON, AND ANY REQUIRED U.S. GOVERNMENT
//  APPROVALS HAVE BEEN OBTAINED. VIOLATIONS ARE SUBJECT TO SEVERE CRIMINAL
//  PENALTIES.
//
//  DOD 5220.22-M, INDUSTRIAL SECURITY MANUAL, CHAPTER 5, SECTION 1 THROUGH 9 :
//  FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN OR DOD 5200.1-R,
//  INFORMATION SECURITY PROGRAM, CHAPTER 6. FOR UNCLASSIFIED, LIMITED DOCUMENTS
//  DESTROY BY ANY  METHOD THAT WILL PREVENT DISCLOSURE OF CONTENTS OR
//  RECONSTRUCTION OF THE DOCUMENT.
// ****************************************************************************//

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Configuration;
using System.Diagnostics;
using System.IO;

namespace Raytheon.Common
{
    /// <summary>
    /// implementation of the Raytheon Configuration Manager
    /// </summary>
    [Export(typeof(IConfigurationManager))]
    public class RaytheonConfigurationManager : IConfigurationManager
    {
        private object _configLock = new();

        private Dictionary<string, RaytheonConfiguration> _configurations = new();

        private static readonly string DefaultStoragePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Raytheon", "InstrumentManagerService");

        private string _storagePath;

        /// <summary>
        /// gets or sets configuration storage path
        /// when setting the path and it does not exist will use the default value instead
        /// </summary>
        public string ConfigurationStoragePath
        {
            get
            {
                return _storagePath;
            }
            set
            {
                string item = value;

                if(string.IsNullOrWhiteSpace(item))
                {
                    item = ConfigurationManager.AppSettings["ConfigurationPath"];
                }

                if(!IsValidPath(item, true))
                {
                    Trace.WriteLine(string.Format("The Application Setting [ConfigurationPath] '{0}' is invalid.", item));
                    _storagePath = DefaultStoragePath;
                }
                else
                {
                    _storagePath = item;
                }
            }
        }

        /// <summary>
        /// if path not provided will be using either app settings value or default
        /// </summary>
        public RaytheonConfigurationManager()
        {
            ConfigurationStoragePath = string.Empty;
        }

        /// <summary>
        /// constructor that takes configuration file path
        /// </summary>
        /// <param name="defaultPath"></param>
        public RaytheonConfigurationManager(string defaultPath) => ConfigurationStoragePath = defaultPath;

        /// <summary>
        /// returns RaytheonConfiguration instance
        /// </summary>
        /// <param name="configurationName"></param>
        /// <returns></returns>
        public IConfiguration GetConfiguration(string configurationName)
        {
            RaytheonConfiguration item = null;
            lock(_configLock)
            {
                if(_configurations.ContainsKey(configurationName))
                {
                    item = _configurations[configurationName];
                }
                else
                {
                    item = new RaytheonConfiguration(configurationName, ConfigurationStoragePath);
                    item.Initialize();
                    _configurations.Add(configurationName, item);
                }
            }
            return item;
        }

        /// <summary>
        /// checks if the configuration storage path for config file is valid
        /// </summary>
        /// <param name="path"></param>
        /// <param name="allowRelativePaths"></param>
        /// <returns></returns>
        private bool IsValidPath(string path, bool allowRelativePaths = false)
        {
            if(string.IsNullOrEmpty(path))
            {
                return false;
            }

            bool isValid;
            try
            {
                string fullPath = Path.GetFullPath(path);

                if(allowRelativePaths)
                {
                    isValid = Path.IsPathRooted(path);
                }
                else
                {
                    string root = Path.GetPathRoot(path);
                    isValid = string.IsNullOrEmpty(root.Trim(new char[] { '\\', '/' })) == false;
                }
            }
            catch(Exception)
            {
                isValid = false;
            }

            return isValid;
        }
    }
}