using System;
using System.Text;

namespace CommonHelpers {

//**************************************************************************************************
partial class LnkVariableProcessor {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="ArgumentNullException" />
public LnkVariableProcessor(HLnkConverterSettings settings)
{
   HArgChecking.VerifyNotNull( settings );
   ConverterSettings = settings;
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="HOperationFailedException" />
public string ProcessVariables(string source,int startingPosInLine)
{
   HArgChecking.VerifyNotNull( source );

   _Source_ = source;
   _StartingPosInLine_ = startingPosInLine;
   _Pos_ = 0;
   _VariablePos_ = -1;

   Output.Clear();
   Output.Capacity = source.Length;

   try { Scan(); }
   catch (VariableProcessingException e) {
      throw HOpFailedExceptionCreator.Create( e ); }

   return Output.ToString();
}

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

bool CheckVariables
{
   get { return HFlags.Check( ConverterSettings.TxtFlags,
      HLnkConverterTxtFlags.CheckVariables ); }
}
bool ExpandDollarVariables
{
   get { return HFlags.Check( ConverterSettings.TxtFlags,
      HLnkConverterTxtFlags.ExpandDollarVariables ); }
}
bool UndefinedDollarVarsAsEmpty
{
   get { return HFlags.Check( ConverterSettings.TxtFlags,
      HLnkConverterTxtFlags.UndefinedDollarVarsAsEmpty ); }
}

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

string Source           { get { return _Source_; } }
int StartingPosInLine   { get { return _StartingPosInLine_; } }
int Pos                 { get { return _Pos_; } }

/// <exception cref="InvalidOperationException" />
char CurrentChar
{
   get { VerifyNotEndOfSource(); return Source[ Pos ]; }
}

bool EndOfSource
{
   get { return Pos >= Source.Length; }
}

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

bool NextCharIsDVOpeningBraket
{
   get
   {
      int nextPos = Pos + 1;
      return nextPos < _Source_.Length && IsDVOpeningBraketCharEx( _Source_[ nextPos ] );
   }
}

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

/// <exception cref="InvalidOperationException" />
bool IsPercentChar { get { return IsPercentCharEx( CurrentChar ); } }
/// <exception cref="InvalidOperationException" />
bool IsDollarChar { get { return IsDollarCharEx( CurrentChar ); } }
/// <exception cref="InvalidOperationException" />
bool IsDVOpeningBraketChar { get { return IsDVOpeningBraketCharEx( CurrentChar ); } }
/// <exception cref="InvalidOperationException" />
bool IsDVClosingBraketChar { get { return IsDVClosingBraketCharEx( CurrentChar ); } }

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

bool IsPercentVariable { get { return IsVarOpen && !IsDollarVariable; } }
bool IsDollarVariable { get { return IsVarOpen && _IsDollarVariable_; } }

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

bool IsVarOpen { get { return _VariablePos_ >= 0; } }

/// <exception cref="InvalidOperationException" />
int VariablePos
{
   get { VerifyVarOpen(); return _VariablePos_; }
}

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

/// <exception cref="InvalidOperationException" />
void VerifyNotEndOfSource()
{
   if ( EndOfSource ) throw new InvalidOperationException();
}
/// <exception cref="InvalidOperationException" />
void VerifyVarOpen()
{
   if ( !IsVarOpen ) throw new InvalidOperationException();
}

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

/// <exception cref="InvalidOperationException" />
void Next()
{
   VerifyNotEndOfSource(); _Pos_++;
}

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

void OpenVariable(bool isDollarVariable=false)
{
   VarNameBuilder.Clear(); _VariablePos_ = Pos; _IsDollarVariable_ = isDollarVariable;
}

void CloseVariable()
{
   _VariablePos_ = -1; _IsDollarVariable_ = false;
}

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

static bool IsPercentCharEx(char ch)
{
   return ch == PercentVariableChar;
}
static bool IsDollarCharEx(char ch)
{
   return ch == DollarVariableChar;
}
static bool IsDVOpeningBraketCharEx(char ch)
{
   return ch == DVOpeningBraketChar;
}
static bool IsDVClosingBraketCharEx(char ch)
{
   return ch == DVClosingBraketChar;
}

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

const char
   PercentVariableChar  = '%',
   DollarVariableChar   = '$',
   DVOpeningBraketChar  = '(',
   DVClosingBraketChar  = ')';

readonly HLnkConverterSettings
   ConverterSettings;
readonly StringBuilder
   Output = new StringBuilder(),
   VarNameBuilder = new StringBuilder();

string _Source_;
int _StartingPosInLine_, _Pos_, _VariablePos_;
bool _IsDollarVariable_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // LnkVariableProcessor
//**************************************************************************************************

} // CommonHelpers
