using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.IO;
using System.Security.AccessControl;
using System.Management;
using System.Security.Principal;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.Drawing;

using CommonLib.Windows.Forms;
using CommonLib.Windows.Misc;
using CommonLib.IO;
using CommonLib.Misc;

namespace All_Purpose_Auto_Setup
{
   class FoldersManager
   {
      // An event that can be raised, allowing other classes to
      // subscribe to it and do what they like with the message.
      public event Action<string, string, List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>> UpdateStatusDisplayAndLogEvent;

      public List<ConfigFileManager.Ini_KeyValue<string>> dirsToCreate = new List<ConfigFileManager.Ini_KeyValue<string>>();

      // this dictionary stores path and its associated share names
      // it would look like this:
      // [ path1 ]  ->  List[sharenames accounts_to_share]
      // [ path2 ]  ->  List[sharenames accounts_to_share]
      public Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>> pathAndShareNames = new Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>>();

      Form m_parentForm;

      public FoldersManager(Form parentForm)
      {
         m_parentForm = parentForm;
      }

      public bool shareFolders(string sectionName)
      {
         string indentation = String.Empty;
         bool setupSuccessful = true;
         string msg, errorMsg = "";
         ConfigFileManager.Ini_KeyValue<string> iniVal = new ConfigFileManager.Ini_KeyValue<string>("");

         CommonLib.Windows.Forms.TextFormat.TextFontAndColor defaultTextProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
         CommonLib.Windows.Forms.TextFormat.TextFontAndColor textProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
         List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor> textPropList = new List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>();

         // set font to default text and color
         textProp.textFont = defaultTextProp.textFont;
         textProp.textColor = Common.getSetupStepTitleColor();
         textProp.wordIndex = 0;
         textProp.wordCount = 100;
         textPropList.Add(textProp);

         DateTime dat1 = DateTime.Now;
         msg = "\n\n<-------------------Date and Time: " + dat1.ToString(@"MM/dd/yyyy     hh:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture) + "------------------->";
         UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

         // set font to default text and color
         textProp.textFont = defaultTextProp.textFont;
         textProp.textColor = Common.getSetupStepTitleColor();
         textProp.wordIndex = 0;
         textProp.wordCount = 100;
         // set font size
         textProp.textFont = new Font(textProp.textFont.Name, 12);
         // set font style
         textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
         textPropList.Add(textProp);

         msg = "\n-=Configuring network shares=-";
         UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

         pathAndShareNames.Clear();

         ConfigFileManager.readOneToManyDictionary(ConfigFileManager.ms_configGeneralInfo.iniFile,
                    sectionName, @"(path\d+)$", @"(path\d+)[^\d].+$", pathAndShareNames);

         setupSuccessful = verifyNetworkSharesInfo();

         if (setupSuccessful)
         {
            if (pathAndShareNames.Count == 0)
            {
               // set font to default text and color
               textProp.textFont = defaultTextProp.textFont;
               textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SYSTEM_SKIP);
               textProp.wordIndex = 0;
               textProp.wordCount = 2;
               // set font style
               textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
               textPropList.Add(textProp);

               indentation = Common.getIndentation(1);
               msg = "\n" + indentation + "- SKIPPED. Nothing to share";
               UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
            }

            foreach (KeyValuePair<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>> entry in pathAndShareNames)
            {
               int autoShareNameKeyIndex = entry.Value.FindIndex(x => Regex.IsMatch(x.iniKeyName, @"auto-generated", RegexOptions.IgnoreCase));
               int shareNameKeyIndex = entry.Value.FindIndex(x => Regex.IsMatch(x.iniKeyName, @"path\d+_additional.+", RegexOptions.IgnoreCase));
               int allowedAccountKeyIndex = entry.Value.FindIndex(x => Regex.IsMatch(x.iniKeyName, @"path\d+_allowed.+", RegexOptions.IgnoreCase));

               List<string> accounts = new List<string>();
               List<string> shareNames = new List<string>();

               if (allowedAccountKeyIndex >= 0)
               {
                  accounts = new List<string>(entry.Value[allowedAccountKeyIndex].iniValue.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries));
               }

               if (accounts.Count == 0)
               {
                  accounts.Add("Everyone");
               }

               if (shareNameKeyIndex >= 0)
               {
                  shareNames = new List<string>(entry.Value[shareNameKeyIndex].iniValue.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries));
               }
               else if (autoShareNameKeyIndex >= 0)
               {
                  shareNames = new List<string>(entry.Value[autoShareNameKeyIndex].iniValue.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries));
               }

