﻿//////////////////////////
// Interface Observable //
//////////////////////////

Observable = {
    addListener: function(listenerObj) {
        if (typeof this.listeners == 'undefined') {
            this.listeners = [];
        }
        for (var i = 0; i < this.listeners.length; i++) {
            if (this.listeners[i] == listenerObj) return;
        }
        this.listeners[this.listeners.length] = listenerObj;
    },

    removeListener: function(listenerObj) {
        for (var i = 0; i < this.listeners.length; i++) {
            if (this.listeners[i] == listenerObj) {
                this.listeners.splice(i, 1);
                return;
            }
        }
    },

    notifyListeners: function(eventName, eventObj) {
        if (typeof this.listeners == 'undefined') return;
        for (var i = 0; i < this.listeners.length; i++) {
            if (typeof this.listeners[i][eventName] != "undefined") {
                this.listeners[i][eventName](eventObj);
            }
        }
    }
};

DHTMLApi = {

    CSS: {
        getStyle: function(element, name) {
            var styleObj;
            if (element.style[name]) return element.style[name];
            if (element.currentStyle) {
                name = name.replace(/-([a-z])/g, function(matched) {
                    return matched.toUpperCase().slice(1, matched.length);
                });
                return element.currentStyle[name];
            }
            if (document.defaultView && document.defaultView.getComputedStyle) {
                name = name.replace(/([A-Z])/g, "-$1");
                name = name.toLowerCase();
                styleObj = document.defaultView.getComputedStyle(element, "");
                return styleObj && styleObj.getPropertyValue(name);
            } else {
                return null;
            }
        },

        setProperties: function(element, properties) {
            var oldProperties = {};
            for (var i in properties) {
                oldProperties[i] = element.style[i];
                element.style[i] = properties[i];
            }
            return oldProperties;
        },

        setClass: function(element, addClassesArray, removeClassesArray) {
            var currentClasses = new Array();
            var newClasses = new Array();
            var removedClasses = new Array();
            findWordsExp = new RegExp("\\w+", "g");
            var result;
            while ((result = findWordsExp.exec(element.className)) != null) currentClasses.push(result[0]);
            for (var i = 0; i < addClassesArray.length; i++) {
                var classExists = false;
                for (var j = 0; j < currentClasses.length; j++) {
                    if (currentClasses[j] == addClassesArray[i]) {
                        classExists = true;
                        break;
                    }
                }
                if (!classExists) newClasses.push(addClassesArray[i]);
            }
            currentClasses = currentClasses.concat(newClasses);
            if (removeClassesArray == null) return removedClasses;
            for (var i = 0; i < removeClassesArray.length; i++) {
                for (var j = 0; j < currentClasses.length; j++) {
                    if (currentClasses[j] == removeClassesArray[i]) {
                        removedClasses = removedClasses.concat(currentClasses.splice(j, 1));
                        break;
                    }
                }
            }
            element.className = currentClasses.join(" ");
            return removedClasses;
        }
    },

    Position: {
        getXPosOnPage: function(element) {
            return element.offsetParent ? element.offsetLeft + DHTMLApi.Position.getXPosOnPage(element.offsetParent) : element.offsetLeft;
        },

        getYPosOnPage: function(element) {
            return element.offsetParent ? element.offsetTop + DHTMLApi.Position.getYPosOnPage(element.offsetParent) : element.offsetTop;
        },

        getXPosInElement: function(element, container) {
            return DHTMLApi.Position.getXPosOnPage(element) - DHTMLApi.Position.getXPosOnPage(container);
        },

        getYPosInElement: function(element, container) {
            return DHTMLApi.Position.getYPosOnPage(element) - DHTMLApi.Position.getYPosOnPage(container);
        },

        setXPosOnPage: function(element, posX) {
            var propertiesArray = {};
            if (element.parentNode != document.body) {
                element = element.parentNode.removeChild(element);
                document.body.appendChild(element);
            }
            if (DHTMLApi.CSS.getStyle(element, "position") != "absolute") {
                propertiesArray = { position: "absolute" };
            }
            propertiesArray.left = posX + "px";
            DHTMLApi.CSS.setProperties(element, propertiesArray);
        },

        setYPosOnPage: function(element, posY) {
            var propertiesArray = {};
            if (element.parentNode != document.body) {
                element = element.parentNode.removeChild(element);
                document.body.appendChild(element);
            }
            if (DHTMLApi.CSS.getStyle(element, "position") != "absolute") {
                propertiesArray = { position: "absolute" };
            }
            propertiesArray.top = posY + "px";
            DHTMLApi.CSS.setProperties(element, propertiesArray);
        },

        setXPos: function(element, posX, relativeToElement) {
            if (relativeToElement == undefined) {
                element.style.left = posX + "px";
            } else {
                if (DHTMLApi.CSS.getStyle(element.parentNode, "position") == "static") {
                    element.parentNode.style.position = "relative";
                }
                element.style.position = "absolute";
                element.style.left = (posX - DHTMLApi.Position.getXPosInElement(element.parentNode, relativeToElement)) + "px";
            }
        },

        setYPos: function(element, posY, relativeToElement) {
            if (relativeToElement == undefined) {
                element.style.top = posY + "px";
            } else {
                if (DHTMLApi.CSS.getStyle(element.parentNode, "position") == "static") {
                    element.parentNode.style.position = "relative";
                }
                element.style.position = "absolute";
                element.style.top = (posY - DHTMLApi.Position.getYPosInElement(element.parentNode, relativeToElement)) + "px";
            }
        }

    },

    Size: {

        getElementWidth: function(element) {
            var tempProperties, width;
            if (DHTMLApi.CSS.getStyle(element, "display") != "none") {
                return element.offsetWidth || parseInt(DHTMLApi.CSS.getStyle(element, "width"));
            }
            tempProperties = DHTMLApi.CSS.setProperties(element, { display: "block", visibility: "hidden", position: "absolute" });
            width = element.clientWidth || parseInt(DHTMLApi.CSS.getStyle(element, "width"));
            DHTMLApi.CSS.setProperties(element, { display: "", visibility: "", position: "" });
            DHTMLApi.CSS.setProperties(element, tempProperties);
            return width;
        },

        getElementHeight: function(element) {
            var tempProperties, height;
            if (DHTMLApi.CSS.getStyle(element, "display") != "none") {
                return element.offsetHeight || parseInt(DHTMLApi.CSS.getStyle(element, "height"));
            }
            tempProperties = DHTMLApi.CSS.setProperties(element, { display: "block", visibility: "hidden", position: "absolute" });
            height = element.clientHeight || parseInt(DHTMLApi.CSS.getStyle(element, "height"));
            DHTMLApi.CSS.setProperties(element, { display: "", visibility: "", position: "" });
            DHTMLApi.CSS.setProperties(element, tempProperties);
            return height;
        },

        getPageWidth: function() {
            return document.body.scrollHeight;
        },

        getPageHeight: function() {
            return Math.max(document.body.scrollHeight, document.body.offsetHeight);
        }

    },

    Visibility: {

        show: function(element) {
            element.style.display = element.__display__ || 'block';
        },

        hide: function(element) {
            var currentDisplay = DHTMLApi.CSS.getStyle(element, "display");
            if (currentDisplay != 'none') element.__display__ = currentDisplay;
            element.style.display = 'none';
        },

        setOpacity: function(element, percent) {
            if (element.filters) {
                element.style.filter = 'alpha(opacity=' + percent + ')';
            } else {
                element.style.opacity = percent / 100;
            }
        }

    },

    Browser: {

        getViewportWidth: function() {
            return self.innerWidth || (document.documentElement && document.documentElement.clientWidth) || document.body.clientWidth;
        },

        getViewportHeight: function() {
            return self.innerHeight || (document.documentElement && document.documentElement.clientHeight) || document.body.clientHeight;
        },

        getScrollX: function() {
            return self.pageXOffset || (document.documentElement && document.documentElement.scrollLeft) || document.body.scrollLeft;
        },

        getScrollY: function() {
            return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
        }
    }
};

