function galleryAddNewItem(instance, face, first)
{
    var insertBefore = null;
    if (face == "simple") {
    	if (first) {
    		insertBefore = $("galleryAddItemFirstButton_" + instance);
    		next = insertBefore.nextSibling;
    		while (next && next.nodeType == 1) {
    			next = next.nextSibling;
    		}
    		if (next) {
    			insertBefore = next;
    		}
    	} else {
        	insertBefore = $("galleryAddItemButton_" + instance)
    	}
    }
    if (isDefined("gallerySliderInstances")) {
        //remove bogus items
        for(var i = 0; i < gallerySliderInstances.length; i++) {
            if (gallerySliderInstances[i].instance == instance) {
                gallerySliderInstances[i].removeBogusItems();
                break;
            }
        }
    }
    ApOnListAddEditor.add("galleryItems_" + instance, insertBefore, {first: !!first});
    var noItemsObject = $("galleryNoItems_" + instance);
    if (noItemsObject) {
        noItemsObject.style.display = "none";
    }
}

function galleryOnLoad()
{
    if (isDefined("gallerySliderInstances")) {
        for(var i = 0; i < gallerySliderInstances.length; i++) {
            gallerySliderInstances[i].init();
        }
    }
}

function galleryUpdate(objectId)
{
    //identify the instance
    for(var i = 0; i < gallerySliderInstances.length; i++) {
        if ("galleryItems_" + gallerySliderInstances[i].instance == objectId) {
            gallerySliderInstances[i].updateAfterAdd();
        }
    }
}

function galleryDelete(objectId, parentObjectId)
{
    //identify the instance
    for(var i = 0; i < gallerySliderInstances.length; i++) {
        if ("galleryItems_" + gallerySliderInstances[i].instance == parentObjectId) {
            gallerySliderInstances[i].updateAfterDelete();
        }
    }
}

function galleryUpdateHeight(value, objectId) {
    for(var i = 0; i < gallerySliderInstances.length; i++) {
        if ("gallerySlidePlace_" + gallerySliderInstances[i].instance == objectId) {
            gallerySliderInstances[i].updateAfterResize();
        }
    }
}

function galleryNarrowWidthUpdate(value, objectId) {
    var objectId = $(objectId).parentNode.id;
    for(var i = 0; i < gallerySliderInstances.length; i++) {
        if ("galleryItems_" + gallerySliderInstances[i].instance == objectId) {
            gallerySliderInstances[i].updateAfterResizeNarrowWidth(value);
        }
    }
}

function gallerySliders(instance, windowSize, narrowWidth, initialized)
{
    this.instance = instance;
    this.windowSize = windowSize;
    this.originalWindowSize = this.windowSize;
    this.narrowWidth = narrowWidth;
    this.count = 0;
    this.span = 10;
    this.pictures = new Array();
    this.selected = 1;
    this.windowStart = 1;
    this.hasBogusItems = !initialized;
}

gallerySliders.prototype.init = function()
{
    if (!$("galleryItems_" + this.instance)) {
        //webpart was removed, so we cannot initialize it anymore
        return;
    }
    this.loadPictures();
    //need prev and next buttons
    this.nextButton = $("gallerySlideNext_" + this.instance);
    this.nextButton.style.display = "block";
    this.nextButton.parent = this;
    this.nextButton.onclick = function () {
        this.parent.nextWindow();
    }
    this.nextButton.onmousedown = function () {
        return false;
    }
    this.prevButton = $("gallerySlidePrev_" + this.instance);
    this.prevButton.style.display = "block";
    this.prevButton.parent = this;
    this.prevButton.onclick = function () {
        this.parent.prevWindow();
    }
    this.prevButton.onmousedown = function () {
        return false;
    }
    this.fixWindowAttributes();
    this.reposition();
    this.showHideNextPrev(this.windowStart);
    if (this.windowSize > this.count) {
        this.windowSize = this.count;
    }
}

gallerySliders.prototype.loadPicture = function(id, uri, offset)
{
    this.count++;
    var index = this.count;
    this.pictures[index] = new Object();
    this.pictures[index].id     = id;
    this.pictures[index].uri    = uri;
    this.pictures[index].offset = offset;
}

gallerySliders.prototype.getItemObject = function(index)
{
    return $("galleryItem_" + this.pictures[index].id + "_" + this.instance);
}

gallerySliders.prototype.getItemImageObject = function(index)
{
    return $("galleryItemImage_" + this.pictures[index].id + "_" + this.instance);
}

gallerySliders.prototype.removeBogusItems = function()
{
    if (!this.hasBogusItems) {
        return;
    }
    var listObject = $("galleryItems_" + this.instance);
    for(var i = 1; i <= this.count; i++) {
        listObject.removeChild(this.getItemObject(i));
    }
    this.pictures = new Array();
    this.count = 0;
    this.windowStart = 0;
    this.hasBogusItems = false;
}

