/*
    $Id: hlib.js,v 1.3 2001/10/17 12:47:35 harrier Exp $

    HLib
    ====

    Copyright (c) 2001 Stephan Tolksdorf
    The HLib Distribution is distributed under the terms of the GNU LGPL license.

    Import name: none
    Depends on: none

    Classes: HLib.Document
    HLib members: Document, client, setLibPath, himport, __getUniqueID,
                  __inlineImport, assert, error_assert, destroy,
                  __libpath, __idcounter, __docs
    Global symbols: isDefined, himport, HLib


    Short description:
    ------------------
    This module initializes the core infrastructure of the HLib API
    and exports the root object of the library: HLib.

    [TODO: Extend description]
*/

// Global helper function which should be used to test an optional function
// argument or object property. This is the only (almost) global symbol
// in the library which deviates from the naming standard (no "__h" prefix).
function isDefined(o) { return typeof(o) != "undefined" }

// HLib root object
HLib = {
    __libpath: "", // path to the base directory of the .js files which are to be included
    __idcounter: 0, // used for __getUniqueID
    __docs: [],      // array holding references to all Document instances
    __imported: { },  // hash array of already imported modules
    __moduledeps: {    // moduledependencies
        "composite": "layer", // a string holding a comma seperated list of
        "event": "layer",     // other modules the module depends on
        "proxy": "layer",
        "drag": "event",
        "canvas": "layer",
        "scrollbar": "drag",
        "viewport": "canvas",
        "scrolledlayer": "theme, viewport, scrollbar"
    },

    // set root path to the library directory
    setLibPath: function (path) {
        if (path.length > 0 && path[-1] != "/") path += '/'
        HLib.__libpath = path
    },

    // helper function for himport
    __inlineimport: function (file) {
        document.write("<script src='" + HLib.__libpath + file + "' type='text/javascript'></script>")
    },

    // Imports HLib modules.
    // modules: a string argument containing a comma seperated list of module names
    // path: optional argument which temporarily overwrites the LibPath
    himport: function (modules, path) {
        // This function can be called outside of an object context
        // this it has _not_ access to "this.".

        var sp = HLib.__libpath                    // store old libpath
        if (isDefined(path)) HLib.setLibPath(path) // temporarily set new libpath

        // split commaseperated list into list of (case insensitive) modules names
        modules = modules.toLowerCase().replace(/\s/g, "").split(",")

        var is = HLib.client
        for (var i = 0; i < modules.length; i++) { // iterating over list of modules
            var mod = modules[i]

            // already imported
            if (HLib.__imported[mod]) continue
            else HLib.__imported[mod] = true

            // check dependencies
            if (HLib.__moduledeps[mod]) himport(HLib.__moduledeps[mod], path)

            // Import the browser specific version of the modules.
            // For every nonstandard modulename a case label has to be created...
            switch (mod) {
            // Core modules
            case "layer":
                if (is.ie5up) mod += "_ie5"
                else if (is.gecko) mod += "_gecko"
                else if (is.ie4) mod += "_ie4"
                else if (is.nav4) mod += "_nav4"
		else mod += "_ie4"
            case "browser":
            case "document":
            case "os":
                mod = "core/" + mod
            break;
            // Event modules
            case "nativeevent":
                mod = "event/" + mod
                if (is.ie) mod += "_ie"
                else if (is.nav4) mod += "_nav4"
            break;
            case "event":
                mod = "event/" + mod
                if (is.gecko) mod += "_gecko"
                else {
                    mod += "_nondom"
                    // additionally import the module nativeevent
                    himport("nativeevent")
                }
            break;
            // Misc modules
            case "proxy":
                mod = "misc/" + mod
            break;
            // GUI modules
            case "canvas":
                mod += HLib.client.nav4 ? "_nav4" : "_default"
            case "composite":
            case "drag":
            case "scrollbar":
            case "scrolledlayer":
            case "viewport":
                mod = "gui/" + mod
            break;
            case "theme":
                mod = "theme/" + mod
            break;
            }
            HLib.__inlineimport(mod + ".js") // all library files have to end with ".js"
        }
        HLib.__libpath = sp // restore old libpath
    },

    // facility for unique ids (mainly needed for the creation of layer objects)
    __getUniqueID: function () { return "__HLibID_" + __idcounter++},

    // debugging facilities
    // for example, assert could be overwritten in the build script
    assert: function (bool) { if (bool) HLib.error_assert() },
    error_assert: function () { alert("Assert Error!") },

    // HLib gui objects and the HLib-object itself have a destroy method
    // to guarantee the proper freeing of allocated memory and native
    // browser objects. HLib.destroy kills all references to browser
    // objects by destroying all Layers and Documents.
    // Should be called from onunload.
    // [TODO: guarantee proper unloading]
    destroy: function () {
        var ds = this.__docs, i = ds.length
        while (i-- > 0) ds[i].destroy()
        HLib.__docs = null
    }

}

