###############################################################################
#
# pkgd.eagle --
#
# Extensible Adaptable Generalized Logic Engine (Eagle)
# Package Downloader Client
#
# Copyright (c) 2007-2012 by Joe Mistachkin.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: $
#
###############################################################################

#
# NOTE: Use our own namespace here because even though we do not directly
#       support namespaces ourselves, we do not want to pollute the global
#       namespace if this script actually ends up being evaluated in Tcl.
#
namespace eval ::PackageDownloader {
  proc setupDownloadVars {} {
    #
    # NOTE: Prevent progress messages from being displayed while downloading
    #       from the repository, etc?  By default, this is enabled.
    #
    variable quiet; # DEFAULT: true

    if {![info exists quiet]} then {
      set quiet true
    }

    #
    # NOTE: The base URI for the package distribution web site.
    #
    variable baseUri; # DEFAULT: https://urn.to/r/pkgr

    if {![info exists baseUri]} then {
      set baseUri https://urn.to/r/pkgr
    }

    #
    # NOTE: The URI where a single package file may be found.  This file will
    #       belong to a specific version of one package.
    #
    variable downloadUri; # DEFAULT: ${baseUri}?...&filename=${fileName}

    if {![info exists downloadUri]} then {
      set downloadUri {${baseUri}?download&ci=trunk&filename=${fileName}}
    }

    #
    # NOTE: The root directory where any persistent packages will be saved.
    #
    variable persistentDirectory; # DEFAULT: [getPersistentRootDirectory]

    if {![info exists persistentDirectory]} then {
      set persistentDirectory [getPersistentRootDirectory]
    }
  }

  proc getPersistentRootDirectory {} {
    #
    # NOTE: Return a directory parallel to the one containing the library
    #       directory.
    #
    return [file join [file dirname [info library]] pkgr]
  }

  proc addToAutoPath { language directory } {
    #
    # NOTE: Add the specified directory to the auto-path if not already
    #       present.
    #
    if {[string length $language] == 0 || $language eq "eagle"} then {
      if {[isEagle]} then {
        if {![info exists ::auto_path] || \
            [lsearch -exact $::auto_path $directory] == -1} then {
          lappend ::auto_path $directory
        }
      } else {
        ::PackageRepository::eagleMustBeReady

        eagle [string map [list %directory% $directory] {
          if {![info exists ::auto_path] || \
              [lsearch -exact $::auto_path {%directory%}] == -1} then {
            lappend ::auto_path {%directory%}
          }
        }]
      }
    } elseif {$language eq "tcl"} then {
      if {[isEagle]} then {
        tcl eval [tcl master] [string map [list %directory% $directory] {
          if {![info exists ::auto_path] || \
              [lsearch -exact $::auto_path {%directory%}] == -1} then {
            lappend ::auto_path {%directory%}
          }
        }]
      } else {
        if {![info exists ::auto_path] || \
            [lsearch -exact $::auto_path $directory] == -1} then {
          lappend ::auto_path $directory
        }
      }
    } else {
      error "unsupported language, no idea how to modify auto-path"
    }
  }

  proc downloadFiles { language version fileNames persistent } {
    variable baseUri
    variable downloadUri
    variable persistentDirectory
    variable quiet

    if {$persistent} then {
      set downloadRootDirectory [file join $persistentDirectory]
    } elseif {[info exists ::env(PKGD_TEMP)]} then {
      set downloadRootDirectory [file join $::env(PKGD_TEMP) pkgr]
    } elseif {[info exists ::env(TEMP)]} then {
      set downloadRootDirectory [file join $::env(TEMP) pkgr]
    } elseif {[info exists ::env(TMP)]} then {
      set downloadRootDirectory [file join $::env(TMP) pkgr]
    } else {
      error "please set PKGD_TEMP (via environment) to temporary directory"
    }

    set downloadDirectories [list]

    foreach fileName $fileNames {
      if {[string length $fileName] == 0 || \
          [file pathtype $fileName] ne "relative"} then {
        error [appendArgs \
            "bad file name \"" $fileName "\", not relative"]
      }

      set directoryParts [file split [file dirname $fileName]]

      if {[llength $directoryParts] == 0} then {
        error [appendArgs \
            "bad file name \"" $fileName "\", no directory parts"]
      }

      set downloadDirectory [eval file join \
          [list $downloadRootDirectory] $directoryParts]

      set downloadFileName [file join $downloadDirectory \
          [file tail $fileName]]

      if {!$persistent} then {
        catch {file delete $downloadFileName}
      }

      file mkdir [file dirname $downloadFileName]

      set fileName [file join $language $version $fileName]
      set uri [subst $downloadUri]

      if {[isEagle]} then {
        writeFile $downloadFileName [interp readorgetscriptfile -- "" $uri]
      } else {
        writeFile $downloadFileName [::PackageRepository::getFileViaHttp \
            $uri 10 stdout $quiet]
      }

      lappend downloadDirectories [file dirname $downloadDirectory]
    }

    set downloadDirectories [lsort -unique $downloadDirectories]

    foreach downloadDirectory $downloadDirectories {
      addToAutoPath $language $downloadDirectory
    }
  }

  #
  # NOTE: Setup the variables, within this namespace, used by this script.
  #
  setupDownloadVars

  #
  # NOTE: This package requires the package repository client package.
  #
  package require Eagle.Package.Repository

  #
  # NOTE: Provide the package to the interpreter.
  #
  package provide Eagle.Package.Downloader \
    [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
}
