using System;
using System.IO;

using CommonHelpers;

namespace SqlCatPP {

//**************************************************************************************************
static partial class Program {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/// <exception cref="HAppFailureException" />
public static void Run(string[] args)
{
   const int expectedParamCount = 5;

   int argCount = args.Length;
   if ( argCount == 0 )
   {
      PrintSyntax();
      return;
   }
   if ( argCount != expectedParamCount )
      throw HAppFailureExceptionCreator.Create(
         "Incorrect number of command-line arguments.\n"+
         "Exactly {0} parameters are expected.\n"+
         "Look syntax (SqlCatPP without args).",
         expectedParamCount );
   for (int i=0; i<argCount; i++)
      CheckParameterNormality( args[i], i );

   _SettingsScriptPath_    = GetArgumentValue( args, ParamIdx_SettingsScriptFile     );
   _ScriptSourcePattern_   = GetArgumentValue( args, ParamIdx_ScriptSourcePattern    );
   _InitialScriptPath_     = GetArgumentValue( args, ParamIdx_InitialScriptFile      );
   _SubfolderSourcePattern_= GetArgumentValue( args, ParamIdx_SubfolderSourcePattern );
   _OuputScriptPath_       = GetArgumentValue( args, ParamIdx_OuputScriptFile        );

   if ( ScriptSourcePattern == null && SubfolderSourcePattern == null )
      throw HAppFailureExceptionCreator.Create(
         "Neither <ScriptSourcePattern>-parameter ({0}) "+
         "nor <SubfolderSourcePattern>-parameter ({1}) was specified.",
         ArgumentNumDisplay( ParamIdx_ScriptSourcePattern ),
         ArgumentNumDisplay( ParamIdx_SubfolderSourcePattern ) );

   string fileName = null, filePath = _ScriptSourcePattern_;
   try { fileName = Path.GetFileName( filePath ); } catch {}
   if ( filePath!=null && Path.GetFileName( filePath ).StartsWith(";") )
      throw HAppFailureExceptionCreator.Create(
         "Forbidden explicit specification of \";\"-prefixed (semicolon) file(s): \"{0}\",\n"+
         "{2} in <ScriptSourcePattern>-parameter ({1}).",
         filePath, ArgumentNumDisplay( ParamIdx_ScriptSourcePattern ), DashChar );

   if ( _OuputScriptPath_ == null )
      throw CreateParameterError( ParamIdx_OuputScriptFile,
         "<OutputScriptFile>-parameter is required." );

   UseAdditionalParams();

   PerformConcatenation();

   foreach (var warningMessage in _WarningList_)
      HConsole.PrintExpressive( warningMessage );
   if ( WarningCount > 1 )
      HConsole.PrintFaint(
         "Totally warnings: {0} ({1})",
         WarningCount, OrderListFileName );

   if ( !AllowEmptyResult )
      if ( TotallyScriptFiles == 0 )
         throw new HAppFailureException(
            "No source files where prepared for SQL-translation." );
      else
      if ( SettingsScriptPath != null && TotallyScriptFiles == 1 )
         throw new HAppFailureException(
            "No source files where prepared for SQL-translation (except settings script)." );

   if ( TotallyScriptFiles > 1 )
      HConsole.PrintFaint(
         "Totally files concatenated: {0}",
         TotallyScriptFiles );
}

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

/// <exception cref="ArgumentNullException" />
/// <exception cref="IndexOutOfRangeException" />
[HOptionalResult]
static string GetArgumentValue(string[] args,int paramIdx)
{
   HArgChecking.VerifyNotNull( args );
   string arg = args[ paramIdx ];
   return HString.EmptyAsNull( arg!="-" ? arg : "" );
}

/// <exception cref="HAppFailureException" />
static void UseAdditionalParams()
{
   try
   {
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.InsertSetVarComments,
         ref _InsertSetVarComments_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.UnfoldEnvironmentVars,
         ref _UnfoldEnvironmentVars_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.ProcessDirectives,
         ref _ProcessDirectives_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.OrderListErrorAsWarn,
         ref _OrderListErrorAsWarn_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.AllowEmptyResult,
         ref _AllowEmptyResult_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.DefaultInputEncodingUTF8,
         ref _DefaultInputEncodingUTF8_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.CheckInputForANSI,
         ref _CheckInputForANSI_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.OutputAsANSI,
         ref _OutputAsANSI_ );
      AdditionalParams.ObtainStr(
         AdditionalParams.Names.OutputFolderPath,
         ref _OutputFolderPath_ );
      if ( AdditionalParams.ObtainStr(
         AdditionalParams.Names.OutputFileName,
         ref _OutputFileName_ ) && (
         _OutputFileName_.IndexOf("\\") >= 0 ||
         _OutputFileName_.IndexOf("/")  >= 0 ))
         throw OpFailedExceptionCreator.Create(
            "Parameter \"{0}\" must not contain directory separators (\"\\\",\"/\").",
            AdditionalParams.Names.OutputFileName );

      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.Generated_GenerationOn,
         ref _GeneratedParams_._GenerationOn_ );
      AdditionalParams.ObtainStr(
         AdditionalParams.Names.Generated_FolderPath,
         ref _GeneratedParams_._FolderPath_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.Generated_CleanAllSQL,
         ref _GeneratedParams_._CleanAllSQL_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.Generated_OrderedWithCleanup,
         ref _GeneratedParams_._OrderedWithCleanup_ );