               foreach (string name in shareNames)
               {
                  string nameFormatted = name.Trim();

                  if (nameFormatted.Length == 1)
                     nameFormatted = nameFormatted.ToUpper();

                  indentation = Common.getIndentation(1);
                  msg = "\n" + indentation + "Sharing " + entry.Key.iniValue + " as " + nameFormatted;

                  // set font to default text and color
                  textProp.textFont = defaultTextProp.textFont;
                  textProp.textColor = defaultTextProp.textColor;
                  textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "sharing") + 1;
                  textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg, "as") - textProp.wordIndex;
                  // set font style
                  textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                  textPropList.Add(textProp);

                  if (Directory.Exists("\\\\" + Environment.MachineName + '\\' + nameFormatted))
                  {
                     msg += " - SKIPPED. Share name already exists";

                     // set font to default text and color
                     textProp.textFont = defaultTextProp.textFont;
                     textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SYSTEM_SKIP);
                     textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "SKIPPED.");
                     textProp.wordCount = 1;
                     // set font style
                     textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                     textPropList.Add(textProp);

                     // set font to default text and color
                     textProp.textFont = defaultTextProp.textFont;
                     textProp.textColor = defaultTextProp.textColor;
                     textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "as") + 1;
                     textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg, "- skipped.") - textProp.wordIndex;
                     // set font style
                     textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                     textPropList.Add(textProp);
                  }
                  else
                  {
                     setupSuccessful = NetworkSharing.EnableNetworkFolderSharing(entry.Key.iniValue, nameFormatted, "", ref errorMsg);

                     if (!setupSuccessful)
                     {
                        msg += " - FAILED. " + errorMsg;

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.FAILURE);
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "FAILED."); ;
                        textProp.wordCount = 1;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = defaultTextProp.textColor;
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "as") + 1;
                        textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg, "- failed.") - textProp.wordIndex;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);
                     }
                     else
                     {
                        msg += " - SUCCESS.";

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SUCCESS);
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "SUCCESS."); ;
                        textProp.wordCount = 1;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = defaultTextProp.textColor;
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "as") + 1;
                        textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg, "- success.") - textProp.wordIndex;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);
                     }
                  }

                  UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

                  foreach (string account in accounts)
                  {
                     string accountFormatted = account.Trim();
                     indentation = Common.getIndentation(1);
                     msg = "\n" + indentation + "Giving account " + accountFormatted + " Full Permission to network share " + nameFormatted;

                     // set font to default text and color
                     textProp.textFont = defaultTextProp.textFont;
                     textProp.textColor = defaultTextProp.textColor;
                     textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "giving account") + 2;
                     textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg, "full permission") - textProp.wordIndex;
                     // set font style
                     textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                     textPropList.Add(textProp);

                     setupSuccessful = NetworkSharing.addAccountToNetworkShare(entry.Key.iniValue, nameFormatted, accountFormatted, "", ref errorMsg);

                     if (!setupSuccessful)
                     {
                        msg += " - FAILED. " + errorMsg;

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.FAILURE);
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "FAILED."); ;
                        textProp.wordCount = 1;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = defaultTextProp.textColor;
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "network share") + 2;
                        textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg, "- failed.") - textProp.wordIndex;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);
                     }
                     else
                     {
                        msg += " - SUCCESS.";

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SUCCESS);
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "SUCCESS."); ;
                        textProp.wordCount = 1;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);

                        // set font to default text and color
                        textProp.textFont = defaultTextProp.textFont;
                        textProp.textColor = defaultTextProp.textColor;
                        textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "network share") + 2;
                        textProp.wordCount = StringManip.GetPhraseWordIndexInText(msg, "- success.") - textProp.wordIndex;
                        // set font style
                        textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                        textPropList.Add(textProp);
                     }

                     UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

                     if (!setupSuccessful)
                        break;
                  }

                  if (!setupSuccessful)
                     break;
               }
            }
         }
         return setupSuccessful;
      }

      bool verifyNetworkSharesInfo()
      {
         bool setupSuccessful = true;
         ConfigFileManager.Ini_KeyValue<string> iniVal = new ConfigFileManager.Ini_KeyValue<string>("");
         string indentation = String.Empty;
         string msg, str;
         string[] splitStrings;

         Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>> tempOneToManyDict = new Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>>();
         List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor> textPropList = new List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>();

         // for every folder to be shared, extract the folder name and use it as a share name
         foreach (KeyValuePair<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>> entry in pathAndShareNames)
         {
            int shareNameKeyIndex = entry.Value.FindIndex(x => Regex.IsMatch(x.iniKeyName, @"path\d+_additional.+", RegexOptions.IgnoreCase));

            str = PathManip.RemoveTrailingSlashInPath(entry.Key.iniValue);
            splitStrings = str.Split(new string[] { "\\", "/", ":" }, StringSplitOptions.RemoveEmptyEntries);

            // get the name of folder to be shared
            if (splitStrings.Length > 0 && splitStrings[splitStrings.Length - 1].Length > 0)
            {
               if (!tempOneToManyDict.ContainsKey(entry.Key))
               {
                  tempOneToManyDict[entry.Key] = new List<ConfigFileManager.Ini_KeyValue<string>>(pathAndShareNames[entry.Key]);
               }

               if (shareNameKeyIndex >= 0 && tempOneToManyDict[entry.Key][shareNameKeyIndex].iniValue.Length == 0)
               {
                  tempOneToManyDict[entry.Key].RemoveAt(shareNameKeyIndex);
                  shareNameKeyIndex = -1;
               }

               if (shareNameKeyIndex < 0)
               {
                  // get the folder name of the path and save it as default share name
                  iniVal.iniSectionName = "Auto-Generated";
                  iniVal.iniKeyName = "Auto-Generated-Share-Name";
                  iniVal.iniValue = splitStrings[splitStrings.Length - 1];

                  // add default share name to path
                  tempOneToManyDict[entry.Key].Add(iniVal);
               }
               else
               {
                  iniVal = tempOneToManyDict[entry.Key][shareNameKeyIndex];
                  iniVal.iniValue += ", " + splitStrings[splitStrings.Length - 1];
                  tempOneToManyDict[entry.Key][shareNameKeyIndex] = iniVal;
               }
            }
            else
            {
               indentation = Common.getIndentation(1);
               msg = "\n" + indentation + "- FAILED. "
                  + "\n" + indentation + "File: " + ConfigFileManager.ms_configGeneralInfo.pathAndNameOfConfigFile
                  + "\n" + indentation + "Section: " + entry.Key.iniSectionName
                  + "\n" + indentation + "Key: " + entry.Key.iniKeyName
                  + "\n" + indentation + "Value: " + entry.Key.iniValue
                  + "\n" + indentation + "Error Description: The value above is invalid the INI file.";

               Common.formatConfigIniFailureMessage(msg, textPropList);

               UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

               setupSuccessful = false;
            }
         }

         pathAndShareNames = new Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>>(tempOneToManyDict);

         if (setupSuccessful)
            pathAndShareNames = new Dictionary<ConfigFileManager.Ini_KeyValue<string>, List<ConfigFileManager.Ini_KeyValue<string>>>(tempOneToManyDict);

         return setupSuccessful;
      }

      public bool createDirectories(string sectionName)
      {
         bool setupSuccessful = true;

         DirectoryInfo di;
         string msg, indentation;

         CommonLib.Windows.Forms.TextFormat.TextFontAndColor defaultTextProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
         CommonLib.Windows.Forms.TextFormat.TextFontAndColor textProp = new CommonLib.Windows.Forms.TextFormat.TextFontAndColor("");
         List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor> textPropList = new List<CommonLib.Windows.Forms.TextFormat.TextFontAndColor>();

         // set font to default text and color
         textProp.textFont = defaultTextProp.textFont;
         textProp.textColor = Common.getSetupStepTitleColor();
         textProp.wordIndex = 0;
         textProp.wordCount = 100;
         textPropList.Add(textProp);

         DateTime dat1 = DateTime.Now;
         msg = "\n\n<-------------------Date and Time: " + dat1.ToString(@"MM/dd/yyyy     hh:mm:ss tt", System.Globalization.CultureInfo.InvariantCulture) + "------------------->";
         UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

         // set font to default text and color
         textProp.textFont = defaultTextProp.textFont;
         textProp.textColor = Common.getSetupStepTitleColor();
         textProp.wordIndex = 0;
         textProp.wordCount = 100;
         // set font size
         textProp.textFont = new Font(textProp.textFont.Name, 12);
         // set font style
         textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);

         textPropList.Add(textProp);
         msg = "\n\n-=Creating Directories=-";
         UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

         dirsToCreate.Clear();

         ConfigFileManager.parseConfigInfo(sectionName, dirsToCreate);

         if (setupSuccessful)
         {
            if (dirsToCreate.Count == 0)
            {
               // set font to default text and color
               textProp.textFont = defaultTextProp.textFont;
               textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SYSTEM_SKIP);
               textProp.wordIndex = 0;
               textProp.wordCount = 2;
               // set font style
               textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
               textPropList.Add(textProp);

               indentation = Common.getIndentation(1);
               msg = "\n" + indentation + "- SKIPPED. Nothing create";
               UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);
            }

            foreach (ConfigFileManager.Ini_KeyValue<string> dir in dirsToCreate)
            {
               di = new DirectoryInfo(Path.GetFullPath(dir.iniValue));

               indentation = Common.getIndentation(1);
               msg = "\n" + indentation + di.ToString();
               // Create the directory only if it does not already exist.
               if (di.Exists == false)
               {
                  try
                  {
                     di.Create();

                     msg += " - SUCCESS";

                     // set font to default text and color
                     textProp.textFont = defaultTextProp.textFont;
                     textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SUCCESS);
                     textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "SUCCESS"); ;
                     textProp.wordCount = 1;
                     // set font style
                     textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                     textPropList.Add(textProp);
                  }
                  catch (Exception e)
                  {
                     msg += " - FAILED. (" + e.Message + ")";

                     // set font to default text and color
                     textProp.textFont = defaultTextProp.textFont;
                     textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.FAILURE);
                     textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "FAILED."); ;
                     textProp.wordCount = 1;
                     // set font style
                     textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                     textPropList.Add(textProp);

                     setupSuccessful = false;
                  }
               }
               else
               {
                  msg += " - SKIPPED. ( Directory already exists )";

                  // set font to default text and color
                  textProp.textFont = defaultTextProp.textFont;
                  textProp.textColor = Common.getSetupStatusColor(Common.EXECUTION_STATUS.SYSTEM_SKIP);
                  textProp.wordIndex = StringManip.GetPhraseWordIndexInText(msg, "SKIPPED."); ;
                  textProp.wordCount = 1;
                  // set font style
                  textProp.textFont = new Font(textProp.textFont, FontStyle.Bold);
                  textPropList.Add(textProp);
               }

               UpdateStatusDisplayAndLogEvent(msg, msg, textPropList);

               if (!setupSuccessful)
                  break;
            }
         }
         return setupSuccessful;
      }
   }
}