MousePositionOnPage = {
    getX: function(mouseEvent) {
        return mouseEvent.pageX || mouseEvent.clientX + DHTMLApi.Browser.getScrollX();
    },
    getY: function(mouseEvent) {
        return mouseEvent.pageY || mouseEvent.clientY + DHTMLApi.Browser.getScrollY();
    }
};

function DOMEventHandle(element, type, handler) {
    this.element = element;
    this.type = type;
    this.handler = handler;
}

DOMEvent = {

    // public

    addDomListener: function(element, type, handler) {
        var handlers;
        if (!handler.__id__) handler.__id__ = DOMEvent.currentId++;
        if (!element.events) element.events = {};
        handlers = element.events[type];
        if (!handlers) {
            handlers = element.events[type] = {};
            if (element["on" + type]) {
                handlers[0] = element["on" + type];
            }
        }
        handlers[handler.__id__] = handler;
        element["on" + type] = DOMEvent.handleEvent;
        return new DOMEventHandle(element, type, handler);
    },

    removeListener: function(domEventHandleObj) {
        var element, type, handler;
        element = domEventHandleObj.element;
        type = domEventHandleObj.type;
        handler = domEventHandleObj.handler;
        if (element.events && element.events[type]) {
            delete element.events[type][handler.__id__];
        }
    },

    preventDefault: function(eventObj) {
        if (eventObj.preventDefault) {
            eventObj.preventDefault();
        } else {
            eventObj.returnValue = false;
        }
    },

    stopPropagation: function(eventObj) {
        if (eventObj.stopPropagation) {
            e.stopPropagation();
        } else {
            e.cancelBubble = true;
        }
    },

    // private

    currentId: 1,

    handleEvent: function(event) {
        var handlers;
        event = event || window.event;
        handlers = this.events[event.type];
        for (var i in handlers) {
            this.__handleEvent = handlers[i];
            this.__handleEvent(event);
        }
        this.__handleEvent = null;
    }
};


MousePositionOnPage = {
    getX: function(mouseEvent) {
        return mouseEvent.pageX || mouseEvent.clientX + DHTMLApi.Browser.getScrollX();
    },
    getY: function(mouseEvent) {
        return mouseEvent.pageY || mouseEvent.clientY + DHTMLApi.Browser.getScrollY();
    }
};

///////////////////////////
// ScaledBackgroundImage //
///////////////////////////

