;(function ($) {
/*!
jQuery.jwPlayer
by Keith C. Ivey, keith@iveys.org
Copyright 2010, Smokescreen Corporation
Dual licensed under the MIT and GPL licenses
http://www.opensource.org/licenses/mit-license.php
http://www.gnu.org/licenses/gpl.html
Version 0.115 (2010-08-18)
*/

var pluginName = 'jwPlayer';

if (!window.console) { console = {}; } // prevent errors from console.log calls
if (!console.log) { console.log = $.noop; }

var eventType = {
    ITEM: 'Controller',
    MUTE: 'Controller',
    PLAY: 'Controller',
    PLAYLIST: 'Controller',
    RESIZE: 'Controller',
    SEEK: 'Controller',
    STOP: 'Controller',
    VOLUME: 'Controller',
    BUFFER: 'Model',
    ERROR: 'Model',
    LOADED: 'Model',
    META: 'Model',
    STATE: 'Model',
    TIME: 'Model',
    FULLSCREEN: 'View',
    LINK: 'View',
    LOAD: 'View',
    NEXT: 'View',
    PREV: 'View',
    REDRAW: 'View'
};

// Properties to be set in object data when listeners are fired
var listenerProperties = {
    ITEM: {index: 'item'},
    STATE: {newstate: 'state'},
    TIME: {position: 'position', duration: 'duration'},
    VOLUME: {volume: 'volume'}
};

var flashvarNames = [
    'author',
    'autostart',
    'backcolor',
    'bufferlength',
    'config',
    'controlbar',
    'date',
    'debug',
    'description',
    'displaytitle',
    'dock',
    'duration',
    'file',
    'frontcolor',
    'fullscreen',
    'icons',
    'image',
    'item',
    'lightcolor',
    'mute',
    'playerready',
    'playlist',
    'playlistfile',
    'playlistsize',
    'plugins',
    'provider',
    'repeat',
    'screencolor',
    'shuffle',
    'skin',
    'smoothing',
    'start',
    'streamer',
    'stretching',
    'tags',
    'title',
    'volume'
];

// Return global function name that's not being used
function getFunctionName(base) {
    var name, i = 0;
    while (true) {
        name = pluginName + '_' + base;
        if (i) {
            name += i;
        }
        if (!window[name]) {
            return name;
        }
        i++;
    }
}

$.fn[pluginName] = function (opts) {
    var fn, args, data, prop;
    if (typeof opts == 'string') { // it's a method name
        fn = $.fn[pluginName][opts];
        if (!fn) {
            throw('No such method: ' + pluginName + '.' + opts);
        }
        args = $.makeArray(arguments).slice(1);
        data = this.data(pluginName);
        if (!data) {
            throw('Constructor not called: ' + pluginName + '.' + opts);
        }
        args.unshift(data);
        return fn.apply(this, args);
    }
    opts = $.extend({}, $.fn[pluginName].defaults, opts);
    // put flashvars into subobject
    for (prop in opts) {
        if ($.inArray(prop, flashvarNames) != -1) {
            opts.flashvars[prop] = opts[prop];
            delete opts[prop]; 
        }
    }
    // Convert integers to pixels
    if (opts.height.toString().match(/^[0-9]+$/)) {
        opts.height += 'px';
    }
    if (opts.width.toString().match(/^[0-9]+$/)) {
        opts.width += 'px';
    }
    return this.each( function (index) {
        var id = opts.id,
            $this = $(this);
        if (index) {
            id += '-' + index;
        }
        if ($('#' + id).length) {
            $.error('id "' + id + '" already exists in document');
        }

        function makeListener(propMap, listenerName) {
            return function (obj) {
                var n, seek;
                for (n in propMap) {
                    $this[pluginName]('set', propMap[n], obj[n]);
                }
                if (listenerName == 'statelistener') {
                    seek = $this[pluginName]('get', 'seek');
                    if ((obj.newstate == 'PAUSED' ||
                        obj.newstate == 'PLAYING') && seek !== false) {
                        $this[pluginName]('set', 'seek', false);
                        $this[pluginName]('seek', seek);
                    }
                }
                if (opts[listenerName]) {
                    opts[listenerName](obj);
                }
            };
        }

        // Set up array of listeners to be added in playerReady.
        var eventName, listenerName, propMap,
            listeners = {};
        for (eventName in eventType) {
            listenerName = eventName.toLowerCase() + 'listener';
            if (listenerProperties[eventName]) {
                propMap = listenerProperties[eventName];
                listeners[eventName] = makeListener(propMap, listenerName);
            }
            else if (opts[listenerName]) {
                listeners[eventName] = opts[listenerName];
            }
        }
        console.log('listeners', listeners);

        // Create global function for playerReady that stores data,
        // adds listeners, and then runs the playerready callback 
        // that was passed in the options, if there is one.
        var fnName = getFunctionName('playerReady');
        var extraPlayerready = opts.flashvars.playerready;
        window[fnName] = function (obj) {
            console.log(fnName + '()', arguments);
            // Store player object (DOM node) in data() of jQuery object
            var data = {
                obj: $('#' + id)[0],
                duration: null,
                item: 0,
                state: 'IDLE',
                position: 0,
                seek: false, // queued seek position
                volume: null
            };
            $this.data(pluginName, data);
            var eventName;
            for (eventName in listeners) {
                $this[pluginName]('addListener', eventName, listeners[eventName]);
            }
            $this.addClass(pluginName); // to signal it's finished
            if (extraPlayerready) {
                extraPlayerready(obj);
            }
        };
        opts.flashvars.playerready = fnName;
        $this.empty().flash( {
            swf: opts.swf,
            id: id,
            name: id,
            height: opts.height,
            width: opts.width,
            wmode: opts.wmode,
            params: {
                allowfullscreen: 'false',
                allowscriptaccess: 'always',
                enablejs: 'true',
                flashvars: opts.flashvars
            }
        } );
        return this;
    } );
};

$.extend($.fn[pluginName], {
    defaults: {
        flashvars: {},
        height: 240,
        width: 320,
        id: pluginName,
        swf: 'player.swf',
        wmode: 'opaque'
    },

    set: function (data, property, value) {
        data[property] = value;
    },

    get: function (data, property) {
        return data[property];
    },

    item: function (data, itemNumber) {
        itemNumber = parseInt(itemNumber, 10);
        console.log('jwPlayer.item', itemNumber);
        data.obj.sendEvent('ITEM', itemNumber);
        return this;
    },

    load: function(data, filename) {
        console.log('jwPlayer.load: setting filename to ', filename);
        data.obj.sendEvent('LOAD', filename);
        return this;
    },

    mute: function (data) {
        console.log('jwPlayer.mute');
        data.obj.sendEvent('MUTE');
        return this;
    },

    next: function (data) {
        console.log('jwPlayer.next');
        data.obj.sendEvent('NEXT');
        return this;
    },

    pause: function (data) {
        console.log('jwPlayer.pause');
        data.obj.sendEvent('PLAY', 'false');
        return this;
    },

    play: function (data) {
        console.log('jwPlayer.play');
        data.obj.sendEvent('PLAY', 'true');
        return this;
    },

    resume: function (data) { // same as play
        console.log('jwPlayer.resume');
        data.obj.sendEvent('PLAY', 'true');
        return this;
    },

    start: function (data) { // same as play
        console.log('jwPlayer.start');
        data.obj.sendEvent('PLAY', 'true');
        return this;
    },

    togglePlay: function (data) {
        console.log('jwPlayer.togglePlay');
        data.obj.sendEvent('PLAY');
        return this;
    },

    prev: function (data) {
        console.log('jwPlayer.prev');
        data.obj.sendEvent('PREV');
        return this;
    },

    redraw: function (data) {
        console.log('jwPlayer.redraw');
        data.obj.sendEvent('REDRAW');
        return this;
    },

    seek: function (data, position) {
        var state;
        console.log('jwPlayer.seek', position);
        position = parseFloat(position);
        if (!position) {
            position = 0.001; // weird bug when seeking to 0
        }
        state = this[pluginName]('get', 'state');
        console.log('state', state);
        if (state == 'PLAYING' || state == 'PAUSED') {
            data.obj.sendEvent('SEEK', position);
            data.seek = false;
        }
        else {
            if (state == 'IDLE') {
                // Play and pause to get media loading
                data.obj.sendEvent('PLAY', 'true');
                data.obj.sendEvent('PLAY', 'false');
            }
            data.seek = position;
        }
        return this;
    },

    stop: function (data) {
        console.log('jwPlayer.stop');
        data.obj.sendEvent('STOP');
        return this;
    },

    volume: function (data, volume) {
        volume = parseInt(volume, 10);
        data.obj.sendEvent('VOLUME', volume);
        return this;
    },

    getConfig: function (data, property) {
        var config = data.obj.getConfig();
        return property ? config[property] : config;
    },

    getPlaylist: function (data, itemNumber) {
        var playlist = data.obj.getPlaylist();
        return itemNumber || itemNumber === 0 ? playlist[itemNumber] : playlist;
    },

    addListener: function (data, eventName, callback) {
        console.log('jwPlayer.addListener', eventName, callback);
        var fnName,
            method = 'add' + eventType[eventName] + 'Listener';
        if ($.isFunction(callback)) {
            fnName = getFunctionName(eventName.toLowerCase() + 'Listener');
            window[fnName] = callback;
            callback = fnName;
        }
        return data.obj[method](eventName, callback);
    },

    destroy: function () {
        console.log('jwPlayer.destroy');
        $(this).removeData(pluginName).empty();
    }

});

})(jQuery);