gallerySliders.prototype.updateAfterAdd = function()
{
    var listObject = $("galleryItems_" + this.instance);
    var scriptList = listObject.getElementsByTagName("SCRIPT");
    if (scriptList.length > 0) {
        eval(scriptList[scriptList.length - 1].innerHTML);
    }
    this.computeSizes();
    this.windowStart = this.count - this.windowSize + 1;
    this.selected = this.count;
    //load the image
    var imageObject = this.getItemImageObject(this.count);
    imageObject.src = this.pictures[this.count].uri;
    imageObject.parent = this;
    imageObject.index  = this.count;
    imageObject.onload = function () {
        this.parent.updateAfterAddImage(this.index, this);
    }
    //scroll to it
    this.fixWindowAttributes();
    this.reposition();
    this.showHideNextPrev(this.windowStart);
}

gallerySliders.prototype.updateAfterAddImage = function(index, imageObject)
{
    this.prepareImage(index, imageObject);
    this.fadeImageIn(index);
    this.rearrangeEditors();
}

gallerySliders.prototype.updateAfterDelete = function()
{
    do {
        var missingItemFound = false;
        //find the missing item
        for(var i = 1; i <= this.count; i++) {
            if (!this.getItemObject(i)) {
                missingItemFound = true;
                //remove the item
                this.pictures.splice(i, 1);
                this.count--;
                break;
            }
        }
    } while (missingItemFound && this.count > 0);
    this.fixWindowAttributes();
    this.reposition();
    this.showHideNextPrev(this.windowStart);
}

gallerySliders.prototype.updateAfterResize = function()
{
    this.reposition();
    this.showHideNextPrev(this.windowStart);
}

gallerySliders.prototype.updateAfterResizeNarrowWidth = function(size)
{
    if (size < 30) {
        size = 30;
    }
    maxNarrowWidth = (0.75 * $("galleryItems_" + this.instance).offsetWidth / this.windowSize) - this.span;
    if (size > maxNarrowWidth) {
        size = maxNarrowWidth;
    }
    this.narrowWidth = size;
    this.reposition();
    this.showHideNextPrev(this.windowStart);
}

gallerySliders.prototype.fixWindowAttributes = function ()
{
    //make sure the window size is still normal
    if (this.windowSize > this.count) {
        this.windowSize = this.count;
    } else if (this.windowSize < this.count && this.windowSize < this.originalWindowSize) {
        //maximize window size as much as possible
        this.windowSize = (this.count > this.originalWindowSize ? this.originalWindowSize : this.count);
    }
    if (this.count > 0) {
        //make sure the entire window is visible
        if (this.windowStart < 1) {
            this.windowStart = 1;
        } else if (this.windowStart > this.count - this.windowSize + 1) {
            this.windowStart = this.count - this.windowSize + 1;
        }
        //make sure the selected item is in the window
        if (this.selected < this.windowStart) {
            this.selected = this.windowStart;
        } else if (this.selected > this.windowStart + this.windowSize - 1) {
            this.selected = this.windowStart + this.windowSize - 1;
        }
    }
}

gallerySliders.prototype.computeSizes = function()
{
    var totalWidth = $("galleryItems_" + this.instance).offsetWidth;
    var totalSpan = (this.windowSize - 1) * this.span;
    this.normalImageWidth = totalWidth - (this.windowSize - 1) * this.narrowWidth - totalSpan;
}

gallerySliders.prototype.reposition = function()
{
    //compute the sizes
    $("galleryItems_" + this.instance).style.display = "block";
    var height = $("galleryItems_" + this.instance).offsetHeight;
    this.computeSizes();
    var leftOffset = - (this.windowStart - 1) * (this.narrowWidth + this.span);
    var overallHeight = $("galleryItems_" + this.instance).offsetHeight;
    for(var i = 1; i <= this.count; i++) {
        var imageSlide = this.getItemObject(i);
        imageSlide.style.top = (- (i - 1) * overallHeight) + "px";
        //left positioning
        imageSlide.style.left = leftOffset + "px";
        //width
        var slideWidth = (i == this.selected ? this.normalImageWidth : this.narrowWidth);
        imageSlide.style.width = slideWidth + "px";
        var imageObject = this.getItemImageObject(i);
        imageObject.style.width = this.normalImageWidth + "px";
        imageObject.style.height = height + "px";
        imageObject.style.left  = (this.selected == i ? 0 : this.pictures[i].offset);
        //offset for next image
        leftOffset += slideWidth + this.span;
    }
    this.showHideNextPrev();
    this.rearrangeEditors();
}

gallerySliders.prototype.loadPictures = function()
{
    //aiding objects
    this.loaders = new Array();
    //load all pictures in the correct order
    this.loadPictureMain();
}

