/**
 *  JSlides class.
 *  Options is an object with the folowing properties:
 *
 *  @param string options.id        The id for the div where the slides will be inserted.
 *  @param string options.slideList An URL where a JSON list of slide URLs
 *                                  can be located.
 *  @param integer options.speed    The slide animation speed. This can also take
 *                                  the values "slow", "normal", "fast"
 *  @param integer options.start    The starting slide index, zero-based. Default
 *                                  is 0.
 *  @param boolean options.numbered If this is true a div with numbered links
 *                                  to each slide will be generated.
 *  @param boolean options.debug    Enable debuging messages, you will need Firebug
 *                                  for this to work.
 *  @param boolean options.autoHtml If this is false the class does not generate
 *                                  the slides HTML, if it's not set then
 *                                  we consider it to be set to true.
 *                               
 *  The id and slideList options are required.
 */
function JSlides(options)
{
    if(window.console && window.console.firebug && options.debug)
    {
        var debug = true;
    }
    else
    {
        var debug = false;
    }

    //Check if the required options (className and slideList) are set.
    if(debug && !options.id)
    {
        console.log("JSlides: You need to provide an id for the slide container.");
    }
    if(debug && !options.slideList)
    {
        console.log("JSlides: You need to provide a slide list.");
    }

    //Check the speed option
    if(!options.speed)
    {
        options.speed = "normal";
    }

    var slides = jQuery("#" + options.id);
    if(debug && !slides)
    {
        console.log("Slides div not found. Are you sure that \'" +
            options.className + "\' is a valid css class?");
    }

    if(options.autoHtml || options.autoHtml == undefined)
    {
        /*
         *  The slide div will contain the folowing HTML:
         */
        var html = '                                                             \
            <a href="javascript:void(null)" class="prev prev-disabled"></a>      \
                <div class="canvas">                                             \
                    <div class="animation"></div>                                \
                </div>                                                           \
                <div class="loading"></div>                                      \
            <a href="javascript:void(null)" class="next next-disabled"></a>      \
            <div class="numbers"></div>                                          \
       ';

        //Start building the HTML
        slides.html(html);
    }
  
    var canvas = slides.find(".canvas");
    var next = slides.find(".next");
    var prev = slides.find(".prev");
    var loading = slides.find(".loading");
    var animation = slides.find(".animation");
    var numbers = slides.find(".numbers");
    
    var width = canvas.width();
    var height = canvas.height();
    

    //Some initial state
    loading.fadeIn("normal");
    slides.css({"display":"block"});
    canvas.css({"width":width+"px", "height":height+"px", "position":"relative", "overflow":"hidden", "display":"block"});

    animation.css({"width":width+"px", "height":height+"px", "position":"relative", "overflow":"visible", "display":"block"});
    numbers.hide();
    
    slides.cache = new Array();
    slides.urls = new Array();
    slides.num = 0;
    if(options.start)
    {
        slides.current = options.start;
    }
    else
    {
        slides.current = 0;
    }

    //Load the slide list
    jQuery.get(options.slideList, null, function(data) {
        slides.urls = data;
        slides.cache.length = slides.urls.length;
        slides.num = slides.urls.length

        if(slides.num <= slides.current)
        {
            slides.current = slides.num - 1;
        }

        //Load the first slide
        jQuery.get(slides.urls[slides.current], null, function(data) {
            slides.cache[slides.current] = data;
            animation.html(slides.cache[slides.current]);
            animation.find(".slide").css({
                "width":width+"px",
                "height":height+"px",
                "display":"block",
                "float":"left",
                "clear":"none"
            });
            
            //Set the next/prev state
            if(slides.current > 0) prev.removeClass("prev-disabled");
            if(slides.current < slides.num - 1) next.removeClass("next-disabled");

            //Done, hide the loader and show the slide
            loading.fadeOut("normal")
            
            //Setup the numbers
            if(options.numbered)
            {
                for(var i=0; i<=slides.num-1; i++)
                {
                    var classes = "number " + "n" + i;
                    if(i == slides.current)
                    {
                        classes += " current";
                    }
                    if(i%2 == 0)
                    {
                        classes += " even";
                    }
                    else
                    {
                        classes += " odd";
                    }
                    if(i == 0)
                    {
                        classes += " first";
                    }
                    else
                    {
                        if(i == slides.num-1)
                        {
                            classes += " last";
                        }
                    }
                    numbers.append('<a href="javascript:void(null)" class="'+classes+'">'+(i+1)+'</a>');
                }
                numbers.fadeIn("normal");

                numbers.find(".number").click(function() {
                    var i = parseInt(jQuery(this).text())
                    
                    if(!isNaN(i))
                    {
                        changeSlide(i-1);
                    }
                });
            }
        }, "html");
    }, "json");

    /**
     *  Change the slide.
     *
     *  @param integer i The slide index.
     */
    function changeSlide(i)
    {
        if(i == slides.current)
        {
            return;
        }

        loading.show();
        
        if(debug)
        {
            console.log("JSlides: changing slide, from "+slides.current+" to "+i)
        }
        
        if(i < 1)
        {
            prev.addClass("prev-disabled");
        }
        else
        {
            prev.removeClass("prev-disabled");
        }

        if(i >= slides.num-1)
        {
            next.addClass("next-disabled");
        }
        else
        {
            next.removeClass("next-disabled");
        }

        /**
         *  Animate the slides.
         *
         *  @param integer from The starting slide index.
         *  @param integer to The end slide index.
         */
        function animate(from, to)
        {            
            var end = 0;
            var start = 0;
            animation.html("");

            if(from < to)
            {
                for(var j=from; j<=to; j++)
                {
                    animation.append(slides.cache[j]);
                }
                start = 0;
                end = -(to-from)*width;
            }
            else
            {
                for(var j=to; j<=from; j++)
                {
                    animation.append(slides.cache[j]);

                }
                start = -(from-to)*width;
                end = 0;
            }

            animation.css({
                "left":start+"px",
                "width":Math.abs(end-start)+width+"px"
            });
            animation.find(".slide").css({
                "width":width+"px",
                "height":height+"px",
                "display":"block",
                "float":"left",
                "clear":"none"
            });
            
            animation.animate({"left":end+"px"}, "normal", "swing");
            slides.current = to;

            numbers.find('.number').removeClass("current");
            numbers.find('.n'+to).addClass("current");
        }

        /**
         *  Load and cache a slide. Slide loading is done with a sinchronous
         *  request.
         *
         *  @param integer i The slide index.
         */
        function loadSlide(i)
        {
            jQuery.ajax({
                type: "GET",
                url: slides.urls[i],
                async: false,
                complete: function(data) {
                    slides.cache[i] = data.responseText;
                }
            });
        }

        //Preloading
        from = Math.min(slides.current-1, i-1);
        to = Math.max(slides.current-1, i+1);
        for(var j=from; j<=to; j++)
        {
            if(j >= 0 && j < slides.num && !slides.cache[j])
            {
                if(debug)
                {
                    console.log("JSlides: preloading "+j);
                }
                loadSlide(j);
            }
        }
        loading.hide();

        animate(slides.current, i);
    }

    //The next/prev click handlers
    next.click(function() {
        if(!next.hasClass("next-disabled")) changeSlide(slides.current+1);
    });
    prev.click(function() {
        if(!prev.hasClass("prev-disabled")) changeSlide(slides.current-1);
    });
}