himport = HLib.himport // convenience function

// Client object with basic functionality for browser and os detection.
// If you need more information concerning browser and platform you
// should import the browser or os module.
HLib.client = new (function () { // create the client object (with an anonymous constructor)
    var t = this
    var a = navigator.userAgent.toLowerCase()

    // only values which are needed within the library are filled up...
    t.agent   = a
    t.major   = parseInt(navigator.appVersion)
    t.minor   = parseFloat(navigator.appVersion)

    t.nav     = a.indexOf('mozilla') != -1 && a.indexOf('spoofer') == -1 &&
                a.indexOf('compatible') == -1 && a.indexOf('opera') == -1 &&
                a.indexOf('webtv') == -1 && a.indexOf('hotjava') == -1
    t.nav4    = t.nav && t.major == 4
    t.navonly = t.nav && (a.indexOf(";nav") != -1 || a.indexOf("; nav") != -1)
    t.gecko   = a.indexOf('gecko') != -1
    t.ie      = a.indexOf("msie") != -1 && a.indexOf("opera") == -1
    t.ie4     = t.ie && t.major == 4 && a.indexOf("msie 5") == -1
    t.ie5     = t.ie && t.major == 4 && a.indexOf("msie 5.0") != -1
    t.ie5up   = t.ie && !t.ie3 && !t.ie4
    t.mac     = a.indexOf("mac") != -1
    t.opera   = a.indexOf("opera") != -1
    t.opera5up   = a.indexOf("opera") != -1
    t.doc     = null // reference to the Document object of the window in which HLib is loaded
})

// Document object with basic functionality
// You will find many additional features in the seperated document module.

// Document instances are managed and created automatically by the library
// On demand HLib.Document either creates a new Document instance
// or hands out a reference (which is stored in HLib.__docs) to an
// already existing instance.
// win: reference to a browser window (frame) object which should be handled by Document
HLib.Document = function (win) {
    if (!isDefined(win)) win = window
    if (win._hObj) return win._hObj // Document instance for this window already exists

    this.win = win
    this.doc = this.win.document

    // store a reference to the new instance in HLib.__docs
    HLib.__docs[HLib.__docs.length] = this

    // attach to the native object a reference to the corresponding HLib object
    this.win._hObj = this.doc._hObj = this

    this.children = [] // holds references to all child layers

    // store a reference to DOM2's defaultView
    if (HLib.client.gecko) this.view = this.doc.defaultView

    if (HLib.client.nav4) this.recyclebin = [] // needed for efficient layer handling in Netscape4
};

(function () {
    var hdp = HLib.Document.prototype

    // delete all child layers
    hdp.deleteAllChildren = function () {
        var cn = this.children, i = cn.length
        while (i-- > 0) cn[i].destroy()
    }

    // destroy the document instance and all its layers
    hdp.destroy = function () {
        this.deleteAllChildren()
        this.children = this.all = this.win = this.doc = null
        if (HLib.browser.nav4) this.recyclebin = null
        var ds = HLib.__docs, i = ds.length, f = i - 1
        while (i-- > 0) if (ds[i] ==  this) { ds[i] = ds[f]; delete ds[f]; ds.length--; break }
    }
}) ()

HLib.client.doc = new HLib.Document(window) // insert a reference to the current document

