using System;
using System.Text;

using CommonHelpers;

namespace SqlCatPP {

//**************************************************************************************************
partial class Scripter {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

bool IsInCommentOrStr => _IsInBlockComment_ || _IsInSQStr_ || _IsInDQStr_;

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

void ResetParseState()
{
   _LineNo_ = 0;
   _IsInBlockComment_ = _IsInSQStr_ = false;
}

/// <summary>
/// In-script-location analysis (shallow parse of comments and string literals in T-SQL)
/// </summary>
/// <remarks>
/// Result fields (state flags): _IsInBlockComment_, _IsInSQStr_, _IsInDQStr_
/// (This routine is not called for PP-directive lines, prefixed by colon character.)
/// </remarks>
/// <exception cref="ArgumentNullException" />
/// <exception cref="InvalidOperationException" />
/// <exception cref="SqlPPException" />
string ParseSqlLine(string str)
{
   HArgChecking.VerifyNotNull( str );
   if ( !Program.ProcessDirectives && !Program.UnfoldEnvironmentVars )
      throw new InvalidOperationException(
         "“ParseSqlLine”-routine requires either “UnfoldEnvironmentVars”-property or "+
         "“ProcessDirectives”-property to have “true”-value." );
   var sb = new StringBuilder( str );
   sb.Append( '\0' );
   int strOpenOffset = -1, quoteCount = 0, varIgnorationZoneEnd = -1;
   char ch = '\0';
   for ( int p=0; p<sb.Length; p++ )
   {
      char prevCh = ch;
      ch = sb[ p ];
      if ( strOpenOffset >= 0 )
         strOpenOffset++;

      if ( varIgnorationZoneEnd >= 0 && p > varIgnorationZoneEnd )
         varIgnorationZoneEnd = -1;

      if ( UnfoldEnvironmentVars() && !_IsInBlockComment_ && varIgnorationZoneEnd < 0 &&
           ch=='$' && p+1<sb.Length && sb[ p+1 ]=='(' )
      {
         int closeBraketPos = -1;
         var varNameBldr = new StringBuilder();
         for ( int i=p+2; i<sb.Length-1; i++ )
            if ( sb[i]==')' ) { closeBraketPos = i; break; }
            else varNameBldr.Append( sb[i] );
         if ( closeBraketPos > 0 )
         {
            var variableName = varNameBldr.ToString();
            if ( IsNormalAsciiIdent( variableName ) )
            {
               if ( !_SetVariables_.TryGetValue( variableName, out string variableValue ) )
                  variableValue = Environment.GetEnvironmentVariable( variableName );
               sb.Remove( p, closeBraketPos-p+1 );
               if ( variableValue != null )
               {
                  sb.Insert( p, variableValue );
                  varIgnorationZoneEnd = p + variableValue.Length - 1;
               }
               else
                  if ( Program.ProcessDirectives )
                     throw InsertionVariableNotDef_Error( p, variableName );
            }
            else
               if ( Program.ProcessDirectives )
                  throw NotAsciiInsertion_Error( p, variableName );
               else
                  varIgnorationZoneEnd = closeBraketPos;
         }
         else
            varIgnorationZoneEnd = sb.Length;
      }

      bool isSQ = ch=='\'', isDQ = ch=='"';

      if ( strOpenOffset > 0 )
      {
         if ( _IsInSQStr_ && isSQ || _IsInDQStr_ && isDQ )
         {
            quoteCount++; continue;
         }
         if ( HArith.IsOdd( quoteCount ) )
            continue;
         strOpenOffset = -1; quoteCount = 0;
         _IsInSQStr_ = _IsInDQStr_ = false;
      }

      if ( _IsInBlockComment_ )
      {
         if ( prevCh=='*' && ch=='/' )
            _IsInBlockComment_ = false;
      }
      else
         if ( prevCh=='/' && ch=='*' )
            _IsInBlockComment_ = true;
         else
         {
            if ( prevCh=='-' && ch=='-' )
               break;
            if ( isSQ || isDQ )
            {
               _IsInSQStr_ = isSQ; _IsInDQStr_ = isDQ;
               strOpenOffset = 0; quoteCount = 1;
            }
         }
   }
   return sb.ToString( 0, sb.Length-1 );
}

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

bool _IsInBlockComment_, _IsInSQStr_, _IsInDQStr_;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // Scripter
//**************************************************************************************************

} // SqlCatPP