gallerySliders.prototype.loadPictureMain = function()
{
    if (this.count == 0) {
        return;
    }
    //load the main (selected) picture
    var imageLoader = new Image();
    imageLoader.parent = this;
    imageLoader.onload = function() {
        this.parent.loadPictureMainCallback();
    }
    imageLoader.src = this.pictures[this.selected].uri;
    //save the loader in the list of loaders
    this.mainLoaderIndex = this.loaders.length;
    this.loaders[this.mainLoaderIndex] = imageLoader;
    this.mainLoader = imageLoader;
    var imageObject = this.getItemImageObject(this.selected);
}

gallerySliders.prototype.loadPictureMainCallback = function()
{
    //main picture has finished loading
    var imageObject = this.getItemImageObject(this.selected);
    imageObject.src = this.mainLoader.src;
    imageObject.parent = this;
    this.prepareImage(this.selected, imageObject);
    this.fadeImageIn(this.selected);
    this.loadPicturesInWindow();
}

gallerySliders.prototype.loadPicturesInWindow = function()
{
    //load all the pictures in the current window
    for(var i = this.windowStart; i < this.windowStart + this.windowSize; i++) {
        if (i != this.selected && i <= this.count) {
            var imageObject = this.getItemImageObject(i);
            imageObject.parent = this;
            imageObject.sliderIndex = i;
            imageObject.onload = function () {
                this.parent.loadPicturesInWindowCallback(this.sliderIndex, this);
            }
            imageObject.src = this.pictures[i].uri;
        }
    }
    this.windowLoaded = 1;
}

gallerySliders.prototype.loadPicturesInWindowCallback = function (index, imageObject)
{
    this.prepareImage(index, imageObject);
    this.fadeImageIn(index);
    this.windowLoaded++;
    if (this.windowLoaded == this.windowSize) {
        this.loadPicturesOther();
    }
}

gallerySliders.prototype.loadPicturesOther = function()
{
    //load all the remaining pictures
    for(var i = 1; i <= this.count; i++) {
        if (i != this.selected && (i < this.windowStart || i > (this.windowStart + this.windowSize - 1))) {
            var imageObject = this.getItemImageObject(i);
            imageObject.parent = this;
            imageObject.sliderIndex = i;
            imageObject.onload = function () {
                this.parent.loadPicturesOtherCallback(this.sliderIndex, this);
            }
            imageObject.src = this.pictures[i].uri;
            imageObject.style.left = this.pictures[i].offset + "px";
        }
    }
}

gallerySliders.prototype.loadPicturesOtherCallback = function(index, imageObject)
{
    this.prepareImage(index, imageObject);
    //no need to fade in, the images are not visible anyway
    imageObject.style.display = "block";
}

gallerySliders.prototype.prepareImage = function(index, imageObject)
{
    imageObject.style.height = this.getItemObject(this.selected).offsetHeight + "px";
    imageObject.parent = this;
    imageObject.style.width = this.normalImageWidth + "px";
    if (index != this.selected) {
        imageObject.style.left = this.pictures[index].offset + "px";
    }
    imageObject.onclick = function () {
        if (this.parent.selected != index) {
            if (!this.lightBoxCall) {
                this.lightBoxCall = this.parentNode.onclick;
                this.parentNode.onclick = function () {};
            }
            this.parent.selectImage(index);
        } else if (this.lightBoxCall) {
            this.lightBoxCall();
        }
    }
}

gallerySliders.prototype.fadeImageIn = function(index)
{
    var imageObject = this.getItemImageObject(index);
    imageObject.style.display = "block";
    var maxFrames = 20;
    var animationFunction = function (frame) {
        var opacity = frame/maxFrames
        if (document.all) {
            imageObject.style.filter = "alpha(opacity=" + Math.round(100 * opacity) + ")";
        } else {
            imageObject.style.opacity = opacity;
        }
    }
    imageObject.fadeImageIn = new ApOnAnimation(0, maxFrames, 40, "linear", animationFunction);
    imageObject.fadeImageIn.start();
}

gallerySliders.prototype.showHideNextPrev = function(toWindow)
{
    this.prevButton.style.display = (toWindow > 1 ? "block" : "none");
    this.nextButton.style.display = (toWindow <= this.count - this.windowSize ? "block" : "none");
    var height = $("galleryItems_" + this.instance).offsetHeight;
    this.prevButton.style.height = height + "px";
    this.nextButton.style.height = height + "px";
}

gallerySliders.prototype.nextWindow = function()
{
    if (this.windowStart <= this.count - this.windowSize) {
        var targetWindow = this.windowStart + this.windowSize;
        if (targetWindow > this.count - this.windowSize + 1) {
            targetWindow = this.count - this.windowSize + 1;
        }
        var targetIndex  = this.selected;
        this.animate(targetIndex, targetWindow);
        this.showHideNextPrev(targetWindow);
    }
}

gallerySliders.prototype.prevWindow = function(index)
{
    if (this.windowStart > 1) {
        var targetWindow = this.windowStart - this.windowSize;
        if (targetWindow < 1) {
            targetWindow = 1;
        }
        var targetIndex  = this.selected;
        this.animate(targetIndex, targetWindow);
        this.showHideNextPrev(targetWindow);
    }
}

gallerySliders.prototype.selectImage = function(index)
{
    this.animate(index, this.windowStart);
}

gallerySliders.prototype.animate = function(toIndex, toWindow)
{
    if (this.selecting || (toIndex == this.selected && this.windowStart == toWindow)) {
        return;
    }
    if (toIndex < toWindow) {
        toIndex  = toWindow;
    } else if (toIndex > toWindow + this.windowSize - 1) {
        toIndex  = toWindow + this.windowSize - 1;
    }
    this.selecting = true;
    var maxFrames = 30;
    this.toSelect = toIndex;
    this.toWindow = toWindow;
    //the animation function
    var slider = this;
    //initial and final positions for animation
    var startPos = new Array();
    var endPos = new Array();
    var initialOffset = (this.narrowWidth + this.span) * (this.windowStart - 1);
    var targetOffset  = (this.narrowWidth + this.span) * (this.toWindow - 1);
    //these do not include the offset, which is calculated by frame
    for (var i = 1; i <= this.count; i++) {
        startPos[i] = (this.narrowWidth + this.span) * (i - 1) + (i > this.selected ? (this.normalImageWidth - this.narrowWidth) : 0);
        endPos[i]   = (this.narrowWidth + this.span) * (i - 1) + (i > this.toSelect ? (this.normalImageWidth - this.narrowWidth) : 0);
    }
    //animation function
    var animationFunction = function (frame) {
        //size
        var narrow = slider.narrowWidth;
        var normal = slider.normalImageWidth;
        if (slider.toSelect != slider.selected) {
            //increasing slider
            var width = Math.round(narrow + frame * (normal - narrow) / maxFrames);
            var itemObject = slider.getItemObject(slider.toSelect);
            itemObject.style.width = width + "px";
            //decreasing slider
            var width = Math.round(normal + frame * (narrow - normal) / maxFrames);
            var itemObject = slider.getItemObject(slider.selected);
            itemObject.style.width = width + "px";
        }
        //position
        var offset = initialOffset + frame * (targetOffset - initialOffset) / maxFrames;
        for (var i = 1; i <= slider.count; i++) {
            var sliderDiv = slider.getItemObject(i);
            var left = Math.round(startPos[i] + frame * (endPos[i] - startPos[i]) / maxFrames) - offset;
            sliderDiv.style.left = left + "px";
        }
        //offset inside
        if (slider.toSelect != slider.selected) {
            var innerOffset = (maxFrames - frame) * slider.pictures[slider.selected].offset / maxFrames;
            //increasing slider
            var imageObject = slider.getItemImageObject(slider.toSelect);
            imageObject.style.left = innerOffset + "px";
            //decreasing slider
            var innerOffset = frame * slider.pictures[slider.toSelect].offset / maxFrames;
            var imageObject = slider.getItemImageObject(slider.selected);
            imageObject.style.left = innerOffset + "px";
        }
        //termination
        if (frame == maxFrames) {
            slider.selecting = false;
            slider.selected = slider.toSelect;
            slider.windowStart = slider.toWindow;
            slider.rearrangeEditors();
        }
    }
    //create the animation
    this.selectAnimation = new ApOnAnimation(0, maxFrames, 25, "accelerated", animationFunction);
    this.selectAnimation.start();
}

gallerySliders.prototype.rearrangeEditors = function(index)
{
    if (typeof ApOnEditors == "function") {
        //hide all editors for the items
        ApOnEditors.hideEditorsFor($("galleryItems_" + this.instance), true);
        //show only the selected one and the add editor
        if (this.count > 0) {
            ApOnEditors.unhideEditorsFor(this.getItemObject(this.selected), true);
        }
        ApOnEditors.unhideEditorsFor($("galleryItems_" + this.instance));
        //show the narrow size editor
        if (this.windowStart == 1) {
            var editors = ApOnEditors.getEditorKeys(this.getItemObject(1), true, "size");
            if (editors.length > 0) {
                if (this.selected > 1) {
                    ApOnEditors.unhideEditor(editors[0]);
                } else {
                    ApOnEditors.hideEditor(editors[0]);
                }
            }
        }
        //make sure all editors are correctly suggested
        ApOnEditors.update();
        //reposition editors
        ApOnEditors.reposition();
    }
}

function galleryOptionsValue()
{
	return {roundness: $('galleryOptionsCornerRoundness').value};
}
