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

namespace CommonHelpers {

//**************************************************************************************************
partial class CmdLineParametersScan {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public const char
   ParamQuoteCharacter        = HCmdLineParametersParser.ParamQuoteCharacter,
   SwitchCharacterSlash       = HCmdLineParametersParser.SwitchCharacterSlash,
   SwitchCharacterHyphen      = HCmdLineParametersParser.SwitchCharacterHyphen,
   SwitchKeyFromArgsSeparator = HCmdLineParametersParser.SwitchKeyFromArgsSeparator,
   SwitchKeyArgumentsSeparator= HCmdLineParametersParser.SwitchKeyArgumentsSeparator;

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

private readonly HCmdLineParametersParser
   Parser;
private readonly string
   LineOfParameters;
private readonly int
   ParametersStartInFullCmdLine;
private readonly StringBuilder
   KeyArgumentBuffer = new StringBuilder();
private readonly List<string>
   NakedKeyArguments = new List<string>();

private int
   ParameterStartPos, Pos, QuoteCount, SwitchKeyLength;
private bool
   IsParamOpen, IsKeyArgumentOpen, WasSwitchKeyChecked, HasSwitchKeyFromArgsSeparator,
   IsHyphenSwitch;
private List<HCmdLineParameter>
   ParamList;

private int Length
   { get { return LineOfParameters.Length; } }
private bool IsInEnd
   { get { return Pos >= Length; } }
/// <exception cref="ArgumentOutOfRangeException" />
private char CurrentChar
   { get { return LineOfParameters[ Pos ]; } }
/// <exception cref="ArgumentOutOfRangeException" />
char PreviousCharacter
   { get { return LineOfParameters[ Pos-1 ]; } }
bool IsPreviousCharacterQuote
   { get { return Pos > 0 && IsParamQuoteCharacter( PreviousCharacter ); } }
bool HasSmthForKeyArguments
   { get { return NakedKeyArguments.Count > 0 || KeyArgumentBuffer.Length > 0; } }

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

/// <exception cref="ArgumentNullException" />
public CmdLineParametersScan( HCmdLineParametersParser parser,
                              string lineOfParameters,
                              int startPosInFullCmdLine )
{
   HArgChecking.VerifyNotNulls( parser, lineOfParameters );
   Parser= parser;
   LineOfParameters = lineOfParameters;
   ParametersStartInFullCmdLine = startPosInFullCmdLine;
}

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

/// <exception cref="HCmdLineParametersParseException" />
public HCmdLineParameter[] ExtractParameters()
{
   ParamList = new List<HCmdLineParameter>();
   ResetParamProperties();
   Pos = 0;
   while ( !IsInEnd )
      DoScan();
   FlushParameter();
   return ParamList.ToArray();
}

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

void ResetParamProperties()
{
   IsParamOpen = IsKeyArgumentOpen = HasSwitchKeyFromArgsSeparator = WasSwitchKeyChecked =
   IsHyphenSwitch = false;
   KeyArgumentBuffer.Length = QuoteCount = 0;
   SwitchKeyLength = ParameterStartPos = -1;
   NakedKeyArguments.Clear();
}

void SkipSpaces()
{
   while ( !IsInEnd && char.IsWhiteSpace( CurrentChar ) )
      Pos++;
}

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

void AppendKeyArgumentBuffer(char ch)
{
   KeyArgumentBuffer.Append( ch );
   IsKeyArgumentOpen = true;
}

void AppendKeyArgumentListFromBuffer()
{
   NakedKeyArguments.Add(HString.UndecorateEmbracement(
      KeyArgumentBuffer.ToString(), ParamQuoteCharacter ));
   KeyArgumentBuffer.Length = 0;
   IsKeyArgumentOpen = false;
}

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

void CheckSwitchKey()
{
   if ( !WasSwitchKeyChecked )
   {
      if ( SwitchKeyLength == 0 )
         throw CreateParseExceptionWithPos( "Empty switch keys are inadmissible." );
      if ( SwitchKeyLength > 0 && IsSwitchCharacterHyphen(
           LineOfParameters[ ParameterStartPos + SwitchKeyLength ] ) )
         throw CreateParseExceptionWithPos( "Switch key must not end with hyphen." );
      WasSwitchKeyChecked = true;
   }
}

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

static bool IsParamQuoteCharacter(char ch)
{
   return HCmdLineParametersParser.IsParamQuoteCharacter( ch );
}

static bool IsSwitchCharacter(char ch)
{
   return HCmdLineParametersParser.IsSwitchCharacter( ch );
}
static bool IsSwitchCharacterSlash(char ch)
{
   return HCmdLineParametersParser.IsSwitchCharacterSlash( ch );
}
static bool IsSwitchCharacterHyphen(char ch)
{
   return HCmdLineParametersParser.IsSwitchCharacterHyphen( ch );
}

static bool IsSwitchKeyFromArgsSeparator(char ch)
{
   return HCmdLineParametersParser.IsSwitchKeyFromArgsSeparator( ch );
}
static bool IsSwitchKeyArgumentsSeparator(char ch)
{
   return HCmdLineParametersParser.IsSwitchKeyArgumentsSeparator( ch );
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // CmdLineParametersScan
//**************************************************************************************************

} // CommonHelpers