      char headingChar = '\0';
      if ( AdditionalParams.ObtainChar(
         AdditionalParams.Names.Generated_OrderHeadingChar,
         ref headingChar ))
      {
         if ( !HOps.IsBetween( headingChar, '0', '9' ) &&
              !HOps.IsBetween( headingChar, 'A', 'Z' )  )
            throw OpFailedExceptionCreator.Create(
               "Incorrect value for \"{0}\"-parameter (english capital letter or decimal digit was expected).",
               GenParamFullNames.OrderHeadingChar );
         _GeneratedParams_._OrderHeadingChar_ = headingChar;
      }

      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.Generated_EmbedFileNamesToOrder,
         ref _GeneratedParams_._EmbedFileNamesToOrder_ );
      AdditionalParams.ObtainFlag(
         AdditionalParams.Names.Generated_RestoreDateIfSameContent,
         ref _GeneratedParams_._RestoreDateIfSameContent_ );

      AdditionalParams.VerifyNames();

      AcceptGenFolderPath();
   }
   catch (OperationFailedException e)
   {
      throw HAppFailureExceptionCreator.Create( e );
   }
}

/// <exception cref="OperationFailedException" />
static void AcceptGenFolderPath()
{
   string FolderPathParameterName() =>
      GenParamFullNames.FolderPath;
   string folderPath = GeneratedParams.FolderPath;
   if ( folderPath == null )
      return;
   try
   {
      folderPath = Path.GetFullPath( folderPath );
   }
   catch (Exception e)
   {
      throw OpFailedExceptionCreator.Create(
         "Can not obtain full path for value of \"{0}\"-parameter.\n"+
         "{1}", FolderPathParameterName(), e.Message );
   }
   string cd = Directory.GetCurrentDirectory();
   if ( HString.EqualsInvariant( folderPath, cd, true ) ||
        HString.EqualsInvariant( folderPath, cd+"\\", true ) ||
        HString.EqualsInvariant( folderPath, cd+"/", true ) )
      throw OpFailedExceptionCreator.Create(
         "Location specified by \"{0}\"-parameter must not coincid with current directory: "+
         "\"{1}\".", FolderPathParameterName(), cd );
   _GeneratedParams_._FolderPath_ = folderPath;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // Program
//**************************************************************************************************

} // SqlCatPP