ScaledBackgroundImage = {
    create: function(imagePath) {
        var obj = this;
        this.imagePath = imagePath;
        this.preloader = new ImagePreloader([imagePath]);
        this.preloader.addListener(this);
        this.preloader.start();
        var bodyElement = document.getElementsByTagName("BODY")[0];
        this.container = document.createElement("DIV");
        bodyElement.insertBefore(this.container, bodyElement.firstChild);
        DHTMLApi.CSS.setProperties(this.container, { overflow: "hidden", width: DHTMLApi.Browser.getViewportWidth() + "px", height: DHTMLApi.Browser.getViewportHeight() + "px" });
        /*this.imageElement=document.createElement("IMG");
        this.container.appendChild(this.imageElement);
        DHTMLApi.Visibility.hide(this.imageElement);
        this.imageElement.onload=function () {
        DHTMLApi.Visibility.show(obj.imageElement);
        DHTMLApi.Visibility.setOpacity(obj.imageElement, 1);
        obj.animation=new Animation.Fade(obj.imageElement, 1);
        obj.animation.setFade(100, 15);
        };
		
		this.imageElement.src=imagePath;
        this.ratio=1.0*DHTMLApi.Size.getElementHeight(this.imageElement)/DHTMLApi.Size.getElementWidth(this.imageElement);
        DHTMLApi.CSS.setProperties(this.imageElement, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: Math.round(this.ratio*DHTMLApi.Browser.getViewportWidth())+"px"});
		
		DOMEvent.addDomListener(window, "resize", function () {
        DHTMLApi.CSS.setProperties(obj.container, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: DHTMLApi.Browser.getViewportHeight() + "px"});
        DHTMLApi.CSS.setProperties(obj.imageElement, {width: DHTMLApi.Browser.getViewportWidth()+"px", height: Math.round(obj.ratio*DHTMLApi.Browser.getViewportWidth())+"px"});
        });
        */
    },

    onImageLoad: function(eventObject) {
    var obj = this;
       
        this.imageElement = document.createElement("IMG");
        this.imageElement.setAttribute("src", this.imagePath);
        this.container.appendChild(this.imageElement);
        DHTMLApi.Visibility.setOpacity(this.imageElement, 1);
        this.ratio = 1.0 * DHTMLApi.Size.getElementHeight(this.imageElement) / DHTMLApi.Size.getElementWidth(this.imageElement);
        DHTMLApi.CSS.setProperties(this.imageElement, { width: DHTMLApi.Browser.getViewportWidth() + "px", height: Math.round(this.ratio * DHTMLApi.Browser.getViewportWidth()) + "px" });

        DOMEvent.addDomListener(window, "resize", function() {
            DHTMLApi.CSS.setProperties(obj.container, { width: DHTMLApi.Browser.getViewportWidth() + "px", height: DHTMLApi.Browser.getViewportHeight() + "px" });
            DHTMLApi.CSS.setProperties(obj.imageElement, { width: DHTMLApi.Browser.getViewportWidth() + "px", height: Math.round(obj.ratio * DHTMLApi.Browser.getViewportWidth()) + "px" });
        });

        this.animation = new Animation.Fade(this.imageElement, 1);
        this.animation.setFade(100, 3);
    }
   
}



  ///////////////////////////////////
 //  Scaled Background Slide Show //
///////////////////////////////////

ScaledBackgroundImages = {
    create: function(imagePaths) {
        var obj = this;

        this.imagePaths = imagePaths;
        this.imageIndex = 0;
        this.imageLoaded = false;
        this.preloader = new ImagePreloader(imagePaths);
        this.preloader.addListener(this);
        this.preloader.start();
        var bodyElement = document.getElementsByTagName("BODY")[0];
        this.container = document.createElement("DIV");
        bodyElement.insertBefore(this.container, bodyElement.firstChild);
        DHTMLApi.CSS.setProperties(this.container, { overflow: "hidden", width: DHTMLApi.Browser.getViewportWidth() + "px", height: DHTMLApi.Browser.getViewportHeight() + "px" });
        this.imageElement = document.createElement("IMG");
        this.container.appendChild(this.imageElement);
        DOMEvent.addDomListener(window, "resize", function() {
            DHTMLApi.CSS.setProperties(obj.container, { width: DHTMLApi.Browser.getViewportWidth() + "px", height: DHTMLApi.Browser.getViewportHeight() + "px" });
            DHTMLApi.CSS.setProperties(obj.imageElement, { width: DHTMLApi.Browser.getViewportWidth() + "px", height: Math.round(obj.ratio * DHTMLApi.Browser.getViewportWidth()) + "px" });
        });
    },

    onImageLoad: function(eventObject) {
        var obj = this;
        /*if(this.imageElement === null){
        this.imageElement = document.createElement("IMG");
        this.container.appendChild(this.imageElement);
        }*/
        if (!this.imageLoaded) {
            this.imageLoaded = true;
            this.changeImage();
        }
    },
    changeImage: function() {
        this.imageElement.setAttribute("src", this.imagePaths[this.imageIndex]);
        this.imageIndex = ++this.imageIndex % this.imagePaths.length;

        DHTMLApi.Visibility.setOpacity(this.imageElement, 1);
        this.ratio = 1.0 * DHTMLApi.Size.getElementHeight(this.imageElement) / DHTMLApi.Size.getElementWidth(this.imageElement);
        DHTMLApi.CSS.setProperties(this.imageElement, { width: DHTMLApi.Browser.getViewportWidth() + "px", height: Math.round(this.ratio * DHTMLApi.Browser.getViewportWidth()) + "px" });



        this.animation = new Animation.Fade(this.imageElement, 1);
        this.animation.setFade(8000, 1000);
        this.startSlideshow(8000);
    },
    startSlideshow: function(interval) {
        this.interval = interval;
        t = setTimeout('ScaledBackgroundImages.changeImage()', interval);

    }

}




////////////////////
// Class Rollover //
////////////////////

function Rollover(imageElement, rolloverPicPath) {
    var rolloverImage;

    this.imageObject = imageElement;
    rolloverImage = new Image();
    rolloverImage.src = rolloverPicPath;
    this.rolloutImageSrc = this.imageObject.src;
    this.rolloverImageSrc = rolloverPicPath;
    this.init();
}

