function Page(elementId) {
    // This class will create a sliding panel within a container, defined by elementId
    // The sliding panel will contain pages that have the same width as the container.
    // The sliding panel can than be moved left or right to display a specific page in the
    // container. Pages that fall outside the border of the container will not be displayed.

    this.elementId = elementId;
    this.id = null;
    this.pages = new Array();
    this.width = '0px';
    this.slidepanel = null;
    this.sliding = false;
    this.queue = new Array();
    this.pageQueue = new Array();
    this.left = 0;

    // Init the paging for the container element elementId
    // 1) Set the position of the container to relative, fixed width and overflow to hidden
    // 2) Create a sliding panel that will move left and right within the container
    // 3) Take the current contents of the container element and put it in a page (a div)
    //    that in it's turn will be positioned within the sliding panel
    this.init = function() {
        if ($(this.elementId)) {
            // Set the properties of the container
            $(this.elementId).style.position = 'relative';
            $(this.elementId).style.width = $(this.elementId).getWidth() + 'px';

            $(this.elementId).style.overflow = 'hidden';
            this.width = $(this.elementId).getWidth();
            
            // Create the slidepanel that will later be placed inside the container
            this.slidepanel = Builder.node('div', {
                id:this.elementId+'_slidepanel',
                className:'slidepanel'});
            this.slidepanel.style.width = '0px';
            this.slidepanel.style.overflow = 'hidden';
            this.slidepanel.style.position = 'relative';
            this.slidepanel.style.margin = '0px';
            this.positionPanel();

            // Create a page that will later be placed within the slidepanel
            myPage = Builder.node('div', {
                id:this.createPageId(),
                className:'page'});
            myPage.style.width = this.width+'px';
            myPage.style.styleFloat = 'left';
            myPage.style.cssFloat = 'left';
            myPage.style.margin = '0px';
            // Move the current contents of the container to the page
            var node = $(this.elementId).firstChild;
            var next;
            while (node) {
                next = node.nextSibling;
                myPage.appendChild(node);
                node = next;
            }

            // Add the page to the slider and the slider to the container
            this.slidepanel.appendChild(myPage);
            this.slidepanel.style.width = myPage.style.width;
            $(this.elementId).appendChild(this.slidepanel);

            this.pages.push(myPage.id);
            this.id = myPage.id;

            return this.id;
        }
        return false;
    }

    // Function to create new pages. Position can be 'begin', 'end' or
    // a number relative to the current page (a negative number indicates
    // that the page is to be placed on the left side)
    // Content can be an array with elements and/or HTML or just a single element or HTML
    this.newPage = function(position, content) {
        if (this.sliding == true) {
            // We can't insert a page now
            this.pageQueue.push({myFunc : 'newPage', myPos : position, myContent : content});
            return true;
        }

        // Create a new page
        myPage = Builder.node('div', {
            id:this.createPageId(),
            className:'page'});
        myPage.style.width = this.width+'px';
        myPage.style.styleFloat = 'left';
        myPage.style.cssFloat = 'left';
        myPage.style.margin = '0px';

        // Check if the content is an array. If not, put it in an array 
        if (typeof(content) == "object" && Object.isArray(content)) {
            myPageContent = content;
        } else {
            myPageContent = new Array(content);
        }

        // Process the array and add the content to the page that we created
        for (i=0;i<myPageContent.length;i++) {
            if (typeof(myPageContent[i]) == "object" && Object.isElement(myPageContent[i])) {
                myPage.appendChild(myPageContent[i]);
            } else {
                myPage.innerHTML = myPageContent[i];
            }
        }

        // Append the page to the sliding panel and resize the panel
        this.slidepanel.appendChild(myPage);
        this.slidepanel.style.width = parseInt(this.slidepanel.style.width) + this.width + 'px';

        // Determine position of the page within the collection and reposition the page if needed
        // If the page is placed before the current page, reposition the panel since the offset will have changed
        if (isNaN(position)) {
            switch(position) {
                case "begin":
                    this.pages.unshift(myPage.id);
                    Element.insert(this.slidepanel, {'top' : myPage});
                    this.positionPanel(-this.width);

                    break;
                case "end":
                default:
                    this.pages.push(myPage.id);
            }
        } else {
            // The determine the new position in the collection and react accordingly
            var newIndex = this.pages.indexOf(this.id) + position;
            if (newIndex < 0) {
                this.pages.unshift(myPage.id);
                Element.insert(this.slidepanel, {'top' : myPage});
                this.positionPanel(-this.width);
            } else if (newIndex >= this.pages.length) {
                this.pages.push(myPage.id);
            } else {
                if (position > 0) {
                    Element.insert($(this.pages[newIndex]), {'before': myPage});
                } else {
                    Element.insert($(this.pages[newIndex]), {'after': myPage});
                }
                if (this.pages.indexOf(this.id) > newIndex) {
                    this.positionPanel(-this.width);
                }
                this.pages.splice((newIndex+1), 0, myPage.id);
            }
            return false;
        }

        if (this.pages.indexOf(myPage.id) > -1) {
            return myPage.id;
        } else {
            myPage.remove();
        }
    }

    this.next = function() {
        return this.go(1);
    }

    this.prev = function() {
        return this.go(-1);
    }

    this.previous = function() {
        return this.prev();
    }

    this.first = function() {
        return this.go(this.pages.first());
    }

    this.last = function() {
        return this.go(this.pages.last());
    }


    // Jump to a page. If the argument is a number, it will indicate the number of pages 
    // skipped relative to the current page. If the argument is an element Id, it will 
    // jump to that page.
    // If we are sliding the panel at the moment, capture the next request and put it in
    // a queue. The queue will be processed after the panel is done sliding.
    this.go = function(position) {
        // Manage the queue
        if (this.sliding == true) {
            if (position != null) {
                this.queue.push(position);
            }
            return false;
        } else if (this.queue.length > 0) {
            if (position != null) {
                this.queue.push(position);
            }
            position = this.clearQueue();
            if (position == null || position == 0) {
                return false;
            }
        }

        var nextPageId = this.getId(position);
        if (nextPageId == this.id || nextPageId == false) return false;

        // Jump to the next element
        var self = this;
        var moveX = this.width * (this.pages.indexOf(this.id) - this.pages.indexOf(nextPageId));
        this.sliding = true;
        new Effect.Move(this.slidepanel, {x: moveX, y: 0, mode:'relative', duration: 0.4, afterFinish: function() {self.sliding = false; self.positionPanel(moveX); self.checkQueue()}});

        this.id = nextPageId;
        return false;

    }

    this.getId = function(position) {
        // Determine the Id of the next element to be displayed
        if (isNaN(position)) {
            if (this.pages.indexOf(position) > -1) {
                return position;
            } else {
                return false;
            }
        } else {
            var nextId;
            nextId = this.pages.indexOf(this.id) + position;
            if (nextId < 0) {
                return this.pages.first();
            } else if (nextId >= this.pages.length) {
                return this.pages.last();
            } else {
                return this.pages[nextId];
            }
        }

        return false;
    }

    this.getIdbyPage = function(position) {
        return this.pages[position-1];
    }

    this.checkQueue = function () {
        this.positionPanel(0);

        if (this.sliding == false) {
            if (this.pageQueue.length > 0) {
                for (i=0;i<this.pageQueue.length;i++) {
                    if (this.pageQueue[i].myFunc == 'newPage') {
                        this.newPage(this.pageQueue[i].myPos, this.pageQueue[i].myContent);
                    }
                }
                this.pageQueue.length = 0;
            }

            if (this.queue.length > 0) {
                this.go();
            }
        }
    }

    // Process each element of the queue and return the id of the element that should be showed in the end
    this.clearQueue = function () {
        var response = this.id;
        for (i=0;i<this.queue.length;i++) {
            if (isNaN(this.queue[i])) {
                response = this.queue[i];
            } else {
                if (i>0 && this.queue[i] == this.queue[i-1]) {
                    if (this.queue[i] == -1) {
                        response = this.pages.first();
                    } else if (this.queue[i] == 1) {
                        response = this.pages.last();
                    }
                } else {
                    nextId = this.pages.indexOf(response) + this.queue[i];
                    if (nextId < 0) {
                        response = this.pages.first();
                    } else if (nextId >= this.pages.length) {
                        response = this.pages.last();
                    } else {
                        response = this.pages[nextId];
                    }
                }
            }
        }
        this.queue.length = 0;
        return response;
    }

    // Function to get the current pagenumber
    this.getPagenum = function () {
        return (this.pages.indexOf(this.id)+1);
    }

    this.isFirst = function() {
        if (this.id == this.pages.first()) {
            return true;
        } else {
            return false;
        }
    }

    this.isLast = function() {
        if (this.id == this.pages.last()) {
            return true;
        } else {
            return false;
        }
    }

    this.positionPanel = function (posChange) {
        if (!isNaN(posChange)) {
            this.left = this.left+posChange;
        }
        if (this.sliding == false) {
            this.slidepanel.style.left = this.left+'px';
        }
    }

    // Create a unique pageId
    this.createPageId = function () {
        var pageId = this.elementId+'_page_'+Math.ceil(Math.random()*100000);
        while ($(pageId)) {
            pageId = this.elementId+'_page_'+Math.ceil(Math.random()*100000);
        }
        return pageId;
    }
}

