/**
 * Simple visual effect functions
 */

/**
 * Makes element, represented by either its document id or object, to
 * change their value at given rate, causing them to (dis)apearÐdepending on
 * sign of rate value
 */
function __valueEffect(element, rate, nextOperation) {

    if(!element) {
        throw Error("The 'element' parameter is required");
    }

    var image = element['src'] ? element : document.getElementById(element);

    if(image && !image['busy']) {
        image['busy'] = true;
        var ef = function() {
            var opacity = image.style.opacity || 1;
            if(!rate)
                rate = .1;
            if((rate > 0 && opacity > 0) || (rate < 0 && opacity < 1)) {
                image.style.opacity = opacity - rate;
                window.setTimeout(ef, 50);
            } else {
                //window.clearInterval(h);
                image['busy'] = false;
                if(nextOperation)
                    window.setTimeout(nextOperation, 0);
            }
        };

        /*var h = */window.setTimeout(ef, 50);
    }
}

/**
 * Makes an element appear in a gradual manner
 */
function appear(element) {
    __valueEffect(element, -0.1);
}

/**
 * Makes an element disappear in a gradual manner (like Chesshire cat)
 */
function disappear(element) {
    __valueEffect(element);
}

/**
 * Zooms in or out, given image, depending on the ratio.
 */
function zoom(image, ratio) {
    if(!image || !ratio)
        throw Error('The "image" or/and "ratio" parameter is required');

    var img = image['src'] ? image : document.getElementById(image);

    if(img) {
        img.width *= ratio;
        img.height *= ratio;
    }
}

/**
 * Figures absolute coordinates of a DOM elementÐcode is heavily influenced
 * by http://www.quirksmode.org/js/findpos.html
 */
function getAbsoluteCoordinates(element) {
    var coords = {top: 0 , left: 0};

    if(element.offsetParent) {
        coords.left = element.offsetLeft;
        coords.top = element.offsetTop;
        while(element = element.offsetParent) {
            coords.left += element.offsetLeft;
            coords.top += element.offsetTop;
        }
    }

    return coords;
}

/**
// Calculates top/left position for a rectangular object of given size with it's
// center at given point. If calculated position results in object not
// completely visible in current document then it is adjusted. Returns a point
// object of calculated top/left corner.
//
// @param point an object of the following layout: {X:,Y:}
// @param size an object -- {width:, height:}
// @return an object -- {X:,Y:}
**/
function cvcpof(point, size) {
    var topLeft = {X: point.X - size.width/2, Y: point.Y - size.height/2 };

    return fit(topLeft, size);
}

/**
// Calculates top/left position for a rectangular object of given size and
// desired location. If calculated position results in object not
// completely visible in current document then it is adjusted. Returns a point
// object of calculated top/left corner.
//
// @param point an object of the following layout: {X:,Y:}
// @param size an object -- {width:, height:}
// @return an object -- {X:,Y:}
**/
function fit(point, size) {

    if(!point || !point.X || !point.Y)
        throw Error("Invalid input: 'point' argument must be a " +
                    "non-null object, with two integer properties: X and Y");

    if(! size || !size.width || !size.height)
        throw Error("Invalid input: 'size' argument must be a " +
                    "non-null object, with two integer properties: width "+
                    "and height");

    var pW = document.body.scrollWidth,
        pH = document.body.scrollHeight;

    var w = size.width,
        h = size.height;

    var dX = point.X + w > pW ? pW - w : point.X;
    var dY = point.Y + h > pH ? pH - h : point.Y;


    return {X: Math.max(dX, 0), Y: Math.max(dY, 0)};
}