Rollover.prototype.setNormalStateImage = function(normalStatePicPath) {
    this.imageObject.src = normalStatePicPath;
    this.rolloutImageSrc = this.imageObject.src;
}

Rollover.prototype.init = function() {
    var obj = this;
    DOMEvent.addDomListener(this.imageObject, "mouseover", function() {
        this.src = obj.rolloverImageSrc;
    });
    DOMEvent.addDomListener(this.imageObject, "mouseout", function() {
        this.src = obj.rolloutImageSrc;
    });
}

function implementsInterface() {
    var prototypeObj = new Object();
    for (var i = 0; i < arguments.length; i++) {
        for (var method in arguments[i]) {
            prototypeObj[method] = arguments[i][method];
        }
    }
    return prototypeObj;
}

//////////////////////////
// Interface Observable //
//////////////////////////

Observable = {
    addListener: function(listenerObj) {
        if (typeof this.listeners == 'undefined') {
            this.listeners = new Array();
        }
        for (var i = 0; i < this.listeners.length; i++) {
            if (this.listeners[i] == listenerObj) return;
        }
        this.listeners[this.listeners.length] = listenerObj;
    },

    removeListener: function(listenerObj) {
        for (var i = 0; i < this.listeners.length; i++) {
            if (this.listeners[i] == listenerObj) {
                this.listeners.splice(i, 1);
                return;
            }
        }
    },

    notifyListeners: function(eventName, eventObj) {
        if (typeof this.listeners == 'undefined') return;
        for (var i = 0; i < this.listeners.length; i++) {
            if (typeof this.listeners[i][eventName] != "undefined") {
                this.listeners[i][eventName](eventObj);
            }
        }
    }
}

/////////////////////////////////////////////
// Class Draggable (implements Observable) //
/////////////////////////////////////////////

/************************************
listenerObj must implement methods:	
onDragStop(DraggableEventObj event)
onDrag(DraggableEventObj event)
************************************/

DraggableMode = { HORIZONTAL: 1, VERTICAL: 2, HORIZONTAL_VERTICAL: 3 };

function Draggable(dragObj, dragHandleObj, boundingObj, dragMode) {
    this.dragObj = dragObj;
    if (dragHandleObj == null) {
        this.dragHandle = this.dragObj;
    } else {
        this.dragHandle = dragHandleObj;
    }
    this.mode = dragMode;
    this.boundingObj = boundingObj;
    this.boundingBox = this.getBoundingBox();

    this.mousePosXOnHandle = null;
    this.mousePosYOnHandle = null;

    this.mouseDownHandler = null;
    this.mouseUpHandler = null;
    this.mouseMoveHandler = null;
};

Draggable.prototype = implementsInterface(Observable);

Draggable.prototype.set = function() {
    var obj = this;

    function dragStart(e) {
        obj.notifyListeners("onDragStart", obj.getDraggableEventObj());
        obj.boundingBox = obj.getBoundingBox();
        obj.mousePosXOnHandle = MousePositionOnPage.getX(e) - DHTMLApi.Position.getXPosOnPage(obj.dragObj);
        obj.mousePosYOnHandle = MousePositionOnPage.getY(e) - DHTMLApi.Position.getYPosOnPage(obj.dragObj);
        obj.mouseMoveHandler = DOMEvent.addDomListener(document, "mousemove", drag);
        obj.mouseUpHandler = DOMEvent.addDomListener(document, "mouseup", dragEnd);
        DOMEvent.preventDefault(e);
    }

    function dragEnd(e) {
        DOMEvent.removeListener(obj.mouseMoveHandler);
        DOMEvent.removeListener(obj.mouseUpHandler);
        obj.notifyListeners("onDragStop", obj.getDraggableEventObj());
    }

    function drag(e) {
        var dragObjPosX, dragObjPosY;
        DOMEvent.preventDefault(e);
        dragObjPosX = obj.calculatePosX(MousePositionOnPage.getX(e));
        dragObjPosY = obj.calculatePosY(MousePositionOnPage.getY(e));
        if (obj.mode != DraggableMode.VERTICAL) {
            if (obj.boundingBox.tlX <= dragObjPosX && dragObjPosX <= obj.boundingBox.brX) {
                DHTMLApi.Position.setXPos(obj.dragObj, dragObjPosX - obj.boundingBox.tlX, obj.boundingObj);
            } else if (obj.boundingBox.tlX > dragObjPosX) {
                DHTMLApi.Position.setXPos(obj.dragObj, 0, obj.boundingObj);
            } else {
                DHTMLApi.Position.setXPos(obj.dragObj, obj.boundingBox.brX - obj.boundingBox.tlX, obj.boundingObj);
            }
        }
        if (obj.mode != DraggableMode.HORIZONTAL) {
            if (obj.boundingBox.tlY <= dragObjPosY && dragObjPosY <= obj.boundingBox.brY) {
                DHTMLApi.Position.setYPos(obj.dragObj, dragObjPosY - obj.boundingBox.tlY, obj.boundingObj);
            } else if (obj.boundingBox.tlY > dragObjPosY) {
                DHTMLApi.Position.setYPos(obj.dragObj, 0, obj.boundingObj);
            } else {
                DHTMLApi.Position.setYPos(obj.dragObj, obj.boundingBox.brY - obj.boundingBox.tlY, obj.boundingObj);
            }
        }
        obj.notifyListeners("onDrag", obj.getDraggableEventObj());
    }

    this.mouseDownHandler = DOMEvent.addDomListener(this.dragHandle, "mousedown", dragStart);
};

