function ScrollBox(container, itemWidth, visibleCount, total, categoryId) {
    this.current = 1;
    this.feedHops = new Array();
    this.container = container;
    this.total = total;
    this.visibleCount = visibleCount;
    this.itemWidth = itemWidth;
    this.categoryId = categoryId;
    this.scrollDuration = 0.4;

    this.getContainerX = function() {
        var x = parseInt(this.container.style.left.replace('px', ''));

        if (!x) {
            return 0;
        }

        return x;
    }

    this.canScrollNext = function() {
        var x = Math.abs(this.getContainerX());

        return x < this.getContainerWidth() - this.visibleCount * this.itemWidth;
    }

    this.canScrollPrev = function() {
        return this.getContainerX() < 0;
    }

    this.shouldAddItems = function() {
        return this.current % this.visibleCount == 3 && !this.feedHops[this.current];
    }

    this.nextItem = function() {
        if (!this.canScrollNext() || this.getContainerX() % this.itemWidth != 0) {
            return false;
        }

        if (this.shouldAddItems()) {
            this.addMoreItems();
        }

        new Effect.Move('items', { x: -this.itemWidth, y: 0, mode: 'relative', duration:this.scrollDuration });

        return ++this.current;
    }

    this.prevItem = function() {
        if (!this.canScrollPrev() || this.getContainerX() % this.itemWidth != 0) {
            return false;
        }

        new Effect.Move('items', { x: this.itemWidth, y: 0, mode: 'relative', duration:this.scrollDuration });
        return --this.current;
    }

    this.itemToHtml = function(item) {
        var htmlItem = document.createElement('div');
        htmlItem.innerHTML = this.container.firstDescendant().innerHTML;
        htmlItem.setAttribute('class', this.container.firstDescendant().readAttribute('class'));

        var firstChildElement = function(element) {
            for(var i = 0; i < element.childNodes.length; i++) {
                if (element.childNodes[i].nodeType == 1) {
                    return element.childNodes[i];
                }
            }
        }
        
        var elements = firstChildElement(htmlItem).getElementsByTagName('a');
        for(var i = 0; i < elements.length; i++) {
            if (elements[i].nodeType != 1) {
                continue;
            }

            var className = elements[i].attributes['class'].value;
            if (className.match('publicUrl')) {
                elements[i].attributes['href'].value = item.publicUrl;
            } else if (className.match('titlePublicUrl')) {
                elements[i].innerHTML = item.title;
                elements[i].attributes['href'].value = item.publicUrl;
            }
        }

        elements = firstChildElement(htmlItem).getElementsByTagName('img');
        for(i = 0; i < elements.length; i++) {
            if (elements[i].nodeType != 1) {
                continue;
            }

            className = elements[i].attributes['class'].value;
            if (className.match('thumbnail')) {
                elements[i].attributes['src'].value = item.thumbnail;
            }
        }

        elements = firstChildElement(htmlItem).getElementsByTagName('span');
        for(i = 0; i < elements.length; i++) {
            if (elements[i].nodeType != 1) {
                continue;
            }

            className = elements[i].attributes['class'].value;
            if (className.match('content')) {
                elements[i].innerHTML = item.content;
            }
        }

        elements = firstChildElement(htmlItem).getElementsByTagName('b');
        for(i = 0; i < elements.length; i++) {
            if (elements[i].nodeType != 1) {
                continue;
            }

            className = elements[i].attributes['class'].value;
            if (className.match('price')) {
                elements[i].innerHTML = item.price;
            }
        }
        

        return htmlItem;
    }

    this.resizeContainer = function() {
        this.container.style.width = this.total * this.itemWidth + 'px';
    }

    this.addItemsToContainer = function(items) {
        this.resizeContainer();
        for(var i = 0; i < items.length; i++) {
            this.container.appendChild(this.itemToHtml(items[i]));
        }
    }

    this.addMoreItems = function() {
        var url = NEOBIZZ_URL + 'ajax/promoted-ads-list/categoryId/' + this.categoryId + '/current/' + this.current;
        var scrollBox = this;
        this.feedHops[this.current] = true;

        new Ajax.Request(url, {
            method: 'get',
            onSuccess: function(transport) {
                var items = transport.responseText.evalJSON();
                if (!items) {
                    return false;
                }

                scrollBox.total += items.length;
                scrollBox.addItemsToContainer(items);

                return true;
            }
        });
    }

    this.setContainerX = function(x) {
        this.container.style.left = x + 'px';
    }

    this.getContainerWidth = function() {
        return parseInt(this.container.style.width, 10);
    }

    this.resetToStart = function() {
        this.setContainerX(0);
    }

    this.resetToEnd = function() {
        this.container.style.left = this.setContainerX(-this.getContainerWidth() + this.visibleCount * this.itemWidth);
    }

    this.updateCurrentByX = function() {
        this.current = Math.ceil(Math.abs(this.getContainerX()) / this.itemWidth);
    }
}

endDrag = function() {
    scrollBox.setContainerX(Math.round(scrollBox.getContainerX() / scrollBox.itemWidth) * scrollBox.itemWidth);
    scrollBox.current = Math.ceil(Math.abs(scrollBox.getContainerX()) / scrollBox.itemWidth) + 1;
}

positionChanged = function() {
    if (scrollBox.shouldAddItems()) {
        scrollBox.addMoreItems();
    }

    if (!scrollBox.canScrollPrev()) {
        scrollBox.resetToStart();
        return false;
    }

    if (!scrollBox.canScrollNext()) {
        scrollBox.current = scrollBox.total - (scrollBox.visibleCount - 1);
        scrollBox.resetToEnd();
        return false;
    }

    scrollBox.updateCurrentByX();

    return true;
}