# AVSLib :: 'loader' special module (for Avisynth's plugins-autoload folder)
# Copyright (c) 2005 George Zarkadas (gzarkadas@users.sourceforge.net)

# This program is free software; you can redistribute it and/or modify it under the terms
# of the GNU General Public License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program;
# if not, write to the "Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA  02111-1307  USA"

global __LIBPREFIX = "__COMPONENT_"  # prefix of component loaded flags
global __LIBCONFIG = 0               # load configuration (set by LoadLibrary)
global __PKG_DELIM = "/"

# The loader functions provide a generic library component's loading 
# interface. In order to achieve that the library must follow the 
# conventions set forth below:

# 1. The library has a two-level breakdown into packages and modules.
#   1.1 Packages are contained into {package} subfolders of the library's 
#       root folder. 
#       Note that packages may nested in *any level desired*, by using 
#       the value of __PKG_DELIM to join levels into one string.
#   1.2 Modules inside a {package} subfolder belong to the package and have 
#       the extension ".avsi".
# 2. Each package has a special module, named "__init.avsi", that loads
#    all modules of the package.
# 3. The library itself has a special module, named "__init.avsi", located
#    inside the library root folder that loads different configurations of 
#    the library depending on the value of the "__LIBCONFIG" global variable 
#    (which is set by the LoadLibrary loader function).
# 4. Before calling any loader the library must have already set somehow[^] 
#    the value of the global variable "__LIBROOT_{library}" to the full path 
#    to its root folder.
#    
#    [^]: for example by a line "global LIB_FOLDER=..." inside the user's 
#    script or by an autoloaded script (the convention to use library's name 
#    as the last part of the global's name avoids clashes between libraries).

# helper: replace all __PKG_DELIM with underscores or path separators
#
Function __parse_package(string package, bool "load")
{
	load = Default(load, false)
	rch = load == false ? "_" : "\"  # if load==true, use OS path separator
	pos = FindStr(package, __PKG_DELIM)
	return pos > 0 \
		? __parse_package(LeftStr(package, pos - 1) + rch + \
		  MidStr(package, pos + StrLen(__PKG_DELIM))) \
		: package
}

# Generic library components' definition routines.

# * Use "DefineModule(...)" on top of each module of your library.
# * Use "DefinePackage(...)" on top of each of you library's packages
#   special loader module (__init.avsi).
# Since they are intended to be used as "macros" they return 'last'
# in order not to mesh up with user code.


Function DefinePackage(string library, string package)
{
	dummy = Eval("global " + __LIBPREFIX + UCase(library) + \
		"_" + UCase(__parse_package(package)) + " = true")
	return last
}

Function DefineModule(string library, string package, string module)
{
	dummy = Eval("global " + __LIBPREFIX + UCase(library) + \
		"_" + UCase(__parse_package(package)) + "_" + UCase(module) + \
		" = true")
	return last
}

# Generic library components' loading routines.

# The functions below test for the existence of a specific global variable:
#   __COMPONENT_{library}_{package}[_{module}]
# where the {term} names are the names of library, package and module.
# If the variable is found they return true, else false

Function IsPackageLoaded(string library, string package)
{
	try {
		dummy = Eval(__LIBPREFIX + UCase(library) + "_" + \
			UCase(__parse_package(package)))
		ret = true
	}
	catch (err_msg) {
		ret = false
	}
	return ret
}

Function IsModuleLoaded(string library, string package, string module)
{
	try {
		dummy = Eval(__LIBPREFIX + UCase(library) + "_" + \
			UCase(__parse_package(package)) + "_" + UCase(module))
		ret = true
	}
	catch (err_msg) {
		ret = false
	}
	return ret
}


# The function loads a module if *not* already loaded.
#
Function LoadModule(string library, string package, string module)
{
	libroot = Eval("__LIBROOT_" + UCase(library))
	return IsModuleLoaded(library, package, module) \
		? NOP \
		: Import(libroot + "\" + __parse_package(package, true) + \
		  "\" + module + ".avsi")
}

# The function loads a package if *not* already loaded.
# Assumes that the library organises modules inside {package} subfolders
# and that any package includes an "__init.avsi" special module that 
# loads all other package's modules.
#
Function LoadPackage(string library, string package)
{
	libroot = Eval("__LIBROOT_" + UCase(library))
	return IsPackageLoaded(library, package) \
		? NOP \
		: Import(libroot + "\" + __parse_package(package, true) + \
		  "\" + "__init.avsi")
}

# The function loads a library with a specific configuration, set by the
# 'config' argument. The default if 'config' is not provided is zero and 
# it should result in loading the entire library.
# Assumes that the library includes an "__init.avsi" special module inside
# its root folder that loads packages and modules depending on the value
# of the __LIBCONFIG global variable (which is set = 'config' by the 
# function).
#
Function LoadLibrary(string library, int "config")
{
	global __LIBCONFIG = Default(config, 0)
	libroot = Eval("__LIBROOT_" + UCase(library))
	return Import(libroot + "\" + "__init.avsi")
}