Draggable.prototype.unset = function() {
    DOMEvent.removeListener(this.mouseDownHandler);
    DOMEvent.removeListener(this.mouseMoveHandler);
    DOMEvent.removeListener(this.mouseUpHandler);
};

Draggable.prototype.getXBounds = function() {
    return (this.boundingBox.brX - this.boundingBox.tlX);
}

Draggable.prototype.getYBounds = function() {
    return (this.boundingBox.brY - this.boundingBox.tlY);
}

Draggable.prototype.setDragObjXPos = function(xPos) {
    DHTMLApi.Position.setXPos(this.dragObj, xPos, this.boundingObj);
}

Draggable.prototype.setDragObjYPos = function(yPos) {
    DHTMLApi.Position.setYPos(this.dragObj, yPos, this.boundingObj);
}

Draggable.prototype.getDragObjXPos = function() {
    return DHTMLApi.Position.getXPosOnPage(this.dragObj) - DHTMLApi.Position.getXPosOnPage(this.boundingObj);
}

Draggable.prototype.getDragObjYPos = function() {
    return DHTMLApi.Position.getYPosOnPage(this.dragObj) - DHTMLApi.Position.getYPosOnPage(this.boundingObj);
}

Draggable.prototype.refreshAfterResize = function() {
    this.boundingBox = this.getBoundingBox();
}

// private

Draggable.prototype.calculatePosX = function(mousePosX) {
    return mousePosX - this.mousePosXOnHandle;
};

Draggable.prototype.calculatePosY = function(mousePosY) {
    return mousePosY - this.mousePosYOnHandle;
};

Draggable.prototype.getBoundingBox = function() {
    return {
        tlX: DHTMLApi.Position.getXPosOnPage(this.boundingObj),
        tlY: DHTMLApi.Position.getYPosOnPage(this.boundingObj),
        brX: DHTMLApi.Position.getXPosOnPage(this.boundingObj) + DHTMLApi.Size.getElementWidth(this.boundingObj) - DHTMLApi.Size.getElementWidth(this.dragObj),
        brY: DHTMLApi.Position.getYPosOnPage(this.boundingObj) + DHTMLApi.Size.getElementHeight(this.boundingObj) - DHTMLApi.Size.getElementHeight(this.dragObj)
    };
}

Draggable.prototype.getDraggableEventObj = function() {
    return new DraggableEventObj(DHTMLApi.Position.getXPosInElement(this.dragObj, this.boundingObj), DHTMLApi.Position.getYPosInElement(this.dragObj, this.boundingObj), this.boundingBox.brX - this.boundingBox.tlX, this.boundingBox.brY - this.boundingBox.tlY);
}

/////////////////////////////
// Class DraggableEventObj //
/////////////////////////////

function DraggableEventObj(objPosX, objPosY, boundWidth, boundHeight) {
    this.posX = objPosX;
    this.posY = objPosY;
    this.boundWidth = boundWidth;
    this.boundHeight = boundHeight;
}

///////////////////
// Class VSlider //
///////////////////

/************************************
listenerObj must implement methods:	
onChange(ChangeEventObj event)
onUpperSliderBarClick(ChangeEventObj event)
onLowerSliderBarClick(ChangeEventObj event)
************************************/

function VSlider(dragObj, boundingObj, topValue, bottomValue, initValue) {
    this.topValue = topValue;
    this.bottomValue = bottomValue;
    this.sliderBar = boundingObj;
    this.sliderBarClickHandler = null;
    this.draggableObject = new Draggable(dragObj, null, boundingObj, DraggableMode.VERTICAL);
    this.draggableObject.set();
    this.draggableObject.addListener(this);
    if (typeof initValue != 'undefined') {
        this.setValue(initValue);
    }
    this.initSliderBar();
}

VSlider.prototype = implementsInterface(Observable);

VSlider.prototype.initSliderBar = function() {
    var obj = this;
    this.sliderBarClickHandler = DOMEvent.addDomListener(this.sliderBar, "click", function(e) {
        var clickPosY = MousePositionOnPage.getY(e) - DHTMLApi.Position.getYPosOnPage(obj.sliderBar);
        if (clickPosY < obj.draggableObject.getDragObjYPos()) {
            obj.notifyListeners("onUpperSliderBarClick", new SliderEventObj(obj.getValue(obj.draggableObject.getDraggableEventObj())));
        }
        if (clickPosY > obj.draggableObject.getDragObjYPos() + DHTMLApi.Size.getElementHeight(obj.draggableObject.dragObj)) {
            obj.notifyListeners("onLowerSliderBarClick", new SliderEventObj(obj.getValue(obj.draggableObject.getDraggableEventObj())));
        }
    });
}

VSlider.prototype.getValue = function(draggableEventObj) {
    return this.topValue + (draggableEventObj.posY / draggableEventObj.boundHeight) * 1.0 * (this.bottomValue - this.topValue);
}

VSlider.prototype.setBoundaryValues = function(topValue, bottomValue) {
    this.topValue = topValue;
    this.bottomValue = bottomValue;
}

VSlider.prototype.setValue = function(value) {
    var dragObjYPos = Math.round((value - this.topValue) * this.draggableObject.getYBounds() / (this.bottomValue - this.topValue));
    this.draggableObject.setDragObjYPos(dragObjYPos);
}

VSlider.prototype.onDragStop = function(draggableEventObj) {
    this.notifyListeners("onChange", new SliderEventObj(this.getValue(draggableEventObj)));
}

VSlider.prototype.onDrag = function(draggableEventObj) {
    this.notifyListeners("onChange", new SliderEventObj(this.getValue(draggableEventObj)));
}

