var classAirOverlay = function(lib, settings)
{
    // Module references //

    var _lib = lib || null;
    var _modules = {};
    var _this = this;
    this.version = '1.0';
    this.toString = function(){ return _lib.toString() + ' - Overlay'; };
    arguments.callee.toString = function(){ return _lib.toString() + ' - Overlay - Constructor'; };

    // Private properties //

    /**
    * Module memory.
    * @type Object
    */
    var _memory = {};

    // Public properties //

    /**
    * DOM references used by module.
    * @type Object
    */
    this.dom =
    {
        close : null,
        closeTrigger : null,
        content : null,
        overlay : null,
        lock : null
    };

    /**
    * Module settings.
    * @type Object
    */
    this.settings =
    {
        cssDirPath : '/styles/shared/air/module',
        closeButtonContent : 'Close',
        closeButtonFloating : true,
        closeButtonPlacement : 'top',
        lockOpacity : 60,
        prefixes :
        {
            closeButtonClassName : 'module-overlay-close',
            closeButtonID : '_close',
            containerClassName : 'module-overlay',
            containerID : 'overlay_',
            contentClassName : 'module-overlay-content',
            contentID : '_content',
            lockClassName : 'module-overlay-lock',
            lockID : '_lock',
            spacerClassName : 'module-overlay-spacer'
        },
        stylesheetVersion : '1.0'
    };

    /**
    * Current state.
    * @type String
    */
    this.state = '';

    // Private functions //

    /**
    * Initialize script.
    * @ignore
    */
    function _init(settings)
    {
        // Verify that library is loaded and linked
        if(_lib === null)
        {
            alert('Library missing for ' + _this.toString());
            return;
        }

        // Settings
        _this.settings = _lib.mergeObjects(_this.settings, settings);

        _lib.addEvent(window, 'resize', _this.fixResize);
        _lib.loadStylesheet('air_overlay', _this.settings.stylesheetVersion, '/' + _lib.trim(_this.settings.cssDirPath, '/') + '/');
    }

    // Public functions //

    /**
    * Create close button for overlay.
    *
    * @param {String} id        Element ID for close button.
    *                           Optional. Default: empty
    * @param {String} content   Content of close button.
    *                           Optional. Default: settings.closeButtonContent
    * @param {String} className Close button additional class name(s).
    *                           Optional. Default empty
    * @version 1.0 2010-09-13
    * @author Mathias Petersson
    * @return DOM element.
    * @type DOM
    */
    this.generateCloseButton = function(id, content, className)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            var dom = {};
            dom.container = document.createElement('DIV');
            dom.container.className = options.className || _lib.settings.cssPrefix + _this.settings.prefixes.closeButtonClassName;
            dom.close = document.createElement('SPAN');
            dom.close.innerHTML = options.content || _this.settings.closeButtonContent;
            dom.container.appendChild(dom.close);
            return dom.container;
        }
    };
    this.generateCloseButton.rules =
    {
        required : [],
        types :
        {
            id : ['string'],
            content : ['string'],
            className : ['string']
        }
    };

    /**
    * Hide overlay.
    *
    * @version 1.0 2010-09-22
    * @author Mathias Petersson
    */
    this.hide = function()
    {
        if(_this.dom.overlay)
        {
            _this.dom.overlay.style.visibility = 'hidden';
            _this.state = 'hidden';
            _lib.setOpacity(_this.dom.overlay, 0);
        }
        if(_this.dom.lock)
        {
            _this.dom.lock.style.display = 'none';
        }
    };

    /**
    * Center overlay.
    *
    * @version 1.0 2010-09-13
    * @author Mathias Petersson
    */
    this.setOverlayMargins = function()
    {
        if(_this.dom.overlay)
        {
            setTimeout(function()
            {
                var dim = _lib.getDimensions(_this.dom.overlay).body;
                _this.dom.overlay.style.marginLeft = (Math.floor(dim.width / 2) * -1) + 'px';
                _this.dom.overlay.style.marginTop = (Math.floor(dim.height / 2) * -1) + 'px';
                if(_this.state == '')
                {
                    _this.show();
                }
            }, 200);
        }
    };

    /**
    * Make overlay visible.
    *
    * @version 1.0 2010-09-22
    * @author Mathias Petersson
    */
    this.show = function()
    {
        if(_this.dom.overlay)
        {
            _this.dom.overlay.style.visibility = 'visible';
            _this.state = 'visible';
            _lib.setOpacity(_this.dom.overlay, 100);
        }

        if(_this.dom.lock)
        {
            _this.dom.lock.style.display = 'block';
        }
    };

    /**
    * Close overlay and resets module.
    *
    * @version 1.0 2010-09-22
    * @author Mathias Petersson
    */
    this.close = function()
    {
        var reLockId = new RegExp(_this.settings.prefixes.closeButtonID, 'gi');
        _lib.removeElement(_this.dom.overlay);
        _lib.removeElement(_this.dom.overlay.id.replace(reLockId) + _this.settings.prefixes.lockID);
        _this.dom.content = null;
        _this.dom.overlay = null;
        _this.dom.lock = null;
        _this.dom.close = null;
        _this.dom.closeTrigger = null;
        _this.state = '';
    };

    /**
    * Handle window resize.
    *
    * @version 1.0 2010-09-13
    * @author Mathias Petersson
    */
    this.fixResize = function()
    {
        if(_this.dom.lock)
        {
            var dim;
            _this.dom.lock.style.width = '100%';
            _this.dom.lock.style.height = '100%';
            dim =
            {
                viewport : _lib.getDimensions(),
                lock : _lib.getDimensions(_this.dom.lock)
            };
            dim.viewport =
            {
                width : (dim.viewport.viewport.width > dim.viewport.width ? dim.viewport.viewport.width : dim.viewport.width),
                height : (dim.viewport.viewport.height > dim.viewport.height ? dim.viewport.viewport.height : dim.viewport.height)
            };
            dim.lock =
            {
                width : (dim.lock.viewport.width > dim.lock.width ? dim.lock.viewport.width : dim.lock.body.width),
                height : (dim.lock.viewport.height > dim.lock.height ? dim.lock.viewport.height : dim.lock.body.height)
            };
            _this.dom.lock.style.width = (dim.viewport.width > dim.lock.width ? dim.viewport.width : dim.lock.width) + 'px';
            _this.dom.lock.style.height = (dim.viewport.height > dim.lock.height ? dim.viewport.height : dim.lock.height) + 'px';
        }
    };

    /**
    * Link module pointers between modules.
    *
    * @param {Object} modules   Object containing modules.
    *                           Required.
    * @version 1.0 2010-09-21
    * @author Mathias Petersson
    */
    this.linkModules = function(modules)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            var x;
            for(x in modules)
            {
                if(modules[x].toString() != _this.toString())
                {
                    _modules[x] = modules[x];
                }
            }
        }
    };
    this.linkModules.rules =
    {
        required : ['modules'],
        types :
        {
            modules : ['object']
        }
    };

    /**
    * Create overlay.
    *
    * @param {Boolean} generateCloseButton  If to create and append a close button.
    *                                       Optional. Default: true
    * @param {Boolean} lockBackground       If to lock the background.
    *                                       Optional. Default: true
    * @param {String} closeButtonPlacement  Close button placement. Valid values are: top, bottom
    *                                       Optional. Default: settings.closeButtonPlacement
    * @param {Boolean} closeButtonFloating  Defines if the close button shall be absolute positioned or not.
    *                                       Optional. Default. settings.closeButtonFloating
    * @param {Function} closeButtonAction   Action for close button click event.
    *                                       Optional. Default: close()
    * @version 1.0 2010-09-21
    * @author Mathias Petersson
    */
    this.open = function(generateCloseButton, lockBackground, closeButtonPlacement, closeButtonFloating, closeButtonAction)
    {
        var options = _lib.isValidInputs();
        if(options)
        {
            var dom = {};
            options.generateCloseButton = (options.generateCloseButton !== undefined ? options.generateCloseButton : true);
            options.lockBackground = (options.lockBackground !== undefined ? options.lockBackground : true);
            options.closeButtonPlacement = options.closeButtonPlacement || _this.settings.closeButtonPlacement;
            options.closeButtonFloating = (options.closeButtonFloating !== undefined ? options.closeButtonFloating : _this.settings.closeButtonFloating);
            options.closeButtonAction = options.closeButtonAction || _this.close;
            dom.container = document.createElement('DIV');
            dom.container.id = _lib.randomID(8, _this.settings.prefixes.containerID);
            dom.container.className = _lib.settings.cssPrefix + _this.settings.prefixes.containerClassName;
            dom.spacer = document.createElement('DIV');
            dom.spacer.className = _lib.settings.cssPrefix + _this.settings.prefixes.spacerClassName;
            dom.content = document.createElement('DIV');
            dom.content.id = dom.container.id + _this.settings.prefixes.contentID;
            dom.content.className = _lib.settings.cssPrefix + _this.settings.prefixes.contentClassName;
            dom.spacer.appendChild(dom.content);
            dom.container.appendChild(dom.spacer);
            if(options.lockBackground)
            {
                if(!(dom.lock = _lib.getDOM(dom.container.id + _this.settings.prefixes.lockID)))
                {
                    dom.lock = document.createElement('DIV');
                    dom.lock.id = dom.container.id + _this.settings.prefixes.lockID;
                    dom.lock.className = _lib.settings.cssPrefix + _this.settings.prefixes.lockClassName;
                    _lib.setOpacity(dom.lock, _this.settings.lockOpacity);
                    document.body.appendChild(dom.lock);
                    dom.container.className += ' locked';
                }
                _this.dom.lock = dom.lock;
                _this.fixResize();
                dom.dom.style.display = 'block';
                _lib.bringToFront(dom.lock);
            }
            if(options.generateCloseButton)
            {
                dom.close = _this.generateCloseButton();
                dom.close.id = dom.container.id + _this.settings.prefixes.closeButtonID;
                dom.close.className += (options.closeButtonFloating ? ' floating' : '');
                switch(options.closeButtonPlacement)
                {
                    default:
                    case 'top':
                        dom.spacer.insertBefore(dom.close, dom.content);
                    break;
                    case 'bottom':
                        dom.close.className += ' bottom';
                        dom.spacer.appendChild(dom.close);
                    break;
                }
                _lib.bringToFront(dom.close);
                _this.dom.close = dom.close;
            }
            _lib.bringToFront(dom.container);
            document.body.appendChild(dom.container);
            (function(id)
            {
                var element = _lib.getDOM(id);
                if(element)
                {
                    element.onmousedown = function()
                    {
                        _lib.bringToFront(this);
                    };
                }
            })(dom.container.id);
            if(options.generateCloseButton)
            {
                (function(id)
                {
                    setTimeout(function()
                    {
                        var close = _lib.getDOM(id);
                        if(close)
                        {
                            var closeTrigger = _lib.getDOM(null, 'span', null, null, close, true, false, true);
                            closeTrigger = closeTrigger[0];
                            closeTrigger.onclick = options.closeButtonAction;
                            _this.dom.closeTrigger = closeTrigger;
                        }
                    }, 250);
                })(dom.close.id);
            }
            _this.dom.overlay = dom.container;
            _this.dom.content = dom.content;
        }
    };
    this.open.rules =
    {
        required : [],
        types :
        {
            generateCloseButton : ['boolean'],
            lockBackground : ['boolean'],
            closeButtonPlacement : ['string'],
            closeButtonFloating : ['boolean'],
            closeButtonAction : ['function']
        }
    };

    // Initialize script //

    _init(settings);

    return arguments.callee.toString();
};
