///<reference path="../TESCO.js" />
///<reference path="../event.js" />
///<reference path="../eventManager.js" />
///<reference path="../exception.js" />
///<reference path="../node.js" />
///<reference path="../position.js" />
///<reference path="../effects.js" />

TESCO.UI.Flyout = (function() {

    //	private static
    //#region 
    var _flyout;
    var _requests = {};
    var _running = 0;
    var _infoContainer;
    var UI = TESCO.UI;
    var NODE = TESCO.system.DOM.node;
    var EVENT = TESCO.system.event;
    var CONFIG = TESCO.sites.Configuration;

    CONFIG.merge({
        "flyout": {
            "hideDelay": 250,
            "fadeOutInterval": 5,
            "fadeInInterval": 1,
            "maxRequests": 5		// set the maximum number of concurrent ajax calls
        }
    });

    //    function _assembleError(msg) {
    //        var _container = new TESCO.UI.InfoContainer()
    //        _container.content.appendChild(TESCO.locale.message.create(msg));
    //        return _container.container;
    //    }

    function _cache(content, id, callback) {
        //  Called when the ajax call completes
        //  Put the content in the cache and show it if still wanted
        _flyout.cache.setItem(id, content);   //  add to the cache
        delete _requests[id];
        _running--;
        if (_flyout.key === id && _flyout.state !== _flyout.states.none) {
            callback(content);   //  show the new stuff if _flyout.key has not changed
        }
    }

    function _post(url, callback, entity, id) {
        var _connection = new TESCO.system.connection.ajax(false);
        EVENT.attach(_connection, "complete",
		    function(e) {
		        _cache(e.response.response.content.nodeValue.firstChild, id, callback);
		    }
		);
        //  send the request
        _requests[id] = _connection.request(url, entity);
        //	XMLHTTP errors
        EVENT.attach(_connection, "error",
			function(e) {
			    //	_cache(_assembleError(e.exception.message), id, callback);
			    _snapHide();
			}
		);    }

    function _resize(content) {
        _flyout.css.display = "block";
        var _content = new UI.Rectangle(content);
        _content.css.display = "block";
        _flyout.resize(CONFIG.infoContainer.left + _content.width + CONFIG.infoContainer.right, _content.height);
        /*@cc_on
        if (_flyout.iframe) {
            _flyout.iframe.resize(
				_flyout.width - (CONFIG.infoContainer.left + CONFIG.infoContainer.right),
				_flyout.height - (CONFIG.infoContainer.top + CONFIG.infoContainer.bottom)
			);
        }
        @*/
    }
    //#endregion

    //	private instance
    //#region
    function _hide() {
        _flyout.state = _flyout.states.none;
        /*@cc_on
        if (_flyout.iframe)
            _flyout.iframe.hide();
        @*/
        _flyout.css.display = "none";
        _constructor.base.hide.call(this);
        _flyout.key = null;
        _flyout.mouseover = null;
    }

    function _position(e) {
        var _target = new UI.Rectangle(e.target);
        var _targetWidth = e.target.offsetWidth;
        var _targetHeight = e.target.offsetHeight;
        var _offset = _target.getScreenCoordinates();
        var _winSize = UI.document.getWindowSize();
        var _scroll = UI.document.getScrollXY();
        var _x = _offset.x;
        switch (this.position.x) {
            case _flyout.position.x.nudge:
                _x = this.nudgeX(_target); //	not implemented in Wine
                break;      
            case _flyout.position.x.related:
                _x = this.related(_target,'x');
                break;
			case _flyout.position.x.centrenudge:
                _x += Math.floor((_target.width / 2) - (_infoContainer.container.offsetWidth / 2));
                _x = this.centreNudgeX(_x); //	not implemented in Wine
                break;
            case _flyout.position.x.leftcentre:
                _x += Math.floor(_target.width / 2);
                break;
            case _flyout.position.x.centre:
                _x += Math.floor((_target.width / 2) - (_infoContainer.container.offsetWidth / 2));
                break;
            case _flyout.position.x.centreoffset:
                if ((_winSize.innerWidth / 2) < (_offset.x - _scroll[0])) {
                    //  left half of the screen
                    _x -= _infoContainer.container.offsetWidth;
                } else {
                    //  right half of screen      
                    _x += _targetWidth;      
                }      
                break;     
        }
        var _y = _offset.y;
        switch (this.position.y) {
            case _flyout.position.y.top:
                _y -= _infoContainer.container.offsetHeight;
                break;
			case _flyout.position.y.bottom:
                _y += _target.height;
                break;
            case _flyout.position.x.related:
                _y = this.related(_target,'y');
                break;
            case _flyout.position.y.centreoffset:
                if ((_winSize.innerHeight / 2) < (_offset.y - _scroll[1])) { 
                    // bottom half of the screen
                    _y -= _infoContainer.container.offsetHeight;
                } else { 
                    //  top half of screen
                    _y += _targetHeight;
                }
                break;
        }
        _flyout.moveIntoView(_x, _y);
        /*@cc_on
        if (_flyout.iframe) {
            _flyout.iframe.moveBy(CONFIG.infoContainer.left, CONFIG.infoContainer.top);
        }
        @*/
    }
    
    function _loading(e) {
        //  show loading message, quick
        _flyout.state = _flyout.states.loading;
        _show.call(this, e, TESCO.sites.retail.UI.Loader.rect, true, true);
    }

    function _show(e, content, fast, loading) {
        //  show content
        NODE.removeChildNodes(_infoContainer.content);
        NODE.append(_infoContainer.content, content);      
        _resize(content);
        _position.call(this, e);
        this.raise();
        this.fadeUp(fast || false);
        if (!loading) {
            this.loaded(content);
        }
    }

    function _snapHide() {
        if (!_flyout.mouseover) {
            _flyout.opacity.stop();
            _flyout.opacity.set(0);
            _hide.call(_flyout);
        }
    }
    //#endregion

    //  constructor
    function _constructor() {
        EVENT.manager.call(this, "over", "out");
        _constructor.base.constructor.call(this, document.createElement("div"), TESCO.system.browser.ie6);
        this.css.position = "absolute";
        this.rect.setAttribute("id", "flyout");

        _infoContainer = new TESCO.sites.retail.UI.InfoContainer();
        this.rect.appendChild(_infoContainer.container);

        _constructor.base.hide.call(this);
        EVENT.document.addEventListener("beforeload",
            function() {
                document.body.appendChild(_flyout.rect);
                /*@cc_on
                if (_flyout.iframe) {
                    document.body.appendChild(_flyout.iframe.rect);
                    _flyout.opacity.addEventListener("complete",
						function() {
						    if (_flyout.css.visibility === "visible")
						        _flyout.iframe.show();
						}
					);
                }
                @*/
                EVENT.attach(document.body, "mouseover",
	                function(e) {
	                    if (_flyout.mouseover) {
	                        _flyout.mouseover = false;
	                        _flyout.dispatchEvent("out");
	                    }
	                }
                );
                EVENT.attach(_flyout.rect, "mouseover",
                    function(e) {
                        e.stop();
                        _flyout.mouseover = true;
                        _flyout.dispatchEvent("over", {});
                    }
                );
                EVENT.attach(document.body, "click", _snapHide);
                EVENT.attach(window, "resize", _snapHide);
            }
        );
        return this;
    }
    _constructor.extend(UI.Rectangle.Position);

    //  public instance
    //#region
    _constructor.prototype.load = function(e, id, url, entity) {
        if (_flyout.cache.exists(id)) {
            this.show(e, _flyout.cache.getItem(id));
        } else {  //  request doesn't already exist?
            //  show loader
            _loading.call(this, e);
            if (!_requests[id]) {
                //  Check if we have too many active requests already
                if (++_running > CONFIG.flyout.maxRequests) {
                    for (var _key in _requests) {
                        if (_requests[_key] && _requests[_key].abort) {
                            //  abort oldest request 
                            _requests[_key].abort();
                            //  delete from fifo stack
                            delete _requests[_key];
                            _running--;
                            break;
                        }
                    }
                }
                var _self = this;
                _post(url,
					function(content) {
					    _self.show(e, content);
					},
					entity, id
				);
            }
        }
    }

    _constructor.prototype.NAME = "TESCO.UI.Flyout";

    _constructor.prototype.fadeUp = function(fast) {
        _flyout.opacity.stop();
        _flyout.opacity.fadeUp({
            "interval": (fast ? 1 : CONFIG.flyout.fadeInInterval)
        });
    }

    _constructor.prototype.fadeDown = function() {
        _flyout.opacity.stop();
        /*@cc_on
        if (_flyout.iframe)
            _flyout.iframe.hide();
        @*/
        _flyout.opacity.fadeDown({
            "interval": CONFIG.flyout.fadeOutInterval,
            "steps": 20
        });
    }

    //  augment base hide method
    _constructor.prototype.hide = function() {
        _hide.call(this);
    }

    //  augment base show method
    _constructor.prototype.show = function(e, content, fast) {
        _flyout.state = _flyout.states.showing;
        _show.apply(this, arguments);
    }
    //#endregion

    //  create instance
    _flyout = new _constructor();

    //  public static
    //#region
    _flyout.opacity = new TESCO.UI.effects.Opacity(_flyout.rect, _flyout);

    _flyout.states = {
        "none": 0,
        "loading": 1,
        "showing": 2
    }

    _flyout.state = _flyout.states.none;

    _flyout.key = null;

    _flyout.position = {
        "x": {
            "left": 0,
            "leftcentre": 1,
            "nudge": 2, //	not implemented in Wine
            "centreoffset": 3,
            "centre" : 4,
            "centrenudge" : 5, //	not implemented in Wine,
            "related" : 6
        },
        "y": {
            "bottom": 0,
            "centreoffset": 1,
            "top" : 2,
            "related" : 3
        }
    }

    _flyout.mouseover = null;

    _flyout.cache = new TESCO.system.Cache();
    //#endregion

    //  return instance
    return _flyout;
})();