// Init SoundManager Immediately
window.audioPath = '/adventure/audio/';
if (window.soundManager) {
    var soundManager = window.soundManager;
    soundManager.debugMode = false; // disable debug output
    soundManager.url = '/adventure/SoundManager/soundmanager2.swf'; // path to movie
}


// Stuff to run at load time for all game stages
$(function () {
    // Anything hidden with CSS should be changed to be hidden the jQuery way so we can use show()/hide() without problems.
    $('.hide').hide().removeClass('hide');
    
    $('#shade').css('opacity', 0.7);
});


/**
 * Preload magicks
 * @param {Array} images An array of paths to images to preload
 * @param {Object} audio An object whose property names are the audio ids and whose property values are the paths to the audio files for those ids
 * @param {Function} after_preload The callback function for once preloaded can completed
 */
function preload(images, audio, after_preload) {
    var thingsToLoadCount = 2;
    
    if (typeof images == 'undefined' || !images) {
        images = new Array();
    }
    
    var imagesDefaults = new Array(
                                    '/adventure/css/images/phone-big.png',
                                    '/adventure/css/images/phone-small.png',
                                    '/adventure/images/phone/notes_background.gif',
                                    '/adventure/images/phone/notes_header_background.gif',
                                    '/adventure/images/phone/notification.gif',
                                    '/adventure/images/phone/text_message.png',
                                    '/adventure/images/loading_wheel.gif',
                                    '/adventure/images/error.png',
							 '/adventure/css/images/black85.png'
                                    );
    
    images = imagesDefaults.concat(images);
    var myPreloader = new Preloader(false);
    myPreloader.load(images, load_checker);
    
    var audioDefaults = {
        text: 'text-message.mp3',
	   success: 'cheer.mp3',
	   success2: 'cheer.mp3',
        fail: 'boo.mp3',
	   fail2: 'boo.mp3'
    };
    
    audio = $.extend(audioDefaults, audio);
    var myAudioPreloader = new AudioPreloader();
    myAudioPreloader.load(audio, load_checker);
    
    if (thingsToLoadCount == 0) {
        $('#loading').fadeOut(500, after_preload);
    }
    
    function load_checker() {
        thingsToLoadCount--;
        
        if (thingsToLoadCount == 0) {
             $('#loading').fadeOut(500, after_preload);
        }
    }
}


/**
 * Darken everything except the directions
 */
function show_shade() {
    $('#shade').fadeTo(1000, 0.5);
}


/**
 * Unbedarken stuff
 */
function hide_shade() {
    $('#shade').fadeOut(1000);
}


/**
 * Change the screen background
 */
function change_screen(new_img_url) {
    $('#screen').fadeOut(
        500,
        function () {
            $('#screen, #screen-blur').css('backgroundImage', 'url(' + new_img_url + ')');
            $('#screen').fadeIn(500);
        }
    );
}


/**
 * Just a little wrapper for jumping to a new stage. Great function name was totally unintentional.
 * @param {Number} stage The number of the stage you want to jump to
 */
function stage_jump(stage) {
    show_direction('<p>Moving to next stage.  One second&hellip;</p>');
    $.get('ajax/stage_jump.php?add_to_score=' + window.add_to_score, function () {
        location.href = 'http://www.sua.umn.edu/adventure/stage' + stage + '#game';
    });
}


/**
 * Run a function after the user has clicked
 * @param {Function} func The function to run [once] after the user clicks.
 */
function run_after_click(func) {
    $('#game').one('click', func);
}


/**
 * Show the user some directions / stage directions.  Get it?
 * @param {String} direction The HTML you want to show as a direction
 */
function show_direction(direction) {
    if (!direction.match(/^<p/)) {
        direction = '<p>' + direction + '</p>';
    }
    
    $('#direction').html(direction).show();
}


/**
 * Hide direction thinger
 */
function hide_direction() {
    $('#direction').hide();
}


