//                           UNCLASSIFIED
/*-------------------------------------------------------------------------
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.
-------------------------------------------------------------------------*/

using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.IO;

namespace Raytheon.Common
{
   /// <summary>
   /// Read/Write to an ini file.
   /// </summary>
   public class IniFile
   {
      #region PrivateMemberVariables

      /// <summary>
      /// 
      /// </summary>
      internal static class NativeMethods
      {
         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
         internal static extern int GetPrivateProfileString(string lpAppName, string lpKeyName, string lpDefault, string lpReturnedstring, int nSize, string lpFileName);

         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
         [return: MarshalAs(UnmanagedType.Bool)]
         internal static extern bool WritePrivateProfileString(string lpAppName, string lpKeyName, string line, string lpFileName);

         [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
         internal static extern int GetPrivateProfileSectionNames(byte[] sections, int bufferSize, string filename);
      }

      private readonly string _fileName;

      #endregion

      #region PublicFunctions

      /// <summary>
      /// The constructor. It will check to make sure the file exists and throw an exception it if does not
      /// </summary>
      /// <param name="fileName">The ini file name (path).</param>
      public IniFile(string fileName)
      {
         _fileName = fileName;

         if (File.Exists(_fileName) == false)
         {
            throw new Exception("IniFile::IniFile() - The file does not exist: " + _fileName);
         }
      }

      /// <summary>
      /// Reads from the ini file.
      /// </summary>
      /// <param name="section">The section.</param>
      /// <param name="key">The key.</param>
      /// <returns>The value.</returns>
      public string ReadValue(string section, string key)
      {
         // just a swag
         const int BUFFER_SIZE = 10240;

         string temp = new string('\0', BUFFER_SIZE);

         int numBytes = NativeMethods.GetPrivateProfileString(section, key, "", temp, BUFFER_SIZE, _fileName);

         if (numBytes == 0)
         {
            throw new Exception("IniFile::ReadValue() - GetPrivateProfilestring returned 0 bytes for section: " + section + ", key: " + key);
         }

         temp = temp.TrimEnd('\0');

         return temp;
      }

      /// <summary>
      /// Reads all keys from a section of an ini file.
      /// </summary>
      /// <param name="section">The section.</param>
      /// <returns>A list of all keys.</returns>
      public List<string> ReadAllKeys(string section)
      {
         // just a swag
         const int BUFFER_SIZE = 102400;

         string temp = new string('\0', BUFFER_SIZE);

         int numBytes = NativeMethods.GetPrivateProfileString(section, null, "", temp, BUFFER_SIZE, _fileName);

         if (numBytes == 0)
         {
            List<string> keyList = new List<string>();
            return keyList;
         }
         else
         {
            temp = temp.TrimEnd('\0');

            List<string> keyList = new List<string>(temp.Split('\0'));

            return keyList;
         }
      }

      /// <summary>
      /// Returns a list of all of the sections in the ini file.
      /// </summary>
      /// <returns>A list of all sections.</returns>
      public List<string> ReadAllSections()
      {
         // just a swag
         const int BUFFER_SIZE = 102040;

         // allocate a 10K buffer. Should be enough to handle plenty of power systems
         byte[] buffer = new byte[BUFFER_SIZE];

         int numBytesReturned = NativeMethods.GetPrivateProfileSectionNames(buffer, BUFFER_SIZE, _fileName);

         if (numBytesReturned == BUFFER_SIZE)
         {
            throw new Exception("IniFile::ReadAllSections() - returned the max buffer size. Probably have more items in config file than we can handle");
         }
         else if (numBytesReturned == 0)
         {
            throw new Exception("IniFile::ReadAllSections() - GetPrivateProfileSectionNames returned 0 bytes");
         }

         // convert the buffer to a string
         string result = System.Text.Encoding.Unicode.GetString(buffer);

         // trim the end of the string
         result = result.TrimEnd('\0');

         // split the string
         string[] sectionListTemp = result.Split('\0');

         // ass the sections to a list
         List<string> sectionList = new List<string>();

         for (int i = 0; i < sectionListTemp.Length; ++i)
         {
            sectionList.Add(sectionListTemp[i]);
         }

         return sectionList;
      }

      /// <summary>
      /// 
      /// </summary>
      /// <param name="section"></param>
      /// <param name="key"></param>
      /// <param name="lineToWrite"></param>
      public void WriteValue(string section, string key, string lineToWrite)
      {
         bool success = NativeMethods.WritePrivateProfileString(section, key, lineToWrite, _fileName);

         if (success == false)
         {
            throw new Exception("IniFile::WriteValue() - WritePrivateProfileString returned false for section: " + section + ", key: " + key + " , line: " + lineToWrite);
         }
      }

      #endregion
   }
}