function SliderEventObj(value) {
    this.value = value;
}

///////////////////
// Class VScroll //
///////////////////

function VScroll(containerElement, contentElement, sliderbarElement, sliderElement, viewport, upButton, downButton, scrollIncrement) {
    this.containerElement = containerElement;
    this.contentElement = contentElement;
    this.sliderbarElement = sliderbarElement;
    this.sliderElement = sliderElement;
    this.upButton = upButton;
    this.downButton = downButton;
    this.viewportWidth = viewport.width;
    this.viewportHeight = viewport.height;
    this.viewportPosX = viewport.x;
    this.viewportPosY = viewport.y;
    this.bottomViewportPadding = DHTMLApi.Size.getElementHeight(this.containerElement) - this.viewportHeight - this.viewportPosY;
    this.rightViewportPadding = DHTMLApi.Size.getElementWidth(this.containerElement) - this.viewportWidth - this.viewportPosX;
    this.invisibleContentHeight = null;
    this.scrollIncrement = scrollIncrement;
    this.slider = null;
    this.mask = this.buildMask();
    this.animation = new Animation.SmoothVMove(this.contentElement, this.mask);
    this.initSlider();
    this.initButtons();
    if (this.viewportHeight > DHTMLApi.Size.getElementHeight(this.contentElement)) {
        this.hideControls();
        this.controlsHidden = true;
    } else {
        this.controlsHidden = false;
    }
}

VScroll.prototype.buildMask = function() {
    var maskDiv = document.createElement("div");
    DHTMLApi.CSS.setProperties(maskDiv, { position: "absolute", left: this.viewportPosX + "px", top: this.viewportPosY + "px", width: this.viewportWidth + "px", height: this.viewportHeight + "px", overflow: 'hidden' });
    this.contentElement = this.containerElement.replaceChild(maskDiv, this.contentElement);
    maskDiv.appendChild(this.contentElement);
    return maskDiv;
}

VScroll.prototype.initSlider = function() {
    var obj = this;
    this.invisibleContentHeight = DHTMLApi.Size.getElementHeight(this.contentElement) - this.viewportHeight;
    this.slider = new VSlider(this.sliderElement, this.sliderbarElement, 0, -this.invisibleContentHeight, 0);
    this.slider.onDragStop = function(draggableEventObj) {
        var value = this.getValue(draggableEventObj);
        obj.animation.setPosition(value);
        this.notifyListeners("onChange", new SliderEventObj(value));
    }
    this.slider.onDrag = function(draggableEventObj) {
        if (obj.animation.getAnimationStep() === null || obj.animation.getAnimationStep() > 0) {
            obj.animation.setPosition(this.getValue(draggableEventObj));
        }
        this.notifyListeners("onChange", new SliderEventObj(this.getValue(draggableEventObj)));
    }
    this.slider.addListener(this);
}

VScroll.prototype.initButtons = function() {
    var obj = this;
    var mousedownInterval;

    DOMEvent.addDomListener(this.downButton, "mousedown", function() {
        mousedownInterval = window.setInterval(function() { obj.scrollDown(obj.scrollIncrement, true) }, 10);
    });

    DOMEvent.addDomListener(this.downButton, "mouseout", function() {
        window.clearInterval(mousedownInterval);
    });

    DOMEvent.addDomListener(this.downButton, "mouseup", function() {
        window.clearInterval(mousedownInterval);
    });

    DOMEvent.addDomListener(this.upButton, "mousedown", function() {
        mousedownInterval = window.setInterval(function() { obj.scrollUp(obj.scrollIncrement, true) }, 10);
    });

    DOMEvent.addDomListener(this.upButton, "mouseup", function() {
        window.clearInterval(mousedownInterval);
    });

    DOMEvent.addDomListener(this.upButton, "mouseout", function() {
        window.clearInterval(mousedownInterval);
    });
}

VScroll.prototype.hideControls = function() {
    DHTMLApi.Visibility.hide(this.upButton);
    DHTMLApi.Visibility.hide(this.downButton);
    DHTMLApi.Visibility.hide(this.sliderElement);
    DHTMLApi.Visibility.hide(this.sliderbarElement);
    DHTMLApi.Visibility.hide(this.sliderbarElement.parentNode);
}

VScroll.prototype.showControls = function() {
    DHTMLApi.Visibility.show(this.sliderbarElement.parentNode);
    DHTMLApi.Visibility.show(this.sliderbarElement);
    DHTMLApi.Visibility.show(this.sliderElement);
    DHTMLApi.Visibility.show(this.downButton);
    DHTMLApi.Visibility.show(this.upButton);
}

VScroll.prototype.setPosition = function(numOfPixels) {
    DHTMLApi.Position.setYPos(this.contentElement, -1 * numOfPixels, this.containerElement);
    this.slider.setValue(-1 * numOfPixels);
}

VScroll.prototype.setBottomPosition = function() {
    this.setPosition(this.invisibleContentHeight);
}

VScroll.prototype.resize = function(width, height) {
    if (height < DHTMLApi.Size.getElementHeight(this.contentElement)) {
        if (this.controlsHidden) {
            DHTMLApi.CSS.setProperties(this.mask, { overflow: 'hidden' });
            this.showControls();
            this.controlsHidden = false;
        }
        this.resizeElements(width, height);
        this.recalculateAfterResize(width, height);
    } else {
        if (!this.controlsHidden) {
            this.hideControls();
            this.setPosition(0);
            this.controlsHidden = true;
            DHTMLApi.CSS.setProperties(this.mask, { overflow: 'visible' });
        }
    }
}