/**
 * Executes a chain of functions, displaying a "click to continue" direction 1s after each function and waits for user click before executing the next function.
 * @param {Array} functions An array of functions that will be executed
 * @param {Function} callback An optional callback to be executed at the end
 */
function click_to_continue_functions(functions, callback) {
    var queue = new Array();
    var i, o, msg;
    
    for (i = 0; i < functions.length; i++) {
        o = {
            f: functions[i]
        }
        
        queue.push(o);
    }
    
    o = {
        f: function () {
            if (callback) {
                (callback)();
            }
        }
    }

    queue.push(o);
    
    new TimedQueue(queue, {stepFunc: click_step, delay: 1000});
    
    function click_step() {
        var self = this;
        show_direction('<p>Click anywhere to continue&hellip;</p>');
        run_after_click(function() {
            hide_direction();
            self.next();
        });
    }
}


/**
 * Show a chain of directions, highlights "click to continue" after 1s and waits for user click before showing the next direction.
 * @param {Array} directions An array of strings that are the directions to show
 * @param {Function} callback An optional callback to be executed at the end
 */
function show_directions(directions, callback) {
    var queue = new Array();
    var i, o, msg;
    
    for (i = 0; i < directions.length; i++) {
        msg = directions[i] + '<p class="clicktocontinue disabled">Click anywhere to continue&hellip;</p>';
        
        o = {
            f: show_direction,
            args: [msg]
        }
        
        queue.push(o);
    }
    
    o = {
        f: function () {
            hide_direction();
            
            if (callback) {
                (callback)();
            }
        }
    }

    queue.push(o);
    
    new TimedQueue(queue, {stepFunc: directions_step, delay: 1000});
    
    function directions_step() {
        var self = this;
        $('.clicktocontinue').removeClass('disabled');
        run_after_click(function() {
            self.next();
        });
    }
}


function texts_and_click_callback(texts, callback) {
    var queue = new Array();
    var o;
    
    for (var i = 0; i < texts.length; i++) {
        var func = (function (msg) {
            return function () {bigPhone.textMsg(msg);};
        })(texts[i]);
        
        o = {
            f: func
        }
        
        queue.push(o);
    }
    
    queue.push({
        f: function () {
            show_direction('<p>Click anywhere to continue&hellip;</p>');
            run_after_click(
                function() {
                    hide_direction();
                    (callback)();
                }
            );
        }
    });
    
    new TimedQueue(queue, {delay: 1500});
}


//
// Various library stuff below this point
//


// Fix jQuery fadeTo() so it can bring back something after hide() or fadeOut()
(function ($) {
    var proxied = $.fn.fadeTo;
    $.fn.fadeTo = function() {
        if ($(this).is(':hidden')) {
            $(this).css('opacity', 0).show();
        }
        
        return proxied.apply(this, arguments);
    }
    
    /* fadeOut() and fadeIn() seem to work correctly, actually /*
    $.fn.fadeOut = function (speed, callback) {
        $(this).fadeTo(
            speed,
            0,
            function () {
                $(this).hide();
                
                if (callback) {
                    (callback)();
                }
            }
        );
    }
    
    $.fn.fadeIn = function (speed, callback) {
        $(this).css('opacity', 0).show().fadeTo(speed, 1, callback);
    }
    */
})(jQuery);


/**
 * Execute a list of functions with custom delay between each function and a custom step function that executes between each function in the list.
 * @param {Array} queue An array of objects describing the functions to execute and their settings.
 * @param {Object} options An object that sets global options for the functions being executed.
 */
function TimedQueue(queue, options) {
    this.index = 0;
    
    this.queue = queue;
    
    this.defaultOptions = {
        stepFunc: function () {
            this.next();
        },
        delay: 0
    }
    
    this.options = $.extend({}, this.defaultOptions, options);
    
    var self = this;
    
    function dispatch() {
        
        var o = self.queue[self.index];
        self.index++;
        
        if (typeof o.args == 'undefined') {
            o.args = [];
        }
        
        o.f.apply(o.f, o.args);
        
        // Can't do || syntax here because zero is a valid value
        var delay = (typeof o.delay == 'undefined') ? self.options.delay : o.delay;
        
        var stepFunc = o.stepFunc || self.options.stepFunc;
        
        if (self.index < self.queue.length) {
            setTimeout(
                function () {stepFunc.call(self);},
                delay
            );
        }
    }
    
    this.next = function () {
        if (self.index < self.queue.length) {
            dispatch();
        }
    }
    
    dispatch();
}


