###############################################################################
#
# backup.eagle --
#
# Written by Joe Mistachkin.
# Released to the public domain, use at your own risk!
#
###############################################################################

package require Eagle
package require Eagle.Library
package require Eagle.Test

runTestPrologue

###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

checkForSQLiteDirectories $test_channel
getSQLiteHandleCounts $test_channel
reportSQLiteResources $test_channel

###############################################################################

set params(pages) [list -1 -1 0 0 1 1 2 2 1000 1000]

set params(callbacks) [list null "new SQLiteBackupCallback(BackupCallback)" \
                            null "new SQLiteBackupCallback(BackupCallback)" \
                            null "new SQLiteBackupCallback(BackupCallback)" \
                            null "new SQLiteBackupCallback(BackupCallback)" \
                            null "new SQLiteBackupCallback(BackupCallback)"]

set params(results) [list \
    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
    1048576 1048576 10\\} 0\$" \
    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
    1048576 1048576 10\\} 0\$" \
    "1 \\{SQL logic error or missing database -- no such table: t1" \
    "1 \\{SQL logic error or missing database -- no such table: t1" \
    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
    1048576 1048576 10\\} 0\$" \
    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
    1048576 1048576 10\\} 10283\$" \
    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
    1048576 1048576 10\\} 0\$" \
    "1 \\{SQL logic error or missing database -- no such table: t1" \
    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
    1048576 1048576 10\\} \\{\\}\$" \
    "0 \\{1 1048576 1048576 1048576 1048576 1048576 1048576 1048576 1048576\
    1048576 1048576 10\\} \\{System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 9284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 8284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 7284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 6284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 5284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 4284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 3284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 2284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 1284 10284 False\
    System\\.Data\\.SQLite\\.SQLiteConnection main\
    System\\.Data\\.SQLite\\.SQLiteConnection main 1000 284 10284 False\\}\$"]

###############################################################################

for {set i 0} {$i < [llength $params(pages)]} {incr i} {
  set pages [lindex $params(pages) $i]
  set callback [lindex $params(callbacks) $i]

  runTest {test [appendArgs backup-1. $i] {BackupDatabase method} -setup {
    setupDb [set fileName(1) :memory:] "" "" "" "" "" \
        false false false true memDb

    setupDb [set fileName(2) [appendArgs backup-1. $i .db]]
  } -body {
    set id [object invoke Interpreter.GetActive NextId]
    set dataSource [file join [getDatabaseDirectory] $fileName(2)]

    sql execute $memDb {
      CREATE TABLE t1(x TEXT);
    }

    for {set index 0} {$index < 10} {incr index} {
      sql execute $memDb [subst {
        INSERT INTO t1 (x) VALUES('[string repeat ! 1048576]');
      }]
    }

    set memSource [getDbConnection memDb]

    unset -nocomplain results errors

    set code [compileCSharpWith [subst {
      using System.Data.SQLite;
      using System.Text;
      using Eagle._Components.Public;

      namespace _Dynamic${id}
      {
        public static class Test${id}
        {
          public static int count = 0;
          public static readonly StringBuilder results = new StringBuilder();

          /////////////////////////////////////////////////////////////////////

          public static bool BackupCallback(
            SQLiteConnection source,
            string sourceName,
            SQLiteConnection destination,
            string destinationName,
            int pages,
            int remainingPages,
            int totalPages,
            bool retry
            )
          {
            results.AppendFormat("{0} {1} {2} {3} {4} {5} {6} {7} ", source,
              sourceName, destination, destinationName, pages, remainingPages,
              totalPages, retry);

            count++;

            return (pages != 2);
          }

          /////////////////////////////////////////////////////////////////////

          public static string BackupAndGetData(
            Interpreter interpreter,
            SQLiteConnection source
            )
          {
            using (SQLiteConnection destination = new SQLiteConnection(
                "Data Source=${dataSource};[getFlagsProperty]"))
            {
              destination.Open();

              int pages = ${pages};

              source.BackupDatabase(destination, "main", "main", pages,
                ${callback}, 0);

              ReturnCode code;
              Result error = null;

              code = interpreter.SetVariableValue(
                VariableFlags.GlobalOnly, "callbackResults", (pages > 2) ?
                    results.ToString().Trim() : count.ToString(), null,
                ref error);

              if (code != ReturnCode.Ok)
                Utility.Complain(interpreter, code, error);

              using (SQLiteCommand command = new SQLiteCommand(
                  "SELECT length(x) FROM t1;", destination))
              {
                using (SQLiteDataReader dataReader = command.ExecuteReader())
                {
                  StringBuilder builder = new StringBuilder();
                  int rowCount = 0;

                  builder.Append(dataReader.FieldCount);
                  builder.Append(' ');

                  while (dataReader.Read())
                  {
                    builder.Append(dataReader.GetInt64(0));
                    builder.Append(' ');
                    rowCount++;
                  }

                  builder.Append(rowCount);
                  return builder.ToString();
                }
              }
            }
          }

          /////////////////////////////////////////////////////////////////////

          public static void Main()
          {
            // do nothing.
          }
        }
      }
    }] true true true results errors [list System.Data.SQLite.dll Eagle.dll]]

    set callbackResults [list]

    list $code $results \
        [expr {[info exists errors] ? $errors : ""}] \
        [expr {$code eq "Ok" ? [catch {
          object invoke _Dynamic${id}.Test${id} BackupAndGetData "" $memSource
        } result] : [set result ""]}] \
        [extractSystemDataSQLiteExceptionMessage $result] $callbackResults
  } -cleanup {
    cleanupDb $fileName(2)
    cleanupDb $fileName(1) memDb

    freeDbConnection memSource

    unset -nocomplain result results errors code index memSource dataSource \
        id memDb db fileName callbackResults
  } -constraints {eagle command.object monoBug28 command.sql compile.DATA\
SQLite System.Data.SQLite compileCSharp} -match regexp -result [appendArgs \
"^Ok System#CodeDom#Compiler#CompilerResults#\\d+ \\{\\} " \
[lindex $params(results) $i]]}
}

###############################################################################

unset -nocomplain i params pages callback

###############################################################################

checkForSQLiteDirectories $test_channel
getSQLiteHandleCounts $test_channel
reportSQLiteResources $test_channel

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue
