//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// CommonHelpers satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;

namespace CommonHelpers {

//**************************************************************************************************
partial class HConsole {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine, string caption,
                          string[] actions, [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray )
{
   return PerformDialog( insertBlankLine, caption,
      actions, false, enablings, keyArray );
}

//--------------------------------------------------------------------------------------------------

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine, string caption,
                          string[] actions,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] string cancelAction )
{
   return PerformDialog( insertBlankLine, caption,
      actions, enablings, keyArray, null,
      cancelAction );
}

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine,
                          string caption,
                          string[] actions,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] string cancelAction,
                          [HOptional] ConsoleKey cancelKey )
{
   return PerformDialog( insertBlankLine, caption,
      actions, enablings, keyArray,
      cancelAction, cancelKey, 0 );
}

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine,
                          string caption,
                          string[] actions,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] string cancelAction,
                          [HOptional] ConsoleKey cancelKey,
                          [HOptional] ConsoleModifiers cancelModifiers )
{
   return PerformDialog( insertBlankLine,
      caption, actions, enablings, keyArray, null,
      cancelAction, cancelKey, cancelModifiers );
}

//--------------------------------------------------------------------------------------------------

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine, string caption,
                          string[] actions, bool isLastActionCancel,
                          [HOptional] bool[] enablings, ConsoleKey[] keyArray )
{
   return PerformDialog( insertBlankLine, caption,
      actions, isLastActionCancel, enablings, keyArray, null );
}

//--------------------------------------------------------------------------------------------------

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine,
                          string caption,
                          string[] actions,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] ConsoleModifiers[] modifierArray )
{
   return PerformDialog( insertBlankLine, caption,
      actions, false, enablings, keyArray, modifierArray );
}

//==================================================================================================

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine,
                          string caption,
                          string[] actions,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] ConsoleModifiers[] modifierArray,
                          [HOptional] string cancelAction )
{
   HArgChecking.VerifyNotNull( cancelAction );
   return PerformDialog( insertBlankLine,
      caption, actions, enablings, keyArray, modifierArray,
      cancelAction, cancelAction!=null ? ConsoleKey.Escape : 0 );
}

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine, string caption,
                          string[] actions,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] ConsoleModifiers[] modifierArray,
                          [HOptional] string cancelAction,
                          [HOptional] ConsoleKey cancelKey )
{
   return PerformDialog( insertBlankLine,
      caption, actions, enablings, keyArray, modifierArray,
      cancelAction, cancelKey, 0 );
}

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine,
                          string caption,
                          string[] actions,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] ConsoleModifiers[] modifierArray,
                          [HOptional] string cancelAction,
                          [HOptional] ConsoleKey cancelKey,
                          [HOptional] ConsoleModifiers cancelModifiers )
{
   HArgChecking.VerifyNotNulls( caption, actions, keyArray );

   if ( !( cancelAction!=null && cancelKey!=0 ||
           cancelAction==null && cancelKey==0 && cancelModifiers==0 ) ||
        enablings!=null && actions.Length!=enablings.Length )
      throw HArgChecking.ArgumentException_IncorrectArguments;

   if (cancelAction!=null)
   {
      HArray.Append(ref keyArray,cancelKey);
      if (modifierArray!=null)
         HArray.Append(ref modifierArray,cancelModifiers);
      HArray.Append(ref actions,cancelAction);
   }

   return PerformDialog( insertBlankLine, caption,
      actions, cancelAction!=null, enablings, keyArray, modifierArray );
}

//--------------------------------------------------------------------------------------------------

/// <exception cref="InvalidOperationException" />
/// <exception cref="HAbortConsoleInputException" />
public int PerformDialog( bool insertBlankLine,
                          string caption,
                          string[] actions,
                          bool isLastActionCancel,
                          [HOptional] bool[] enablings,
                          ConsoleKey[] keyArray,
                          [HOptional] ConsoleModifiers[] modifierArray )
{
   HArgChecking.VerifyNotNulls( caption, keyArray, actions );

   if
   (
      keyArray.Length==0 ||
      modifierArray!=null && modifierArray.Length!=keyArray.Length ||
      actions.Length!=keyArray.Length ||
      enablings!=null &&
      !(
         !isLastActionCancel && enablings.Length==actions.Length ||
         isLastActionCancel  && enablings.Length==actions.Length-1
      )
   )
      throw HArgChecking.ArgumentException_IncorrectArguments;

   VerifyInNativeVisualMode();

   PrintUnderbarCaption( insertBlankLine, DialogCaptionChar, DialogCaptionColor, caption );

   int itemCount = actions.Length;

   var keyStrings = new string[ itemCount ];
   for (int i=0; i<keyStrings.Length; i++)
      keyStrings[i] = KeyToString( HArray.GetAtZeroBasedIndex(keyArray,i),
         modifierArray!=null ? HArray.GetAtZeroBasedIndex(modifierArray,i) : 0 );

   int maxCaptionLength = HString.MaxLength( keyStrings );

   Predicate<int> isItemEnabledDelegate = (i) =>
      enablings==null || isLastActionCancel && i==itemCount-1 ||
      HArray.GetAtZeroBasedIndex(enablings,i);

   for (int i=0; i<itemCount; i++)
   {
      OutputDashAlignedListItemCaption
      (
         null, null, keyStrings[i],
         isItemEnabledDelegate(i) ? DialogKeyColor : DialogKeyDisablingColor,
         maxCaptionLength, null, DialogDashColor
      );
      Print
      (
         i==keyStrings.Length-1 && isLastActionCancel ?
         DialogCancelActionColor : DialogActionColor,
         HArray.GetAtZeroBasedIndex(actions,i)
      );
   }

   OutputDialogPrompt();

   int idx;

   for (;;)
   {
      try
         { idx = AcceptInputKey( keyArray, modifierArray ); }
      catch (HAbortConsoleInputException)
         { Print(); throw; }
      idx = HArray.ZeroBasedIndex( keyArray, idx );

      if (isItemEnabledDelegate(idx))
      {
         Print();
         break;
      }
      PlayDisabledSound();
   }

   return isLastActionCancel && idx==itemCount-1 ?
      -1 : idx;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // HConsole
//**************************************************************************************************

} // CommonHelpers