/**
 * Timer class from zachstronaut.com
 */
function Timer(func, timing, repeat) {
    var count = 0;
    
    if(!repeat) {
        repeat = 0;
    }
    
    var timer = null;
    
    var self = this;
    
    this.start = function () {
        if (onBeforeStartFunc) {
            onBeforeStartFunc();
        }
        timer = setInterval(
                    function () {
                        if (!func(count) || (repeat > 0 && ++count >= repeat)) {
                            self.stop();
                        }
                    },
                    timing
                    );
        
        return this;
    };
    
    this.stop = function () {
        if (timer) {
            clearTimeout(timer);
            timer = null;
            if (onStopFunc) {
                onStopFunc();
            }
        }
    };
    
    this.cancel = function () {
        if (timer) {
            clearTimeout(timer);
            timer = null;
        }
    };
    
    var onBeforeStartFunc = null;
    this.onBeforeStart = function (f) {
        onBeforeStartFunc = f;
        
        return this;
    };
    
    var onStopFunc = null;
    this.onStop = function (f) {
        onStopFunc = f;
        return this;
    };
}


//
// Preloader stuff from Paul Armstrong
//

$.extend(Function.prototype, {
    use: function() {
		var method = this, args = Array.prototype.slice.call(arguments), object = args.shift();
		return function() {
			return method.apply(object, args.concat(Array.prototype.slice.call(arguments)));
		}
    },
    useEL: function() {
        var method = this, args = Array.prototype.slice.call(arguments), object = args.shift();
        return function(event) {
            return method.apply(object, [event || window.event].concat(Array.prototype.slice.call(arguments)));
        }
    }
});

/**
 * Preloader
 * @param overlay [boolean]     Whether or not the Preloader shows and overlay and loading message
 *
 * Usage:
 * var myPreloader = new Preloader(false);
 * $(myPreloader).bind('loading', myLoadStartCallback);
 * $(myPreloader).bind('loaded', myLoadCompleteCallback);
 * $(myPreloader).bind('error', myLoadErrorCallback); // event.data.message returns error text string from Preloader.strings.error
 * myPreloader.load(['img1.png', 'img2.png', 'img3.png';]);
 */
var Preloader = function(overlay) {
    this.cache = [];
    this.loading = false;

    if(overlay) {
        this.els = {
            overlay: $(Preloader.selectors.overlay),
            container: $(Preloader.selectors.loadingBox)
        };

        this.show();
    }
};

$.extend(Preloader.prototype, {
   _load: function(source) {
       if($.inArray(source, this.cache) != -1) {
           $(this).trigger('loaded');
           return;
       }

       var image = new Image();

       image.onload = function() {
           this.cache.push(image.src);
           $(this).trigger('loaded');
       }.use(this);

       image.onerror = function() {
           $(this).trigger('error', {image: source});
       }.use(this);

       this.loading = true;

       $(this).trigger('loading', {image: source});

       image.src = source;
   },
   load: function(sources) {
       var sources = $.makeArray(sources);

       var preCacheLength = this.cache.length;
       var l = sources.length;

       $(this).bind('loaded', function(event) {
           if(sources.length+preCacheLength == this.cache.length) {
               $(this).trigger('complete');
           }
       }.useEL(this));

       while(l--) {
           this._load(sources[l]);
       }
   },
   setPosition: function() {
       var leftCenter = Math.round(($(window).width()/2)-(this.els.container.width()/2));
       var topCenter = Math.round(($(window).height()/2)-(this.els.container.height()/2));

       this.els.container.css({ 'top': topCenter+'px', 'left': leftCenter+'px' });
   },
   show: function() {
       this.els.overlay.show();
       this.setPosition();
       this.els.container.show();
   },
   hide: function() {
       setTimeout(function() {
           this.els.overlay.fadeOut(2000)
           if($.support.opacity) {
               this.els.container.fadeOut(2000)
           } else {
               this.els.container.hide()
           }
       }.use(this), Preloader.minTimeout);
   }
});
$.extend(Preloader, {
    strings: {
        error: 'Error loading images. Please reload this page to try again.'
    },
    selectors: {
        overlay: '#overlay',
        loadingBox: '#loadingBox' 
    },
    minTimeout: 1000
});


