using System;
using System.IO;
using System.Text;
using System.Collections.Generic;

using CommonHelpers;

namespace SqlCatPP {

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

/// <exception cref="InvalidOperationException" />
/// <exception cref="OperationFailedException" />
void CleanGeneratedPreliminary()
{
   VerifyHasFileNamesAndTable();
   bool cleanAllSQL = CleanAllSQL();
   try
   {
      foreach (string fileName in _GenFileNames_)
      {
         var filePath = _GenFileTable_[ fileName ].Path;
         if ( cleanAllSQL ||
              !HasOrderPrefix( fileName, out var isSameHeadingChar ) ||
              isSameHeadingChar )
            HFile.RemoveReadOnlyFile( filePath, false );
      }
   }
   catch (Exception e)
   {
      throw OpFailedExceptionCreator.Create(
         "Can not perform preliminary cleanup:\n"+
         "{0}", e.Message );
   }
}

/// <exception cref="InvalidOperationException" />
/// <exception cref="OperationFailedException" />
void CleanGeneratedPosterior()
{
   VerifyHasFileNamesAndTable();
   try
   {
      foreach (string fileName in _GenFileNames_)
      {
         var genFileData = _GenFileTable_[ fileName ];
         var filePath = genFileData.Path;
         if ( !genFileData.Generated && (
              !HasOrderPrefix( fileName, out var isSameHeadingChar ) ||
              isSameHeadingChar ))
            HFile.RemoveReadOnlyFile( filePath, false );
      }
   }
   catch (Exception e)
   {
      throw OpFailedExceptionCreator.Create(
         "Can not perform posterior cleanup:\n"+
         "{0}", e.Message );
   }
}

/// <exception cref="NullReferenceException" />
bool HasOrderPrefix(string fileName,out bool isSameHeadingChar)
{
   isSameHeadingChar =
      HArgChecking.NotNull( fileName ) != "" &&
      fileName[0] == GeneratedParams.OrderHeadingChar;
   return fileName.Length > 5 && (
      HOps.IsBetween( fileName[0], 'A', 'Z' ) || char.IsDigit( fileName[0] )) &&
      char.IsDigit( fileName[1] ) && char.IsDigit( fileName[2] ) && char.IsDigit( fileName[3] ) &&
      fileName[4] == '.';
}

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

/// <exception cref="InvalidOperationException" />
void VerifyHasScriptWriter()
{
   if ( _ScriptWriter_ == null )
      throw new InvalidOperationException(
         "Script writer is unexpectendly null." );
}
/// <exception cref="InvalidOperationException" />
void VerifyHasCurrentScriptWriter()
{
   if ( _CurrentScriptWriter_ == null )
      throw new InvalidOperationException(
         "Current script writer is unexpectendly null." );
}

/// <exception cref="InvalidOperationException" />
void VerifyHasFileNamesAndTable()
{
   if ( _GenFileNames_ == null )
      throw new InvalidOperationException( "Generated file names array is unexpectedly null." );
   if ( _GenFileTable_ == null )
      throw new InvalidOperationException( "Generated file table is unexpectedly null." );
}

/// <exception cref="InvalidOperationException" />
void VerifyHasGenFolderPath()
{
   if ( GenFolderPath == null )
      throw new InvalidOperationException( "Generated folder path is unexpectedly null." );
}

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

SqlPPException CreatePPError( string message ) =>
   SqlPPExceptionCreator.Create(
      "{0}\n"+
      "Source line number: {1}.",
      message, _LineNo_ );

SqlPPException CreatePPError( int zeroBasedPosition, string message ) =>
   SqlPPExceptionCreator.Create(
      "{0}\n"+
      "Source line number: {1};\n"+
      "In-line position: {2}.",
      message, _LineNo_, zeroBasedPosition+1 );

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

SqlPPException CreatePPError( string messageFmt, params object[] parameters ) =>
   CreatePPError( string.Format(messageFmt,parameters) );

SqlPPException CreatePPError( int zeroBasedPosition, string messageFmt,
                              params object[] parameters ) =>
   CreatePPError( zeroBasedPosition, string.Format(messageFmt,parameters) );

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

SqlPPException NotAsciiInsertion_Error( string variableName ) =>
   variableName != "" ?
      CreatePPError(
         "Name of inserted variable is not a normal ASCII-identifier: \"{0}\".",
         variableName ) :
      CreatePPError( "Empty name of inserted variable." );

SqlPPException NotAsciiInsertion_Error( int zeroBasedPosition, string variableName ) =>
   variableName != "" ?
      CreatePPError( zeroBasedPosition,
         "Name of inserted variable is not a normal ASCII-identifier: \"{0}\".",
         variableName ) :
      CreatePPError( zeroBasedPosition, "Empty name of inserted variable." );

SqlPPException InsertionVariableNotDef_Error( int zeroBasedPosition, string variableName ) =>
   CreatePPError( zeroBasedPosition,
      "Insertion variable is not defined: \"{0}\".",
      variableName );

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

SqlPPException IncorrectRDirective_Error() =>
   throw CreatePPError( "Incorrect \":r\"-directive." );

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

/// <exception cref="ArgumentNullException" />
static bool IsNormalAsciiIdent(string ident)
{
   HArgChecking.VerifyNotNull( ident );
   if ( ident == "" )
      return false;
   for ( int i=0; i<ident.Length; i++ )
   {
      char ch = ident[ i ];
      bool isDigit = char.IsDigit( ch );
      if ( i==0 && isDigit || !(isDigit || ch=='_' || HChar.IsEnglishLetter( ch )) )
         return false;
   }
   return true;
}

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

} // SqlCatPP