/**
// Connects DOM element, pointed to by 'initiatingElement' argument with
// a 'popupElement' such that when mouse pointer appears above the initiating
// element, the popup element appears under, or to one of the sides of
// initiating element. Should the mouse pointer leave the area of the initiating
// or popup elements, the latter will be hidden.
//
// @param initiatingElement a DOM object or an id thereof
// @param popupElement      a DOM object or an id thereof
**/
function connectPopup(initiatingElement, popupElement) {

    if(!initiatingElement)
        throw Error("The 'initiatingElement' argument is required");
    if(!popupElement)
        throw Error("The 'popupElement' argument is required");

    var domInitElem = document.getElementById(initiatingElement)
                        || initiatingElement;
    var domPopupElem = document.getElementById(popupElement) || popupElement;

    if(!domInitElem.id)
        throw Error("Failed to obtain iniating DOM element");
    if(!domPopupElem.id)
        throw Error("Failed to obtain popup DOM element");

    var closePopupTimeout = null;
    domInitElem.onmouseover = function() {
        if(closePopupTimeout)
            window.clearTimeout(closePopupTimeout);
        var myTopLeft = getAbsoluteCoordinates(this);
        domPopupElem.style.position = 'absolute';
        domPopupElem.style.top = myTopLeft.top + this.offsetHeight;
        domPopupElem.style.left = myTopLeft.left;

        hidePref();

        domPopupElem.style.display = 'block';
        if(domPopupElem.offsetWidth < this.offsetWidth)
            domPopupElem.style.width = this.offsetWidth;
    };

    domInitElem.onmouseout = function() {
        closePopupTimeout = window.setTimeout(function() {
            domPopupElem.style.display = 'none';

            showPref();
        }, 200);
    };

    domPopupElem.onmouseover = function() {
        if(closePopupTimeout)
            window.clearTimeout(closePopupTimeout);
    }

    domPopupElem.onmouseout = domInitElem.onmouseout;

    domInitElem.onmousemove = domInitElem.onmouseover;
}

function hidePref() {
    var browser=navigator.appName;
    if (browser=="Microsoft Internet Explorer") {
        var narrowBy0 = document.getElementById("narrowByAttr0");
        var narrowBy1 = document.getElementById("narrowByAttr1");
        var narrowBy2 = document.getElementById("narrowByAttr2");
        var narrowBy3 = document.getElementById("narrowByAttr3");
        var narrowBy4 = document.getElementById("narrowByAttr4");
        var sortBy = document.getElementById("sortByAttr");
        var itemPer = document.getElementById("itemPerAttr");

        if (narrowBy0 != null) narrowBy0.style.display = 'none';
        if (narrowBy1 != null) narrowBy1.style.display = 'none';
        if (narrowBy2 != null) narrowBy2.style.display = 'none';
        if (narrowBy3 != null) narrowBy3.style.display = 'none';
        if (narrowBy4 != null) narrowBy4.style.display = 'none';
        if (sortBy != null) sortBy.style.display = 'none';
        if (itemPer != null) itemPer.style.display = 'none';
    }
}

function showPref() {
    var browser=navigator.appName;
    if (browser=="Microsoft Internet Explorer") {
        var narrowBy0 = document.getElementById("narrowByAttr0");
        var narrowBy1 = document.getElementById("narrowByAttr1");
        var narrowBy2 = document.getElementById("narrowByAttr2");
        var narrowBy3 = document.getElementById("narrowByAttr3");
        var narrowBy4 = document.getElementById("narrowByAttr4");
        var sortBy = document.getElementById("sortByAttr");
        var itemPer = document.getElementById("itemPerAttr");

        if (narrowBy0 != null) narrowBy0.style.display = '';
        if (narrowBy1 != null) narrowBy1.style.display = '';
        if (narrowBy2 != null) narrowBy2.style.display = '';
        if (narrowBy3 != null) narrowBy3.style.display = '';
        if (narrowBy4 != null) narrowBy4.style.display = '';
        if (sortBy != null) sortBy.style.display = '';
        if (itemPer != null) itemPer.style.display = '';
    }
}

/**
 *
 */
function SlideShow() {}

SlideShow.prototype = {

    preload: function() {
        if(arguments.length > 1) {
            var imgId = arguments[0];
            var protoImage = imgId['src'] ? imgId
                                          : document.getElementById(imgId);
            if(!protoImage)
                throw Error('Prototype image is not found: ' + imgId);

            var h = protoImage.height;
            var w = protoImage.width;

            for(var i = 1; i < arguments.length; ++i) {
                var image = new Image();
                image.src = arguments[i];
                if(image.height > image.width)
                    image.height = h;
                else
                    image.width = w;
            }
        }
    },

    start: function() {
        if(arguments.length > 1) {

            var imgId = arguments[0];
            var protoImage = imgId['src'] ? imgId
                                          : document.getElementById(imgId);

            if(protoImage && !protoImage['sliding']) {

                var h = protoImage.height;
                var w = protoImage.width;

                protoImage['sliding'] = true;
                var src = protoImage.src;

                var root = {image: null, next: null};
                var current = root;
                for(var i = 1; i < arguments.length; ++i) {
                    current.image = arguments[i];

                    if(i + 1 < arguments.length) {
                        current.next = {image: null, next: null};
                        current = current.next;
                    }
                }

                var self = this;
                var slide = function(s) {
                    if(s && !protoImage['stop']) {
                        var url = s.image;
                        __valueEffect(protoImage, 0.1, function() {
                            if(protoImage.width > protoImage.height)
                                protoImage.width = w;
                            else
                                protoImage.height = h;
                            protoImage.src = url;
                            __valueEffect(protoImage, -0.1, function() {
                                window.setTimeout(function() {
                                    slide(s.next);
                                }, 500);
                            });
                        });
                    } else {
                        if(!protoImage['stop']) {
                            __valueEffect(protoImage, 0.1, function() {
                                protoImage.src = src;
                                __valueEffect(protoImage, -0.1, function() {
                                    protoImage['sliding'] = false;
                                });
                            });
                        } else {
                            protoImage.src = src;
                            protoImage['sliding'] = false;
                        }

                        protoImage['stop'] = false;
                    }
                };

                slide(root);
            }
        }
    },

    stop: function(image) {
        var img = image['src'] ? image : document.getElementById(image);
        if(img && img['sliding'] && !img['stop']) {
            img['stop'] = true;
        }
    }
};