VScroll.prototype.resizeElements = function(width, height) {
    var heightDifference, widthDifference;
    heightDifference = height - DHTMLApi.Size.getElementHeight(this.containerElement);
    widthDifference = width - DHTMLApi.Size.getElementWidth(this.containerElement);
    DHTMLApi.CSS.setProperties(this.containerElement, { width: width + "px", height: height + "px" });
    DHTMLApi.CSS.setProperties(this.mask, { width: (width - this.rightViewportPadding - this.viewportPosX) + "px", height: (height - this.bottomViewportPadding - this.viewportPosY) + "px" });
    DHTMLApi.CSS.setProperties(this.sliderbarElement, { height: (DHTMLApi.Size.getElementHeight(this.sliderbarElement) + heightDifference) + "px" });
    DHTMLApi.CSS.setProperties(this.sliderbarElement.parentNode, { height: height + "px" });
    DHTMLApi.CSS.setProperties(this.downButton, { top: (height - (DHTMLApi.Size.getElementHeight(this.downButton))) + "px", height: DHTMLApi.Size.getElementHeight(this.downButton) + "px", width: DHTMLApi.Size.getElementWidth(this.downButton) + "px" });
    DHTMLApi.CSS.setProperties(this.contentElement, { width: (DHTMLApi.Size.getElementWidth(this.contentElement) + widthDifference) + "px" });
}

VScroll.prototype.recalculateAfterResize = function(width, height) {
    this.viewportWidth = width - this.rightViewportPadding - this.viewportPosX;
    this.viewportHeight = height - this.bottomViewportPadding - this.viewportPosY;
    this.invisibleContentHeight = DHTMLApi.Size.getElementHeight(this.contentElement) - this.viewportHeight;
    this.slider.setBoundaryValues(0, -this.invisibleContentHeight);
    this.slider.draggableObject.refreshAfterResize();
    if (DHTMLApi.Position.getYPosInElement(this.contentElement, this.containerElement) < -1 * this.invisibleContentHeight) {
        DHTMLApi.Position.setYPos(this.contentElement, -1 * this.invisibleContentHeight, this.containerElement);
    }
    this.slider.setValue(DHTMLApi.Position.getYPosInElement(this.contentElement, this.containerElement));

}

VScroll.prototype.scrollUp = function(scrollIncrement, refreshSliderPos) {
    var targetPosY;
    if ((this.getCurrentScrollPosition() + scrollIncrement) >= 0) {
        targetPosY = 0;
    } else {
        targetPosY = this.getCurrentScrollPosition() + scrollIncrement;
    }
    if (refreshSliderPos) {
        this.animation.setPosition(targetPosY);
        this.slider.setValue(targetPosY);
    } else {
        this.animation.setPosition(targetPosY);
        this.animation.addListener(this);
    }
}

VScroll.prototype.scrollDown = function(scrollIncrement, refreshSliderPos) {
    var targetPosY;
    if ((this.getCurrentScrollPosition() - scrollIncrement) < -this.invisibleContentHeight) {
        targetPosY = -this.invisibleContentHeight;
    } else {
        targetPosY = this.getCurrentScrollPosition() - scrollIncrement;
    }
    if (refreshSliderPos) {
        this.animation.setPosition(targetPosY);
        this.slider.setValue(targetPosY);
    } else {
        this.animation.setPosition(targetPosY);
        this.animation.addListener(this);
    }
}

VScroll.prototype.getCurrentScrollPosition = function() {
    return DHTMLApi.Position.getYPosInElement(this.contentElement, this.mask);
}

VScroll.prototype.scrollToTop = function() {
    this.scrollTo(0);
}

VScroll.prototype.scrollTo = function(pixelValue) {
    if (pixelValue < this.invisibleContentHeight) {
        this.animation.setPosition(-1 * pixelValue);
    } else {
        this.animation.setPosition(-1 * this.invisibleContentHeight);
    }
    this.animation.addListener(this);
}

VScroll.prototype.onUpperSliderBarClick = function(event) {
    this.scrollUp(this.viewportHeight, false);
}

VScroll.prototype.onLowerSliderBarClick = function(event) {
    this.scrollDown(this.viewportHeight, false);
}

VScroll.prototype.onAnimationStep = function() {
    this.slider.setValue(this.getCurrentScrollPosition());
}

VScroll.prototype.onAnimationEnd = function() {
    //if (this.initialAnimation===null) {
    this.animation.removeListener(this);
    //}
}

///////////////////////
// Package Animation //
///////////////////////

Animation = new Object();

Animation.FRAME_RATE = 50; // miliseconds

/////////////////////////////////
// Class Animation.SmoothVMove //
/////////////////////////////////

Animation.SmoothVMove = function(movingObject, relativeToObject) {
    this.movingObject = movingObject;
    this.relativeToObject = relativeToObject;
    this.currentYPos = DHTMLApi.Position.getYPosInElement(movingObject, relativeToObject);
    this.targetYPos = null;
    this.interval = null;
    this.numOfAnimationStep = null;
}

Animation.SmoothVMove.prototype = implementsInterface(Observable);

Animation.SmoothVMove.prototype.setPosition = function(targetPosition) {
    this.currentYPos = DHTMLApi.Position.getYPosInElement(this.movingObject, this.relativeToObject);
    if (this.interval !== null) {
        window.clearInterval(this.interval);
        this.notifyListeners("onAnimationEnd", null);
    }
    var animationObject = this;
    this.targetYPos = targetPosition;
    this.numOfAnimationStep = 0;
    this.notifyListeners("onAnimationStart", null);
    this.animate();
    this.interval = window.setInterval(function() { animationObject.animate() }, Animation.FRAME_RATE);
}

