var PicController = Class.create({

    display: null,
    queue: null,
    updateInterval: null,
    updateId: null,
    fetchInterval: null,
    fetchId: null,
    updateData: null,
    cycleRepeat: null,

    initialize: function (slots, updateInterval, fetchInterval, url, imgUrl, profileUrl, updateData, cycleRepeat) {
        this.display = new PicDisplay(imgUrl, profileUrl, slots);
        this.queue = new PicQueue(url, imgUrl);
        this.updateInterval = updateInterval;
        this.fetchInterval = fetchInterval;
        this.updateData = updateData;
        this.cycleRepeat = cycleRepeat;
    },

    start: function () {
        if(this.isRunning())
            this.stop();
        this.fetch();
        this.updateId = setTimeout(this.update.bind(this, null), 1000);

    },

    update: function (item) {
        if(!item)
            var item = this.queue.next();

        if(item && this.queue.imageComplete()){
            this.display.displayItem(item);
            if(this.cycleRepeat || this.queue.hasMore()){
                this.queue.preloadNext();
                this.updateId = setTimeout(this.update.bind(this, null), this.updateInterval);
            }
            else {
                this.display.clear();
            }
        }
        else{
            this.updateId = setTimeout(this.update.bind(this, item), 500);
        }
    },

    fetch: function () {
        if(this.queue.runningOut() && !this.queue.isFetching())
            this.queue.fetch();
        if(this.updateData && !this.queue.isTooManyFetches())
            this.fetchId = setTimeout(this.fetch.bind(this), this.fetchInterval);
    },

    stop: function () {
        clearTimeout(this.runInterval);
        clearTimeout(this.fetchInterval);
    },

    isRunning: function () {
        return this.updateId || this.fetchId;
    }

});


var PicDisplay = Class.create({

    imgUrl: null,
    profileUrl: null,
    slots: null,

    initialize: function (imgUrl, profileUrl, slots) {
        this.imgUrl = imgUrl;
        this.profileUrl = profileUrl;
        this.slots = slots;
    },

    displayItem: function (item) {
        var where = Math.floor(Math.random()*this.slots);
        var pic = $("pb"+where).down("img");
        var anchor = $("pb"+where).down("a");

        new Effect.toggle(pic, "appear", {
            duration: 1.5
        });

        setTimeout(
            function() {
                pic.src = this.imgUrl.interpolate(item);
                anchor.href = this.profileUrl.interpolate(item);

                new Effect.toggle(pic, "appear", {
                    duration: 1.5
                });

            }.bind(this), 1600
        );
    }

});

var PicQueue = Class.create({
    itemList: null,
    itemsLeft: null,
    index: null,
    url: null,
    imgUrl: null,
    memento: null,
    nextImg: null,
    fetchAttempts: null,
    fetching: null,

    initialize: function (url, imgUrl) {
        this.index = 0;
        this.url = url;
        this.imgUrl = imgUrl;
        this.itemList = new Array();
        this.itemsLeft = 0;
        this.nextImg = new Image();
        this.fetchAttempts = 0;
        this.fetching = false;
    },

    next: function(){
        var item = this.itemList[this.index];
        if(item){
            this.itemsLeft--;
            this.index++;
        }
        if(this.index == this.itemList.length)
            this.index = 0;
        return item;
    },

    preloadNext: function(){
        try{
            this.nextImg.src = this.imgUrl.interpolate(this.itemList[this.index]);
        } catch(err){
           // Nothing to load yet, wait for next try.
        }
    },

    hasMore: function() {
        return (this.itemsLeft >= 0);
    },

    runningOut: function() {
        return (this.itemsLeft < 1);
    },

    imageComplete: function() {
        return this.nextImg.complete;
    },

    isTooManyFetches: function() {
        return (this.fetchAttempts > 4);
    },

    isFetching: function() {
        return this.fetching;
    },

    fill: function(result) {
        if(result.items.length > 0){
            this.memento = result.memento;
            this.itemList = result.items;
            this.itemsLeft = this.itemList.length;
            this.preloadNext();
            this.fetchAttempts = 0;
        }
        this.fetching = false;
    },

    fetchError: function (result) {
        this.fetching = false;
        if (console)
            console.dir(result);
    },

    fetch: function () {
        this.fetchAttempts++;
        this.fetching = true;
        new PupAjax.JSONRequest(
            this.url, {
            parameters: {
                memento: this.memento
            },
            onSuccess: this.fill.bind(this),
            onError: this.fetchError
        });
    }
});
