//print(__FILE,':',__LINE,": Hi, world.");
/* Intended to be import()ed by unit-test.th1ish.

   Extend the Fossil bits a bit...
*/
/* Reminder: CLI args:

  The th1ish shell passed flags _after_ -- (two dashes)
  on to the script. It expects them to be in one of these
  forms:

  -f (boolean flag)
  -f=xxx (value - it tries to determine the type automatically)

  Any number of '-' may preceed a flag - they are all equivalent.

  Any such flags are stored as properties in ARGV.flags. Any
  arguments which do not start with a dash are presumed to be filenames
  or app commands and are added to ARGV.nonFlags.

  ARGV flags supported by this code:

  -R=/path/to/repo.fsl  tells it to open a repository db.

  -S (boolean) enables fossil-level SQL tracing. This applies to any
  DBs opened via a Fossil context (as opposed to directly opening them
  with Fossil.Db.open().

  -C (boolean) suppresses the automatic attempt to open an existing
  checkout under the current directory. Implied by -R.
*/

0 && scope {
    assert api.prototypes.Exception
    assert api.Exception

    assert api.PathFinder === api.prototypes.PathFinder
    assert api.prototypes.Array

    assert 'function' === typename import
    assert api
    assert 'function' === typename api.import
    assert api.PathFinder
    assert 'PathFinder' === typename api.PathFinder
    assert 'PathFinder' === typename api.import.path
    assert Fossil
    assert Fossil.Context
    assert Fossil.Db
    assert Fossil.Db.Stmt
    assert 'Db' === typename Fossil.Db
    assert 'Stmt'  === typename Fossil.Db.Stmt
    assert 'function' === typename Fossil.Db.open

    assert 'function' === typename Fossil.deltaCreate
    assert 'function' === typename Fossil.deltaApply
    assert 'function' === typename Fossil.deltaAppliedLength

    assert Fossil.file
    assert 'function' === typename Fossil.file.isAccessible
    assert 'function' === typename Fossil.file.size
    assert 'function' === typename Fossil.file.mtime
    assert 'function' === typename Fossil.file.isFile
    assert 'function' === typename Fossil.file.isDir
    assert 'function' === typename Fossil.file.canonicalName
    assert 'function' === typename Fossil.file.unlink
}

/**
    createContext() extends the Context constructor
    to support more options. obj may be a falsy value
    or an Object with any of these properties:

    repoDb: path to repository DB. Default is ARGV.flags.R.

    traceSql: if true, enable SQL tracing on the context.
    Default is ARGV.flags.S.

    checkout: a path to look for a checkout in. Not used if repoDb
    is set. Default is getenv('PWD') unless ARGV.flags.C is truthy,
    in which case no checkout is opened by default.
*/
Fossil.createContext = function(obj = null){
    if(!obj){
        const rdb = ARGV.flags.R
        obj = object{
            repoDb: rdb,
            traceSql: !!ARGV.flags.S,
            checkout: rdb ? undefined
                          : (ARGV.flags.C ? undefined : getenv('PWD'))
        }
    }
    var f = this.Context(obj)
    obj || return f
    if('string'===typename obj.repoDb){
        [f.openRepo obj.repoDb]
        // run it again to test an exception:
        //[f.openRepo obj.repoDb]
    }
    else if('string'===typename obj.checkout){
        [f.openCheckout obj.checkout]
        // run it again to test an exception:
        //[f.openCheckout obj.checkout]
    }
    return f
}

/**
  SELECT's the first column of the first row
  of the result set of the given SQL.
  If the bind argument is passed in then
  it is passed on to the Stmt.bind() method
  of the underlying statement. Use an array to
  bind multiple values.
*/
Fossil.Context.selectVal = proc(sql,bind){
    const st = [this.db.prepare sql]
    var rc
    const ex = catch {
        if(1<argv.length()){
            if('array' === typename bind){
                st.bind(bind)
            }else{
                st.bind(1,bind)
            }
        }
        [st.step] && (rc = [st.get 0])
    }
    [st.finalize]
    ex ? throw ex : return rc;
}

/**
    Given a SELECT-style query and optional bind parameters
    (either a single value for a single param or an array
    of multiple params), this routine simply dumps out
    the results of the query.
*/
Fossil.Context.dumpQuery = proc(sql,bind, separator='\t'){
    const params object{
        sql:sql,
        bind:bind, // note that undefined value is treated as non-existent here
        callback:proc(){
            (1===rowNumber) && [print [columnNames.join separator]]
            [print [this.join separator]]
        }
    }
    [this.db.each params]
}

/**
    Stmt.each() loops over this.step(),
    calling func(this, N) on each iteration,
    where N is the current row number (1-based).
    If func() returns a literal false, looping
    stops without an error.
*/
Fossil.Db.Stmt.each = proc(func){
    var rowNum = 0
    var rc
    while(this.step()){
        (false === func(this, rowNum += 1)) && break
    }
}

//Fossil.cx = Fossil.createContext()
Fossil.cx && scope {
    const cx = Fossil.cx
    assert cx inherits Fossil.Context
    assert 'FossilContext' === typename cx
    assert 'function' === typename cx.finalize
    assert 'function' === typename cx.closeCheckout
    assert 'function' === typename cx.closeRepo
    assert 'function' === typename cx.openRepo
    assert 'function' === typename cx.openCheckout
    assert 'function' === typename cx.openDb
    assert 'function' === typename cx.symToUuid
}