Animation.SmoothVMove.prototype.animate = function() {
    var stepDistance = (this.targetYPos - this.currentYPos) / 3;
    if (Math.abs(stepDistance) > 0.3) {
        this.currentYPos += stepDistance;
        DHTMLApi.Position.setYPos(this.movingObject, this.currentYPos, this.relativeToObject);
        ++this.numOfAnimationStep;
        this.notifyListeners("onAnimationStep", this.numOfAnimationSteps);
        return this.numOfAnimationStep;
    } else {
        this.currentYPos = this.targetYPos;
        DHTMLApi.Position.setYPos(this.movingObject, this.currentYPos, this.relativeToObject);
        this.notifyListeners("onAnimationStep", ++this.numOfAnimationSteps);
        window.clearInterval(this.interval);
        this.notifyListeners("onAnimationEnd", null);
        this.numOfAnimationStep = null;
        return false;
    }
}

Animation.SmoothVMove.prototype.getAnimationStep = function() {
    return this.numOfAnimationStep;
}


//////////////////////////
// Class Animation.Fade //
//////////////////////////

Animation.Fade = function(fadeObject, currentOpacityPercentage) {
    this.fadeObject = fadeObject;
    this.currentOpacityPercentage = currentOpacityPercentage;
    this.interval = null;
    this.targetOpacityPercentage = null;
    this.currentAnimationStep = null;
    this.numOfAnimationSteps = null;
    DHTMLApi.Visibility.setOpacity(this.fadeObject, Math.round(this.currentOpacityPercentage));
}

Animation.Fade.prototype = implementsInterface(Observable);

Animation.Fade.prototype.setFade = function(targetOpacityPercentage, numOfSteps) {
    this.stop();
    var animationObject = this;
    this.targetOpacityPercentage = targetOpacityPercentage;
    this.opacityStep = 1.0 * (targetOpacityPercentage - this.currentOpacityPercentage) / numOfSteps;
    this.numOfAnimationSteps = numOfSteps;
    this.currentAnimationStep = 0;
    this.notifyListeners("onAnimationStart", null);
    this.animate();
    this.interval = window.setInterval(function() { animationObject.animate() }, Animation.FRAME_RATE);
}

Animation.Fade.prototype.animate = function() {
    if (this.currentAnimationStep < this.numOfAnimationSteps) {
        this.currentOpacityPercentage += this.opacityStep;
        DHTMLApi.Visibility.setOpacity(this.fadeObject, Math.round(this.currentOpacityPercentage));
        this.notifyListeners("onAnimationStep", this.currentAnimationStep);
        ++this.currentAnimationStep;
        return this.numOfAnimationStep;
    } else {
        this.currentOpacityPercentage = this.targetOpacityPercentage;
        DHTMLApi.Visibility.setOpacity(this.fadeObject, Math.round(this.currentOpacityPercentage));
        this.notifyListeners("onAnimationStep", this.currentAnimationStep);
        window.clearInterval(this.interval);
        this.notifyListeners("onAnimationEnd", null);
        this.numOfAnimationStep = null;
        return false;
    }
}

Animation.Fade.prototype.stop = function() {
    if (this.interval !== null) {
        window.clearInterval(this.interval);
        this.notifyListeners("onAnimationEnd", null);
    }
}

//////////////////////////
// Class ImagePreloader //
//////////////////////////

/* broadcasts
onImageLoad - event Object - img url string
onAllImagesLoad + event Object - array of imgs url string
*/

function ImagePreloader(imgUrlArray) {
    this.imgUrlArray = imgUrlArray;
    this.imgPreloadingIndex = 0;
    this.isPreloading = false;
    this.preloadInterval = null;
    this.imageIsPreloaded = false;
}

ImagePreloader.prototype = implementsInterface(Observable);

ImagePreloader.prototype.preload = function() {

    var obj = this;
    if (this.imgPreloadingIndex >= this.imgUrlArray.length) return;
    this.preloadInterval = window.setInterval(function() {
        if (obj.imageIsPreloaded === false && obj.isPreloading == false) {
            obj.preloadImage(obj.imgPreloadingIndex);
            return;
        }
        if (obj.imgPreloadingIndex == (obj.imgUrlArray.length - 1)) {
            window.clearInterval(obj.preloadInterval);
        } else {
            if (obj.imageIsPreloaded === true) {
                obj.imgPreloadingIndex++;
                obj.preloadImage(obj.imgPreloadingIndex);
            }
        }

    }, 150);
}

ImagePreloader.prototype.preloadImage = function(imageNum) {
    var obj = this;
    this.isPreloading = true;
    var img = new Image();
    this.imageIsPreloaded = false;
    img.onload = img.onerror = function() {
        obj.notifyListeners("onImageLoad", obj.imgUrlArray[obj.imgPreloadingIndex]);
        obj.imageIsPreloaded = true;
        if ((obj.imgUrlArray.length - 1) == obj.imgPreloadingIndex) {
            obj.notifyListeners("onAllImagesLoad", obj.imgUrlArray);
        }
    }
    img.src = this.imgUrlArray[imageNum];
}

ImagePreloader.prototype.start = function() {
    this.preload();
}

ImagePreloader.prototype.stop = function() {
    this.isPreloading = false;
    this.imageIsPreloaded = false;
    if (this.preloadInterval !== null) {
        window.clearInterval(this.preloadInterval);
        this.preloadInterval = null;
    }
}