// Further Preloader extension by Zach including monkey patching / proxy pattern patching
(function (Preloader) {
    var proxy = Preloader.prototype.load;
    
    $.extend(Preloader.prototype, {
        sources: null,
        
        load: function (sources, callback) {
            this.sources = $.makeArray(sources);
            
            $(this).bind('loaded', this.progressStep);
            $(this).bind('error', this.progressError);
            $(this).bind('complete', callback);
            
            return proxy.call(this, sources);
        },
        
        progressError: function () {
            $('#loading-error').show();
        },
        
        progressStep: function () {
            $('#loading-bar').css('width', Math.floor((this.cache.length / this.sources.length) * 100) + '%');
        }
    });
})(Preloader);


// Zach's audio preloader for SoundManager2
var AudioPreloader = function () {
    this.audio = null;
    this.audioCount = 0;
    this.loadedCount = 0;
    this.callback = function () {};
}

$.extend(AudioPreloader.prototype, {
    load: function (audio, callback) {
        this.audio = audio;
        
        for (var id in audio) {
            if (id != 'soundtrack') {
                this.audioCount++;
            }
        }
        
        if (callback) {
            this.callback = callback;
        }
        
        if (window.soundManager) {
            var soundManager = window.soundManager;

            soundManager.defaultOptions = ({'autoLoad': true});

            soundManager.onload = function () {
                for (id in audio) {
                    var audioURL = window.audioPath + audio[id];
                    if (navigator.appVersion.indexOf('MSIE') != -1) {
                        audioURL += '?' + Math.random();
                    }
                    
                    if (id == 'soundtrack') {
                        soundManager.createSound(
                            {
                                id: 'soundtrack',
                                url: audioURL,
                                onfinish: function() {
                                    soundManager.play('soundtrack', {volume: 15});
                                },
                                onload: function() {
                                    soundManager.play('soundtrack', {volume: 15});
                                }
                            }
                        );
                        
                    } else {
                        soundManager.createSound(
                            {
                                id: id,
                                url: audioURL,
                                onload: this.progressStep.use(this)
                            }
                        );
                    }
                }
            }.use(this);
        }
    },
    
    progressStep: function () {
        this.loadedCount++;

        $('#audio-loading-bar').css('width', Math.floor((this.loadedCount / this.audioCount) * 100) + '%');
        
        if (this.loadedCount == this.audioCount) {
            (this.callback)();
        }
    }
});


/**
 * Play a sound by its sound id
 * @param {String} soundID The id that the audio file / sound was loaded as
 */
function triggerSound(soundID) {
    var soundManager = window.soundManager;
    soundManager.play(soundID);
}

/**
 * Format numbers with commas
 * 
 * @author http://www.mredkj.com/javascript/nfbasic.html
 * @param {Number} nStr
 * @type String
 */
function add_commas(nStr)
{
	nStr += '';
	
	x = nStr.split('.');
	x1 = x[0];
	x2 = x.length > 1 ? '.' + x[1] : '';
	
	var rgx = /(\d+)(\d{3})/;
	
	while (rgx.test(x1))
	{
		x1 = x1.replace(rgx, '$1' + ',' + '$2');
	}
	
	return x1 + x2;
}


var add_to_score = 0;