function ZoomingSlideShow(width, height) {
    if(!width || !height)
        throw Error("The 'width' or/and 'height' arguments are required");

    this.width = width;
    this.height = height;
}
ZoomingSlideShow.prototype = new SlideShow();
ZoomingSlideShow.prototype.constructor = ZoomingSlideShow;
ZoomingSlideShow.prototype.base = SlideShow.prototype;
ZoomingSlideShow.prototype.width = null;
ZoomingSlideShow.prototype.height = null;
ZoomingSlideShow.prototype.start = function() {
    if(arguments.length > 1) {
        var imgId = arguments[0];
        var protoImage = imgId['src'] ? imgId
                                      : document.getElementById(imgId);

        if(protoImage) {

            if(protoImage['sliding'])
                this.stop(protoImage);

            // Dimesions of original, thumbnail image
            var h = protoImage.height;
            var w = protoImage.width;
            var position = protoImage.style.position;

            // Coordinates of the proto image center
            var coords = getAbsoluteCoordinates(protoImage);
            var protoImgCenter = {Y: coords.top + h/2 + 60,
                                  X: coords.left + w/2};
            var slideWndPos = cvcpof(protoImgCenter,
                                     {width: this.width + 1,
                                      height: this.height + 1});
            // Make a slideshow window
            var slideWnd = document.createElement('DIV');
            slideWnd.style.position = 'absolute';
            slideWnd.style.top = slideWndPos.Y;
            slideWnd.style.left = slideWndPos.X;
            slideWnd.style.width = this.width + 1;
            slideWnd.style.height = this.height + 1;
            slideWnd.style.border = '2px solid silver';

            var closeSlideWnd = function() {
                try {
                    document.body.removeChild(slideWnd);
                } catch(x) {
                    // supress
                }
            };

            slideWnd.onmouseout = closeSlideWnd;

            var hostImage = document.createElement('IMG');
            hostImage.src = arguments[1];
            if(hostImage.height > hostImage.width)
                hostImage.height = this.height;
            else
                hostImage.width = this.width;
            slideWnd.appendChild(hostImage);
            document.body.appendChild(slideWnd);

            if(arguments.length < 3)
                return;

            // Preload images
            var root = {image: null, next: null};
            var current = root;
            for(var i = 2; i < arguments.length; ++i) {
                current.image = new Image();
                current.image.src = arguments[i];

                if(i + 1 < arguments.length) {
                    current.next = {image: null, next: null};
                    current = current.next;
                }
            }

            var self = this;
            var slide = function(s) {
                if(s) {
                    var url = s.image.src;
                    __valueEffect(hostImage, 0.1, function() {
                        hostImage.src = url;
                        if(hostImage.height > hostImage.width)
                            hostImage.height = self.height;
                        else
                            hostImage.width = self.width;
                        __valueEffect(hostImage, -0.1, function() {
                            window.setTimeout(function(){
                                slide(s.next);
                            }, 1000);
                        });
                    });
                } else {
                    /*slideWnd.onmouseout = null;
                    var closeBtn = document.createElement('INPUT');
                    closeBtn.type = 'submit';
                    closeBtn.value = 'Close';
                    closeBtn.style.position = 'absolute';
                    closeBtn.style.right = 3;
                    closeBtn.style.bottom = 3;
                    closeBtn.onclick = closeSlideWnd;
                    slideWnd.appendChild(closeBtn);*/
                }
            };

            window.setTimeout(function() { slide(root); }, 1000);
        }
    }
};

var slider = new SlideShow();
var zoomingSlider = new ZoomingSlideShow(320, 320);
var zoomingSliderLarger = new ZoomingSlideShow(450, 450);

