/*! Viocorp Enhanced Media Player
 * Created by: Sugendran Ganess
 */

/// TODO:
 /// Group List object

var Vio = (function() {
    var UNDEF = "undefined",
	    win = window,
	    doc = document;

    function getElement(o) { return o.constructor == String ? doc.getElementById(o) : o; }
    function createElement(tagname, classname, styles) { 
        var tag = doc.createElement(tagname); 
        if(typeof(classname) != UNDEF){
            if(classname != null && classname != ""){
                tag.className = classname;
            }
            if(typeof(styles) != UNDEF){
                for(var a in styles){
                    if(typeof(tag.style[a]) != UNDEF){
                        tag.style[a] = styles[a];
                    }
                }
            }
        }
        return tag;
    }
    function createText(o) { return doc.createTextNode(o); }
    
    function emptyElement(node) { while (node.hasChildNodes()) {node.removeChild(node.firstChild);} }

    function getObject(o) {
        var n = o.getElementsByTagName("object");
        if (n.length > 0) {
            return n[0];
        }
        return null;
    }
    function log(o) {
        if (typeof (window.console) != UNDEF && typeof (window.console.log) != UNDEF) {
            console.log(o);
        }
    }
    /// Browser detection
    var browser = (function() {
        var ua = navigator.userAgent.toLowerCase();
        return {
            usesAttachEvent: (typeof (doc.attachEvent) != UNDEF),
            usesEventListener: (typeof (doc.addEventListener) != UNDEF),
            webkit: (/webkit/.test(ua)),
            msie: (ie = ! +"\v1") // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
        }
    })();

    function GetScriptTag() { // magic!
        var scripts = document.getElementsByTagName("script");
        return scripts[scripts.length - 1];
    }

    function init() {
        ///<summary>This is the init function that is called when the object has loaded.</summary>
    }

    /// Inspired by the swfobject and jQuery	
    var isReady = false,
    readyStack = new Array();
    function DoReady() {
        if(typeof(Vio) == UNDEF){
            setTimeout(arguments.callee,10);
        }else{        
            if (!isReady) { /// only call this once
                isReady = true;
                init();
                for (var i = 0; i < readyStack.length; i++) {
                    try{
                        readyStack[i]();
                    }catch(ex){
                        log(ex);
                    }
                }
                /// Trigger Render Events
                Vio.Event.Trigger("Render");
            }
        }
    }
    function OnReady(fn) {
        if (isReady) {
            try{
                fn();
            }catch(ex){
                log(ex);
            }
        } else {
            readyStack.push(fn);
        }
    }
    
    /// FROM SwfObject - based on - http://brothercake.com/site/resources/scripts/onload/
	function addLoadEvent(fn) {
		if (win.addEventListener) {
			win.addEventListener("load", fn, false);
		}
		else if (win.attachEvent) {
			win.attachEvent("onload", fn);
		}
		else if (typeof win.onload == "function") {
			var fnOld = win.onload;
			win.onload = function() {
				fnOld();
				fn();
			};
		}
		else {
			win.onload = fn;
		}
	}
    
    /// DOM Ready Checker
    (function() {
        if ( typeof(doc.readyState) != UNDEF && doc.readyState == "complete") {
            // function is fired after onload, e.g. when script is inserted dynamically 
            DoReady();
        }else if (!isReady) {
            if (doc.addEventListener) {
                doc.addEventListener("DOMContentLoaded", function(){  
                    doc.removeEventListener( "DOMContentLoaded", arguments.callee, false );
                    DoReady();
                }, false);
            }else if (document.attachEvent) {
                doc.attachEvent("onreadystatechange", function() {
                    if (doc.readyState === "complete") {
                        doc.detachEvent("onreadystatechange", arguments.callee);
                        DoReady();
                    }
                });
                if (document.documentElement.doScroll && win == top) { // if not inside an iframe
                    (function() {
                        if (!isReady) {
                            try {
                                doc.documentElement.doScroll("left");
                            }
                            catch (e) {
                                return setTimeout(arguments.callee, 20);
                            }
                            DoReady();
                        }
                    })();
                }
            }
            
            addLoadEvent(DoReady);
        }
    })();


    function ObjArray(){
        this.length = 0;
    }
    
    /// because msie6 does not play fair
    (function(){
        var methods = ['push', 'pop', 'shift', 'unshift', 'slice', 'splice', 'join', 'sort'];
        for ( var i = 0; i < methods.length; i++ ) 
            (function(name){
                    ObjArray.prototype[ name ] = function(){
                            return Array.prototype[ name ].apply( this, arguments );
                        };
            })(methods[i]);
    })();

    return {
        /// $ge = document.getElementById
        $ge: getElement,
        /// $go = find the object tag in the element
        $go: getObject,
        /// $ce = document.createElement
        $ce: createElement,
        /// $ct = document.createTextNode
        $ct: createText,
        // $ee = emptyElement
        $ee: emptyElement,
        // An arra like object
        ObjArray : ObjArray,

        Extend: function Extend(t, o, d) {
            if (typeof (o) == UNDEF) {
                o = t;
                t = Vio;
            }
            if (typeof (d) == UNDEF) {
                d = false;
            }
            for (var a in o) {
                if (d === true && typeof (t[a]) != UNDEF && t[a].constructor == Object) {
                    Extend(t[a], o[a], true);
                } else {
                    t[a] = o[a];
                }
            }
            return t;
        },
        OnReady: OnReady,
        Log: log,
        Rand: function() { return Math.floor(Math.random() * 10000) + Math.floor(Math.random() * 100); },
        Browser: browser,
        GetScriptTag: GetScriptTag,
        Config: {} // unused?
    }
})();

Vio.OnReady(function(){ VioLoader.Run(); });
Vio.Extend(Vio,{
        Event : (function(){
            /// <summary>The internal event stack that will drive all functionality</summary>
            /// <remarks>This can be replaced for sites that use a known javascript framework, this way we can minimise the embed</remarks>
            var UNDEF = "undefined", eventStack = new Array();
            function EvtCallback(target, fn, data){
                ///<summary>Callback event object</summary>
                this.target = target;
                this.callback = fn;
                this.data = data;
            }
            function Evt(evtName){ 
                ///<summary>Event object</summary>
                this.Name = evtName;
                this.callbacks = new Array();
            }
            
            function findEvent(evtName){
                for(var i=0;i<eventStack.length;i++){
                    if(eventStack[i].Name == evtName){
                        return eventStack[i];
                    }
                }
            }
            
            function removeCallbacks(evt, target, fn){
                var i = 0;
                while(i < evt.callbacks.length){
                    if( evt.callbacks[i].target == target && ( (fn == true) || (evt.callbacks[i].callback == fn) )  ){
                        evt.callbacks.splice(i,1);
                    }else{
                        i++;
                    }
                }
            }
            
            return {
                Bind : function(target, evtName, callback, data){
                    var evt = findEvent(evtName);
                    if(evt == null){
                        evt = new Evt(evtName);
                        eventStack.push(evt);
                    }
                    evt.callbacks.push(new EvtCallback(target, callback, data || { }));
                },
                Unbind : function(target, evtName, callback){
                    var evt = findEvent(evtName);
                    if(evt != null){
                        removeCallbacks(evt, target, typeof(callback) == UNDEF ? true : callback);
                    }
                },
                Trigger : function(evtName, val){
                    var evt = findEvent(evtName);
                    if(evt != null){
                        for(var i = 0;i<evt.callbacks.length;i++){
                            with(evt.callbacks[i]){
                                try{
                                    var r = callback.call(target, { value : val || "", data : data });
                                    if(typeof(r) != UNDEF && r == false){ 
                                        break;
                                    }
                                }catch(ex){
                                    Vio.Log(ex);
                                }
                            }
                        }
                    }
                }
            }
        })()
});
/// A cut back version of json2.js from json.org
/// - It's been modified to not change any native object prototypes
/// -- sugendran
// TODO: Cut this back and mesh it into the Vio.Ajax.js file as that's the only place it's used
Vio.Extend(
(function () {

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    function nativeVal(o){
        if(o.constructor == Date){
            return isFinite(o.valueOf()) ?
                   o.getUTCFullYear()   + '-' +
                 f(o.getUTCMonth() + 1) + '-' +
                 f(o.getUTCDate())      + 'T' +
                 f(o.getUTCHours())     + ':' +
                 f(o.getUTCMinutes())   + ':' +
                 f(o.getUTCSeconds())   + 'Z' : null;
        }else{
            return o.valueOf();
        }
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };


    function quote(string) {
        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }


    function str(key, holder) {
        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            partial,
            value = holder[key];
            
        if (value && typeof value === 'object') { value = nativeVal(value); }

        switch (typeof value) {
            case 'string':
                return quote(value);
            case 'number':
                return isFinite(value) ? String(value) : 'null';
            case 'boolean':
            case 'null':
                return String(value);
            case 'object':
                if (!value) {
                    return 'null';
                }
                partial = [];
                if (Object.prototype.toString.apply(value) === '[object Array]') {
                    for (i = 0; i < value.length; i++) {
                        partial[i] = str(i, value) || 'null';
                    }
                    v = partial.length === 0 ? '[]' : '[' + partial.join(',') + ']';
                    return v;
                }
                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + ':' + v);
                        }
                    }
                }
                v = partial.length === 0 ? '{}' : '{' + partial.join(',') + '}';
                return v;
        }
    }

    return {
        toJSON : function (value) {
            return str('', {'': value});
        }
    }
})()
);
Vio.Extend(
    (function() {

        function formatDate(date, format) {
            var longMonths = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
                month = date.getMonth() + 1,
                year = date.getFullYear(),
                hours = date.getHours();

            function f(n) { return n < 10 ? '0' + n : n; }
            function r(regex, val) { format = format.replace(regex, val); }
            function s(o) { return o.toString(); }

            /// replace any year items
            r(/y{4}/, year);
            r(/yy/, s(year).substr(2, 2));

            /// replace any dates
            r(/dd/, f(date.getDate()));

            /// replace the hours for 24 hour time
            if (format.indexOf("HH") > -1) {
                r(/HH/, f(hours));
            }

            /// replace the hours for 12 hour time
            if (format.indexOf("hh") > -1) {
                r(/hh/, f(hours > 12 ? hours - 12 : hours == 0 ? 12 : hours));
            }

            /// replace the minutes
            r(/mm/, f(date.getMinutes()));

            /// replace the seconds
            r(/ss/, f(date.getSeconds()));

            /// replace the t for am/pm
            if (format.indexOf("t") > -1) {
                r(/t/, (hours > 11) ? "pm" : "am");
            }

            /// now replace the months
            r(/M{4}/, longMonths[month - 1]);
            r(/MMM/, longMonths[month - 1].substr(0, 3));
            r(/MM/, f(month));

            return format;

        }

        return { FormatDate: formatDate }
    })());
/// Adds the AJAX functionality

Vio.Extend((function() {
    var UNDEF = "undefined",
    log = Vio.Log;
    function getReq(url, data, fn, err) {
        var xhr = (window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest());
        var params = "";
        for (var a in data) {
            if (params.length > 0) {
                params += "&";
            }
            params += (a + "=" + Vio.toJSON(data[a]));
        }
        xhr.open("GET", url + (url.match(/\?/) ? "&" : "?") + params, true);
        xhr.onreadystatechange = function(evt) {
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    try {
                        var resp = eval("(" + xhr.responseText + ")");
                        if (resp && resp.d) {
                            if (resp.d.Error.length > 0) {
                                err(resp.d.Error[0].Message);
                            } else {
                                fn(resp.d.Item, resp.d.ItemInfo);
                            }
                        } else {
                            err("An invalid response was recieved");
                        }
                    } catch (e) {
                        log(e);
                        err("An error occured parsing the result");
                    }
                } else {
                    err("Error loading URL");
                }
            }
        }
        xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        xhr.send(null);
    }

    return {
        Ajax: function(url, data, callback, err) {
            /// <param name="url">The URL to load</param>
            /// <param name="data">A javascript object with any data that we want to load</param>
            /// <param name="callback">
            ///     The function to call on a successful response. The callback will recieve two variables, 
            ///     the first is the "Item" object from the response and the second is the "ItemInfo" object
            /// </param>
            /// <param name="err">The function to call on an error. The function will recieve an error message</param>
            getReq(url, data || {}, callback || log, err || log);
        }
    }
})());
/// Handles the media objects
Vio.Extend(
    (function () {
    	var UNDEF = "undefined";

    	function setParams(target, params) {
    		for (var a in params) {
    			if (typeof (target[a]) != UNDEF && (target[a] == null || target[a].constructor != Array)) {
    				target[a] = params[a];
    			}
    		}
    	}

    	/// Thumbnails
    	function Thumbnail(o) {
    		if (typeof (o) != UNDEF) {
    			setParams(this, o);
    		}
    	}

    	Vio.Extend(Thumbnail.prototype, {
    		Width: 0,
    		Height: 0,
    		Path: ""
    	});

    	/// MediaUrl object
    	function MediaUrl(o) {
    		if (typeof (o) != UNDEF) {
    			setParams(this, o);
    			var extRegex = /(\.)([A-Za-z0-9]){3,4}(?=\?|$)/;
    			var protocolRegex = /^[(A-Za-z)]{4}(?=:\/\/)/;
    			var match = extRegex.exec(this.Url) || protocolRegex.exec(this.Url);
    			this.Extension = match[0].replace(/(^\.)/, "").toLowerCase();
    			this.Quality = this.Quality.toLowerCase();
    		}
    	}

    	Vio.Extend(MediaUrl.prototype, {
    		Url: null,
    		Quality: null,
    		Duration: 0,
    		MediaType: null,
    		Extension: null
    	});

    	/// MediaBase object
    	function MediaBase(o) {
    		if (typeof (o) != UNDEF) {
    			setParams(this, o);
    			this.Thumbnails = new Array();
    			this.Keywords = new Array();
    			this.Urls = new Array();

    			var dateRegex = new RegExp("\/", "g");
    			if (dateRegex.test(this.DisplayTime)) {// .NET Awesomeness.
    				this.DisplayTime = eval("(new " + this.DisplayTime.replace(dateRegex, "") + ")");
    			}
    			this.LoadUrls(o.MediaUrls);
    			for (var i = 0; i < o.KeyWords.length; i++) {
    				this.Keywords.push(o.KeyWords[i]);
    			}
    			for (var i = 0; i < o.Thumbnails.length; i++) {
    				this.Thumbnails.push(new Thumbnail(o.Thumbnails[i]));
    			}
    		}
    	}

    	Vio.Extend(MediaBase.prototype, {
    		MediaId: null,
    		DisplayTime: "",
    		MediaTitle: "",
    		MediaDescription: "",
    		MediaType: "",
    		AuthorName: "",
    		Urls: [],
    		Thumbnails: [],
    		Keywords: [],

    		IsMatch: function (regEx) {
    			if (regEx.constructor == String) {
    				regEx = new RegExp(regEx, "igm");
    			}

    			if ((regEx.test(this.MediaTitle)) || (regEx.test(this.MediaDescription))) {
    				return true;
    			} else {
    				for (var i = 0; i < this.Keywords.length; i++) {
    					if (regEx.test(this.Keywords[i])) {
    						return true;
    					}
    				}
    			}
    			return false;
    		},

    		/// URLs
    		LoadUrls: function (mediaUrls) {
    			if (mediaUrls.length > 0) {
    				for (var i = 0; i < mediaUrls.length; i++) {
    					this.Urls.push(new MediaUrl(mediaUrls[i]));
    				}
    			}
    		},
    		HasUrl: function (extension) {
    			for (var i = 0; i < this.Urls.length; i++) {
    				if (this.Urls[i].Extension == extension) {
    					return true;
    				}
    			}
    			return false;
    		},
    		FindUrl: function (extension, quality) {
    			extension = extension.toLowerCase();
    			quality = quality.toLowerCase();
    			var j = -1; //highest match on extension
    			for (var i = 0; i < this.Urls.length; i++) {
    				if (this.Urls[i].Extension == extension) {
    					if (this.Urls[i].Quality == quality) {
    						return this.Urls[i];
    					} else {
    						j = Math.max(j, i);
    					}
    				}
    			}
    			if (j > -1) { // fallback to another one with the same extension
    				return this.Urls[j];
    			}
    			return null;
    		},

    		/// THUMBNAILS
    		FindThumbnail: function (width) {
    			if (this.Thumbnails.length == 0) {
    				return null;
    			}
    			var tlist = [];
    			for (var i = 0; i < this.Thumbnails.length; i++) {
    				if (this.Thumbnails[i].Width == width) {
    					return this.Thumbnails[i];
    				}
    				if (this.Thumbnails[i].Width > width) {
    					tlist.push(this.Thumbnails[i]);
    				}
    			}
    			if (tlist.length == 0) {
    				tlist = this.Thumbnails;
    			}
    			var mi = 0;
    			var minx = tlist[0].Width;
    			for (var i = 0; i < tlist.length; i++) {
    				if (tlist[0].Width < minx) {
    					minx = tlist[0].Width;
    					mi = i;
    				}
    			}
    			return tlist[mi];
    		}

    	});

    	/// Media List object
    	function Media() { }
    	Media.prototype = new Vio.ObjArray();
    	Vio.Extend(Media.prototype, {
    		Find: function (mediaId) {
    			for (var i = 0; i < this.length; i++) {
    				if (this[i].MediaId == mediaId) {
    					return this[i];
    				}
    			}
    			return null;
    		},
    		Add: function (mediaBaseObject) {
    			var mb = this.Find(mediaBaseObject.MediaId);
    			if (mb == null) {
    				mb = new MediaBase(mediaBaseObject);
    				this.push(mb);
    			} else {
    				mb.LoadUrls(mediaBaseObject.MediaUrls);
    			}
    			return mb;
    		},
    		AddRange: function (mediaBaseObjects) {
    			for (var i = 0; i < mediaBaseObjects.length; i++) {
    				this.Add(mediaBaseObjects[i]);
    			}
    		},
    		Load: function (mediaId, callback) {
    			Vio.Ajax(Vio.BaseURL + "content.asmx/MediaInfoByMethod",
                    { mediaId: mediaId, streamingMethod: "AkamaiProgressiveStream" },
                    function (respItem, respItemInfo) {
                    	Vio.Media.Add(respItem[0]);
                    	if (typeof (callback) == "function") callback();
                    }
                );
    		},
    		LoadP: function (mediaId, callback) {
    			var head = document.getElementsByTagName("head")[0];
    			var script = document.createElement("script");
    			script.setAttribute("type", "text/javascript");
    			script.setAttribute("src", Vio.BaseURL + "JSONP.axd?a=media&id=" + mediaId);
    			head.appendChild(script);
    			if (typeof (callback) == "function") {
    				var timedout = false, timeout = setTimeout(function () { timedout = true; }, 30000);
    				(function () {
    					var mb = Vio.Media.Find(mediaId);
    					if (mb != null && mb.Urls.length > 0) {
    						clearTimeout(timeout);
    						timedout = true;
    						callback();
    					} else {
    						if (!timedout) {
    							setTimeout(arguments.callee, 10);
    						}
    					}
    				})()
    			}

    		}
    	});



    	return {
    		Media: new Media()
    	}
    })()
);

Vio.Extend((function(){
    var UNDEF = "undefined";
    
    function setParams(target, params){
        for(var a in params){
            if(typeof(target[a]) != UNDEF && (target[a] == null || target[a].constructor != Array)){
                target[a] = params[a];
            }
        }
    }
    
    function Group(o){
        if(typeof(o) != UNDEF){
            setParams(this, o);
        
            this.SubGroups = new Array();
            this.MediaBases = new Array();
        
            if(o.MediaBases && o.MediaBases.length > 0){
                for(var i=0;i<o.MediaBases.length;i++){
                    this.MediaBases.push(Vio.Media.Add(o.MediaBases[i]));
                }
            }
            if(o.SubGroups && o.SubGroups.length > 0){
                for(var i=0;i<o.SubGroups.length;i++){
                    var newGroup = new Group(o.SubGroups[i])
                    this.SubGroups.push(newGroup);
                    Vio.Groups.push(newGroup);
                }
            }
        }
    }
    Vio.Extend(Group.prototype, {
        Id : "",
        Name : "",
        Description : "",
        SortName : "",
        SortDirection : "",
        SubGroups : new Array(),
        MediaBases : new Array(),
        Filter : function(regEx){
            if(regEx.constructor == String){
                regEx = new RegExp(regEx, "igm");
            }
            if(regEx.source == ""){
                return this.MediaBases;
            }else{
                var ret = [];
                for(var i = 0;i<this.MediaBases.length;i++){
                    if(this.MediaBases[i].IsMatch(regEx)){
                        ret.push(this.MediaBases[i]);
                    }
                }
                return ret;
            }
        },
        Sort : function(sortName, sortDirection){
            if(this.SortName != sortName || this.SortDirection != sortDirection){
                var data = (sortName == "date" ? "DisplayTime" : "MediaTitle");
                var delta = (sortDirection == "asc" ? 1 : -1);
                function sortFn(a,b){ 
                    return (a[data] < b[data]) ? (-1 * delta) : ((a[data] > b[data]) ? (1 * delta) : 0);
                }
                this.MediaBases.sort(sortFn);
                this.SortName = sortName;
                this.SortDirection = sortDirection;
            }
        }
    });

    function Groups(){ };
    Groups.prototype = new Vio.ObjArray();
    Vio.Extend(Groups.prototype, {
        Find : function(groupId){
            for(var i=0;i<this.length;i++){
                if(this[i].Id == groupId){
                    return this[i];
                }
            }
            return null;
        },
        Load : function(groupId, callback){
            Vio.Ajax(Vio.BaseURL + "content.asmx/MediaByGroup",
                { groupId: groupId },
                function(respItem, respItemInfo) {
                    Vio.Groups.Add(respItem);
                    if (typeof (callback) == "function") callback();
                }
            );
        },
        LoadP: function(groupId, callback){
            /// if it exists then reload it
            this.Remove(groupId);
            var head = document.getElementsByTagName("head")[0];
            var script = document.createElement("script");
            script.setAttribute("type","text/javascript");
            script.setAttribute("src", Vio.BaseURL + "JSONP.axd?a=group&id=" + groupId);
            head.appendChild(script);
            if(typeof(callback) == "function"){
                var timedout = false, timeout = setTimeout(function(){timedout = true;}, 30000);
                (function(){
                    if(Vio.Groups.Find(groupId) == null){
                        if(!timedout){
                            setTimeout(arguments.callee, 10);
                        }
                    }else{
                        clearTimeout(timeout);
                        timedout = true;
                        callback();
                    }
                })()
            }
            
        },
        Remove : function(groupId){
            for(var i=0;i<this.length;i++){
                if(this[i].Id == groupId){
                    this.splice(i,1);
                    return;
                }
            }
        },
        Add : function(groupObject){
            // if it exists then we're reloading it
            this.Remove(groupObject.Id);
            // load the group into the list
            this.push(new Group(groupObject));
        }
    });
    
    return {
        Groups : new Groups()
    }
    
})());
Vio.Extend({
    Player: (function() {
        var UNDEF = "undefined",
            PX = "px",
            MediaPlayers = {},
            getElement = Vio.$ge,
            createElement = Vio.$ce,
            createText = Vio.$ct,
            emptyElement = Vio.$ee,
            targets = [];

        function sanity(obj, key, fallback) { return (typeof (obj[key]) == UNDEF) ? fallback : obj[key]; }
        
        var PlayerTarget = function(elem) {
            if (elem.constructor == String) {
                elem = getElement(elem);
            } else if (elem.id == "") {
                elem.id = "VioTarget_" + Math.floor((Math.random() * 100)) + "_" + ((new Date()).valueOf());
            }
            this.Id = elem.id;
            this.Element = elem;
            this.Options = {
                embedPlayer: {
                    showSplash: false,
                    splashImage: "",
                    showChooser: false,
                    showChooserWhenPlaying: false,
                    playerFormat: "",
                    playerQuality: "",
                    playerWidth: 400,
                    playerHeight: 224
                },
                playlist: {
                    playlistHeight: 224,
                    playlistWidth: 200,

                    /* defaults if not found in database */
                    sort_order: "name",
                    sort_direction: "asc" // asc or desc
                },
                mediainfo : { },
                bookmarks : [ ]
            };
        }

        Vio.Extend(PlayerTarget.prototype, {
            Id: null,
            Element: null,
            PlayerElement: null,
            PlayerOptions: null,
            MediaInfo : null,
            PlaylistElement: null,
            PlaylistControl: null,
            Options: {}
        });

        /// Called from the player layout
        /// The param.value for the event is the target that we're rendering
        function Render(o) {
            var target = o.value;

            var embedPlayer = target.Options.embedPlayer;
            var mediaBase = Vio.Media.Find(embedPlayer.mediaId);

            if (mediaBase) {
                setTimeout(function() { Vio.Event.Trigger("RenderMediaInfo", target); }, 10);
                setTimeout(function() { Vio.Event.Trigger("RenderPlayerOptions", target); }, 10);

                if (embedPlayer.showSplash) {
                    emptyElement(target.PlayerElement);
                    /// We have to show the splash image
                    var thumbUrl = embedPlayer.splashImage;
                    if (thumbUrl == "") {
                        var thumb = mediaBase.FindThumbnail(embedPlayer.playerWidth);
                        if (thumb != null) {
                            thumbUrl = thumb.Path;
                        }
                    }
                    /// Image
                    var img = createElement("img", null, { width: embedPlayer.playerWidth + PX, height: embedPlayer.playerHeight + PX});
                    img.src = thumbUrl;

                    /// Link
                    var a = createElement("a");
                    a.href = "javascript:void(0);";
                    a.onclick = function(){Vio.Player.Render(target.Id); return false; }; 
                    a.appendChild(img);

                    target.PlayerElement.appendChild(a);

                    target.Options.embedPlayer.showSplash = false;
                } else {
                    /// Render a player or chooser
                    if (embedPlayer.showChooser
                            || ((embedPlayer.playerFormat || "") == "")
                            || ((embedPlayer.playerQuality || "") == "")) {
                        emptyElement(target.PlayerElement);
                        target.PlayerElement.style.width = embedPlayer.playerWidth + PX;
                        target.PlayerElement.style.height = embedPlayer.playerHeight + PX;

                        var thumb = mediaBase.FindThumbnail(embedPlayer.playerWidth);
                        if (embedPlayer.splashImage != "" || thumb != null) {
                            var thumbPath = (embedPlayer.splashImage != "") ? embedPlayer.splashImage : thumb.Path;
                            target.PlayerElement.style.backgroundImage = "url(" + thumbPath + ")";
                            target.PlayerElement.style.backgroundPosition = "50% 50%";
                            target.PlayerElement.style.backgroundRepeat = "no-repeat";
                        } else {
                            target.PlayerElement.style.backgroundImage = "none";
                        }

                        /// Available formats/qualities are taken from the first media item if the current one is useless
                        if(mediaBase.Urls.length == 0){
                            for(var i=0;i<Vio.Media.length;i++){
                                if(Vio.Media[i].Urls.length > 0){
                                    mediaBase = Vio.Media[i];
                                    break;
                                }
                            }
                        }
                        
                        var selFormat = createElement("select");
                        selFormat.id = target.Id + "_mediaPlayer";
                        var selQuality = createElement("select");
                        selQuality.id = target.Id + "_mediaQuality";

                        function addOpt(sel, opt) {
                            try {
                                sel.add(opt, null);
                            } catch (e) {
                                sel.add(opt);
                            }
                        }
//                        var qtemp = {};

                        for (var a in MediaPlayers) {
                            for (var i = 0; i < mediaBase.Urls.length; i++) {
                                var e = mediaBase.Urls[i].Extension;
                                if (MediaPlayers[a].CanPlay(mediaBase.Urls[i].Extension)) {
                                    var opt = new Option(MediaPlayers[a].Name, a);
                                    addOpt(selFormat, opt);
                                    break;
                                }
                            }
                        }
                        var qtemp = [];
                        function FQ(s) { 
                            for (var i = 0; i < qtemp.length; i++) { 
                                if (qtemp[i] == s) 
                                    return true; 
                            } 
                            return false; 
                        }
                        for (var i = 0; i < mediaBase.Urls.length; i++) {
                            var q = mediaBase.Urls[i].Quality;
                            if (q == "undefined") continue;
                            if (!FQ(q)) {
                                qtemp.push(q);
                            }
                        }
                        var qsort = { "hd": 4, "high": 3, "medium": 2, "low": 1 };
                        qtemp.sort(function(a, b) {
                            return (qsort[a] || 0) > (qsort[b] || 0);
                        });
                        
                        for (var i = 0; i < qtemp.length; i++) {
                            var opt = new Option((qtemp[i] == "hd") ? "HD" : (qtemp[i].substr(0,1).toUpperCase() + qtemp[i].substr(1)), qtemp[i]);
                            opt.selected = (qtemp.length - 1) == i;
                            addOpt(selQuality, opt);
                        }

                        /// Render chooser
                        /// Outer div for background and position
                        var divOuter = createElement("div", "player-chooser");
                        
                        var divMiddle = createElement("div", "player-chooser-spacer");
                        divOuter.appendChild(divMiddle);
                        
                        /// Inner div for background and position
                        var divInner = createElement("div", "player-chooser-box");
                        divMiddle.appendChild(divInner);
                        /// Title holder
                        var divTitle = createElement("div", "title");
                        divTitle.appendChild(createText("Media Player Options"));
                        divInner.appendChild(divTitle);
                        /// Choices
                        var divChoices = createElement("div", "choices vio-clearfix");
                        divInner.appendChild(divChoices);
                        /// Format chooser
                        var divFormat = createElement("div", "format");
                        divFormat.appendChild(createText("Format"));
                        divFormat.appendChild(selFormat);
                        divChoices.appendChild(divFormat);
                        /// Quality chooser
                        var divQuality = createElement("div", "quality");
                        divQuality.appendChild(createText("Quality"));
                        divQuality.appendChild(selQuality);
                        divChoices.appendChild(divQuality);
                        /// Save button
                        var divSave = createElement("div","save-button");

                        var btnSave = createElement("input");
                        btnSave.onclick = function(){ Vio.Player.Choose(target.Id); return false; };
                        btnSave.type = "button";
                        btnSave.setAttribute("value", "Save");
                        divSave.appendChild(btnSave);
                        divInner.appendChild(divSave);

                        target.PlayerElement.appendChild(divOuter);
                    } else {
                        if (embedPlayer.playerFormat == "auto") {
                            target.Options.embedPlayer.playerFormat = (function() {
                                var mb = Vio.Media[0]; //check the first mediabase object to see what we're up against
                                for (var mp in MediaPlayers) {
                                    for (var i = 0; i < mb.Urls.length; i++) {
                                        if (MediaPlayers[mp].CanPlay(mb.Urls[i].Extension)) {
                                            return mp;
                                        }
                                    }
                                }
                                return null;
                            })();
                            Render({ value: target });
                        } else {
                            MediaPlayers[embedPlayer.playerFormat].Render(target);
                        }
                    }
                }
            } 
        }

        function RenderOptions(o) {
            var target = o.value,
                ep = sanity(target.Options, "embedPlayer", {}),
                bk = sanity(target.Options, "bookmarks", []);
            if(target.PlayerOptions && (ep.showChooserWhenPlaying || bk.length > 0)){
                emptyElement(target.PlayerOptions);
                if(bk.length > 0){
                    var bkUl = createElement("ul","bookmarks");
                    for(var i=0;i<bk.length;i++){
                        var bkLi = createElement("li");
                        var bkA = createElement("a");
                        var bkImg = createElement("img");
                        bkA.href = bk[i].Url.replace(/\{0\}/i,location.toString()).replace(/\{1\}/i,document.title);
                        bkA.title = bkImg.tooltip = bk[i].Name;
                        bkImg.src = bk[i].IconUrl;
                        bkA.appendChild(bkImg);
                        bkLi.appendChild(bkA);
                        bkUl.appendChild(bkLi);
                    }
                    target.PlayerOptions.appendChild(bkUl);
                }
                
                if(ep.showChooserWhenPlaying){
                    var optLink = createElement("a","player-option");
                    optLink.appendChild(createText("Player options"));
                    optLink.href = "javascript:void(0);";
                    optLink.onclick = function(){ Vio.Player.ShowOptions(target.Id); };
                    target.PlayerOptions.appendChild(optLink);
                }
            }
        }
        
        function RenderMediaInfo(o){
            var target = o.value,
                pl = sanity(target.Options, "playlist", {}),
                mi = sanity(target.Options, "mediainfo", {}),
                ep = sanity(target.Options, "embedPlayer", {}),
                pr = sanity(target.Options, "player", {}),
                showTitle = sanity(mi,"show_title",true),
                showDesc = sanity(mi,"show_desc",true),
                showDate = sanity(mi, "show_date", false),
                dateFmt = sanity(mi, "date_fmt", "dd MM yy"),
                mediaBase = Vio.Media.Find(ep.mediaId);
            
            if(target.MediaInfo && mediaBase){
                emptyElement(target.MediaInfo);
                                
                if(showTitle){
                    var divTitle = createElement("div", "media-title");
                    divTitle.appendChild(createText(mediaBase.MediaTitle));
                    target.MediaInfo.appendChild(divTitle);
                }
                if(showDesc){
                    var divDesc = createElement("div", "media-description");
                    divDesc.innerHTML = mediaBase.MediaDescription;
                    target.MediaInfo.appendChild(divDesc);
                }
                if(showDate){
                    var divDate = createElement("div", "media-date");
                    divDate.appendChild(createText(Vio.FormatDate(mediaBase.DisplayTime, dateFmt)));
                    target.MediaInfo.appendChild(divDate);
                }
            }
        }

        Vio.Event.Bind(window, "RenderPlayer", Render);
        Vio.Event.Bind(window, "RenderPlayerOptions", RenderOptions);
        Vio.Event.Bind(window, "RenderMediaInfo", RenderMediaInfo);

        return {
            Layouts: {},
            AddTarget: function(playerName, elem, opts) {
                if (typeof (Vio.Player.Layouts[playerName]) != "undefined") {
                    var target = new PlayerTarget(elem);
                    Vio.Extend(target.Options, opts, true);
                    Vio.Player.Layouts[playerName].AddTarget(target);
                }
            },
            NewTarget : function(elem){
                /// <summary>This function is called to add an adhoc player target. That is, a player without a layout</summary>
                var t = new PlayerTarget(elem);
                targets.push(t);
                return t;
            },
            FindTarget: function(id) {
                for(var i=0;i<targets.length;i++){
                    if(targets[i].Id == id){
                        return targets[i];
                    }
                }
                for (var a in Vio.Player.Layouts) {
                    var b = Vio.Player.Layouts[a].FindTarget(id);
                    if (b != null) {
                        return b;
                    }
                }
                return null;
            },
            Render: function(id) {
                var t = Vio.Player.FindTarget(id);
                if (t != null) {
                    setTimeout(function() { Render({ value: t }); }, 10);
                }
            },
            Choose: function(id) {
                var t = Vio.Player.FindTarget(id);
                if (t != null) {
                    var mp = getElement(t.Id + "_mediaPlayer");
                    var mq = getElement(t.Id + "_mediaQuality");
                    t.Options.embedPlayer.playerFormat = mp.options[mp.selectedIndex].value;
                    t.Options.embedPlayer.playerQuality = mq.options[mq.selectedIndex].value;
                    t.Options.embedPlayer.showChooser = false;
                    setTimeout(function() { Vio.Event.Trigger("Render", t); }, 10);
                }
            },
            ShowOptions: function(id){
                var t = Vio.Player.FindTarget(id);
                if (t != null) {
                    t.Options.embedPlayer.playerFormat = "";
                    t.Options.embedPlayer.playerQuality = "";
                    t.Options.embedPlayer.showChooser = false;
                    setTimeout(function() { Vio.Event.Trigger("Render", t); }, 10);
                }
            },
            MediaPlayers: MediaPlayers
        }
    })()
});
Vio.Extend({
    Playlist: (function() {
        var UNDEF = "undefined",
            PX = "px",
            getElement = Vio.$ge,
            createElement = Vio.$ce,
            createText = Vio.$ct,
            emptyElement = Vio.$ee;

        function sanity(obj, key, fallback) { return (typeof (obj[key]) == UNDEF) ? fallback : obj[key]; }

        function Render(o) {
            var target = o.value,
                pl = target.Options.playlist,
                ep = target.Options.embedPlayer,
                pr = target.Options.player,
                group = Vio.Groups.Find(ep.groupId || null),
                mediaId = sanity(ep, "mediaId", ""),
                showTitle = sanity(pl, "show_title", true),
                showDesc = sanity(pl, "show_desc", true),
                showThumbnail = sanity(pl, "show_thumbnail", true),
                showDate = sanity(pl, "show_date", false),
                thumbWidth = sanity(pl, "thumbnail_width", 96),
                thumbHeight = sanity(pl, "thumbnail_height", 54),
                itemHeight = sanity(pl, "item_height", 60),
                itemWidth = sanity(pl, "item_width", 300),
                descCutoff = sanity(pl, "desc_cutoff", -1),
                dateFmt = sanity(pl, "date_fmt", "dd MM yy"),
                filter = sanity(pl, "filter","");

            if(filter.constructor == String){
                filter = new RegExp(filter, "igm");
            }

            //target.PlaylistElement.style.height = sanity(pl, item_height, 60) + "px";
            //target.PlaylistElement.style.width = sanity(pl, item_width, 300) + "px";

            function defaultThumb(t) {
                return t == "Video" ? pr.default_video_thumb : t == "Audio" ? pr.default_audio_thumb : pr.default_image_thumb;
            }
            function trunc(d, l){ 
                if(l < 0 || d.length < l){
                    return d;
                }else{
                    var s = d.substr(0,l);
                    return s.substr(0, s.lastIndexOf(" ")) + " ...";
                    
                }
                return (descCutoff < 0) ? d : d.substr(0, descCutoff);
            }
            
            emptyElement(target.PlaylistElement);
            var altCheck = 1;
            function mouseOver(){ this.className = this.className + " hover"; }
            function mouseOut(){ this.className = this.className.replace(/\shover/,""); }
            function renderCell(mb, divClass) {
                var div = createElement("div");
                divClass = "media-card vio-clearfix " + (divClass.length > 0 ? divClass + " " : "") + mb.MediaType.toLowerCase() + ( (++altCheck % 2) == 0 ? "" : " alt") + (mb.MediaId == mediaId ? " now-playing" : "");
                div.className = divClass;
                div.setAttribute("rel", mb.MediaId);
                div.onmouseover = mouseOver;
                div.onmouseout = mouseOut;

                /// actions
                var a1 = createElement("a");
                var a2 = createElement("a");
                div.onclick = a1.onclick = a2.onclick = function(e){ 
                    if (typeof(e) == UNDEF) { e = window.event; }

                    Vio.Playlist.PlayMedia(target.Id , mb.MediaId); 
                    
                    if (typeof(e.cancelBubble) != UNDEF){
                      e.cancelBubble = true;
                    } else {
                      e.stopPropagation();
                    }
                    
                    return false; 
                };
                a1.href = a2.href = "javascript:void(0);";
                
                /// thumbnails
                if(showThumbnail){
                    a1.style.width = thumbWidth + PX;
                    a1.style.height = thumbHeight + PX;
                    a1.className = "thumbnail";
                    var img = createElement("img");
                    var thumb = mb.FindThumbnail(thumbWidth);
                    if(thumb == null){
                        img.src =  defaultThumb(mb.MediaType); // at this point we have no other info
                        //TODO: onreadystate check for image size
                        img.style.height = thumbHeight + PX;
                        img.style.width = ((thumbHeight / 54) * 96) + PX;
                        if(thumbHeight != 54 || thumbWidth != 96){
                            img.style.marginLeft = (((thumbWidth - ((thumbHeight/54) * 96))/2)) + PX;
                        }
                    }else{
                        img.src = thumb.Path;
                        img.style.height = thumbHeight + PX;
                        img.style.width = ((thumbHeight / thumb.Height) * thumb.Width) + PX;
                        if(thumbHeight != thumb.Height || thumbWidth != thumb.Width){
                            img.style.marginLeft = (((thumbWidth - ((thumbHeight/thumb.Height) * thumb.Width))/2)) + PX;
                        }
                    }
                    a1.appendChild(img);
                    div.appendChild(a1);
                }
                if(showTitle || showDesc || showDate){
                    var dl = createElement("dl");
                    
                    if(showTitle){
                        var dt = createElement("dt");
                        a2.appendChild(createText(mb.MediaTitle));
                        dt.appendChild(a2);
                        dl.appendChild(dt);
                    }
                    if(showDesc){
                        var dd1 = createElement("dd");
                        dd1.innerHTML = (trunc(mb.MediaDescription, descCutoff));
                        dl.appendChild(dd1);
                    }
                    if(showDate){                    
                    var dd2 = createElement("dd");
                    dd2.appendChild(createText(Vio.FormatDate(mb.DisplayTime, dateFmt)));
                    dl.appendChild(dd2);
                    }
                    div.appendChild(dl);
                }
                target.PlaylistElement.appendChild(div);

            }

            if (group) {              
                var mbs = group.Filter(filter);  
                for (var i = 0; i < mbs.length; i++) {
                    renderCell(mbs[i], i == 0 ? "first" : i == (mbs.length -1) ? "last" : "");
                }
            } else{
                var media  = Vio.Media.Find(mediaId);
                if(media != null){
                    renderCell(media, "first");
                }
            }

        }
        
        function renderControl(o){
            var target = o.value,
                pl = target.Options.playlist,
                group = Vio.Groups.Find(target.Options.embedPlayer.groupId || "");
                
            emptyElement(target.PlaylistControl);
            if(group != null){ // sorting only makes sense if we have a group
                var ul = createElement("ul","vio-clearfix");
                
                var li1 = createElement("li");
                li1.appendChild(createText("Sort by:"));
                ul.appendChild(li1);
                
                var li2 = createElement("li");
                if(group.SortName == "name"){
                    li2.className = group.SortDirection;
                }
                var a1 = createElement("a", "sort");
                a1.href = "javascript:void(0);";
                a1.onclick = function(){ Vio.Playlist.SortMedia(target.Id, 'name'); };
                a1.appendChild(createText("Name"));
                li2.appendChild(a1);
                ul.appendChild(li2);
                
                var li3 = createElement("li");
                if(group.SortName == "date"){
                    li3.className = group.SortDirection;
                }
                var a2 = createElement("a","sort");
                a2.href = "javascript:void(0);";
                a2.onclick = function(){ Vio.Playlist.SortMedia(target.Id, 'date'); };
                a2.appendChild(createText("Date"));
                li3.appendChild(a2);
                ul.appendChild(li3);
                
                target.PlaylistControl.appendChild(ul);
            }
        }

        function UpdateNowPlaying(o){;
            var target = o.value, 
                ep = sanity(target.Options, "embedPlayer", { }),
                mediaId = sanity(ep, "mediaId", "");
            if(target.PlaylistElement && mediaId != ""){
                var childs = target.PlaylistElement.childNodes;
                var clsRegex = (/\snow-playing/);
                for(var i=0;i<childs.length;i++){
                    if(childs[i] && childs[i].nodeType == 1){
                        if(clsRegex.test(childs[i].className)){
                            childs[i].className = childs[i].className.replace(clsRegex, "");
                        }
                        if(childs[i].getAttribute("rel") == mediaId){
                            childs[i].className = childs[i].className + " now-playing";
                        }
                    }
                }
            }
        }

        Vio.Event.Bind(window, "RenderPlaylist", Render);
        Vio.Event.Bind(window, "RenderPlaylistControl", renderControl);
        /// The following event is called when the media item has changed and we have to show
        /// an updated media info. We're going to use the same event to update the playlist to
        /// show what is currently playing
        Vio.Event.Bind(window, "RenderMediaInfo", UpdateNowPlaying);

        return {
            PlayMedia: function(targetId, mediaId) {
                var t = Vio.Player.FindTarget(targetId);
                if (t != null) {
                    t.Options.embedPlayer.mediaId = mediaId;
                    setTimeout(function() { Vio.Event.Trigger("RenderPlayer", t); }, 10);
                    //Vio.Player.Render(targetId);
                }
                return true;
            },
            FilterMedia: function(targetId, filter){
                var t = Vio.Player.FindTarget(targetId);
                if (t != null) {
                    t.Options.playlist.filter = filter;
                    setTimeout(function() { Vio.Event.Trigger("RenderPlaylist", t); }, 10);
                }
            },
            SortMedia: function(targetId, sortName){
                var t = Vio.Player.FindTarget(targetId);   
                if(t != null){
                    var g = Vio.Groups.Find(t.Options.embedPlayer.groupId || "");
                    if(g != null){
                        g.Sort(sortName, (sortName == g.SortName) ? (g.SortDirection == "asc" ? "desc" : "asc") : (sortName == "date" ? "desc" : "asc") );
                        setTimeout(function() { Vio.Event.Trigger("RenderPlaylist", t); }, 10);
                        setTimeout(function() { Vio.Event.Trigger("RenderPlaylistControl", t); }, 10);
                    }
                }
            }
        }
    })()
});
/// <summary>
/// Handles the mapping of overridable options.
/// Lazy loads the player core if needed.
/// </summary>
if (typeof (VioLoader) == "undefined") {
    var VioLoader = (function() {
        var UNDEF = "undefined",
            isRun = false,
            LoadStack = new Array();

        function log(o) {
            if (typeof (window.console) != UNDEF && typeof (window.console.log) == "function") {
                console.log(o);
            }
        }

        function checkScriptOptions(opts) {
            var s = document.getElementsByTagName("script"),
                    t = s[s.length - 1],
                    o = eval(t.innerHTML) || {};
            if (typeof (opts.embedPlayer) == UNDEF) { opts.embedPlayer = {}; }
            if (typeof (opts.playlist) == UNDEF) { opts.playlist = {}; }
            /// Datamapping layer to map public overrides to config names
            var embedMap = {
                "PlayerWidth": "playerWidth",
                "PlayerHeight": "playerHeight",
                "ShowSplash": "showSplash",
                "SplashImage": "splashImage",
                "ShowChooser": "showChooser",
                "ShowChooserWhenPlaying": "showChooserWhenPlaying",
                "PlayerFormat": "playerFormat",
                "DefaultExtension": "playerExtension",
                "DefaultQuality": "playerQuality",
                "AutoStart": "autoStart",
                "AutoRewind": "autoRewind"
            },
            playlistMap = {
                "PlaylistWidth": "playlistWidth",
                "PlaylistHeight": "playlistHeight"
            };
            for (var a in o) {
                if (typeof (o[a]) != "function") {
                    if (typeof (embedMap[a]) != UNDEF) {
                        opts.embedPlayer[embedMap[a]] = o[a];
                    } else if (typeof (playlistMap[a]) != UNDEF) {
                        opts.playlist[playlistMap[a]] = o[a];
                    }
                }
            }
            return t;
        }

        /// Lazy load core library here!

        return {
            Fn: function(fn) {
                if (!isRun) {
                    LoadStack.push(fn);
                } else {
                    fn.call(null);
                }
            },
            Add: function(playerName, options) {
                ///<summary>Adds a player for rendering</summary>
                ///<param name="playerName">The name of the layout to be used for rendering. This layout needs to exist in Vio.Player.Layouts</param>
                ///<param name="options">The set of options for the player</param>
                t = checkScriptOptions(options);
                var playerId = /playerid=([0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})/.exec(t.src)[1]
                var css = Vio.BaseURL + "StyleSheet.axd?playerId=" + playerId;
                LoadStack.push(function() {
                    if (typeof (document.createStyleSheet) == "function") {
                        document.createStyleSheet(css);
                    } else {
                        var head = document.getElementsByTagName("head")[0];
                        var style = document.createElement("link");
                        style.setAttribute("rel", "stylesheet");
                        style.setAttribute("type", "text/css");
                        style.setAttribute("href", css);
                        head.appendChild(style);
                    }
                });
                var d = document.createElement("div");
                d.className = "vio-container vio-clearfix";
                t.parentNode.replaceChild(d, t);
                LoadStack.push((function() {
                    Vio.Player.AddTarget(playerName, d, options);
                }));
            },
            Run: function() {
                if (!isRun) {
                    isRun = true;
                    for (var i = 0; i < LoadStack.length; i++) {
                        try {
                            LoadStack[i].call(null);
                        } catch (ex) {
                            log(ex);
                        }
                    }
                }
            }
        }
    })();
}
Vio.Extend(Vio.Player.MediaPlayers, {
    "Flash": (function() {

        var UNDEF = "undefined",
		OBJECT = "object",
		win = window,
		doc = document,
		nav = navigator,
		createElement = Vio.$ce,
		getElementById = Vio.$ge,
		FLASH_MIME_TYPE = "application/x-shockwave-flash",
		browser = Vio.Browser,
		flashVer = "3.2.5r6";
		
        /*	SWFObject v2.2 <http://code.google.com/p/swfobject/> 
        is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
	
	*************** NOTE *****************
        This is a heavily modified version of the swfobject to suit the embed player. It is much smaller than the original
        as I have cut out any functionality that would not be used.
        -- Sugendran
        */

        var swfobject = function() {

            var 
		SHOCKWAVE_FLASH = "Shockwave Flash",
		SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
		EXPRESS_INSTALL_LOCATION = "Flash/expressInstall.swf",

		plugin = false,
		objIdArr = [],
		isExpressInstallActive = false;

            function toLower(i) { return i.toLowerCase(); }
            function toInt(d) { return parseInt(d, 10); }

            /* Grab the player version */
            var playerVersion = (function() {
                var playerVersion = [0, 0, 0], d = null;

                if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
                    d = nav.plugins[SHOCKWAVE_FLASH].description;
                    if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
                        plugin = true;
                        d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
                        playerVersion[0] = toInt(d.replace(/^(.*)\..*$/, "$1"));
                        playerVersion[1] = toInt(d.replace(/^.*\.(.*)\s.*$/, "$1"));
                        playerVersion[2] = /[a-zA-Z]/.test(d) ? toInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1")) : 0;
                    }
                }
                else if (typeof win.ActiveXObject != UNDEF) {
                    try {
                        var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
                        if (a) { // a will return null when ActiveX is disabled
                            d = a.GetVariable("$version");
                            if (d) {
                                d = d.split(" ")[1].split(",");
                                playerVersion = [toInt(d[0]), toInt(d[1]), toInt(d[2])];
                            }
                        }
                    }
                    catch (e) { }
                }
                return playerVersion;
            })();


            /* Requirements for Adobe Express Install
            - only one instance can be active at a time
            - fp 6.0.65 or higher
            */
            function canExpressInstall() {
                return hasPlayerVersion("6.0.65") && !isExpressInstallActive;
            }

            /* Show the Adobe Express Install dialog
            - Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
            */
            function showExpressInstall(att, par, replaceElemIdStr) {
                isExpressInstallActive = true;
                var obj = getElementById(replaceElemIdStr);
                if (obj) {
                    att.id = "SWF$Object$Expr$Inst";
                    att.width = Math.max(att.width || 310, 310);
                    att.height = Math.max(att.height || 137, 137);
                    var pt = plugin ? "PlugIn" : "ActiveX",
				        fv = "MMredirectURL=" + win.location.toString().replace(/&/g, "%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
                    if (typeof par.flashvars != UNDEF) {
                        par.flashvars += "&" + fv;
                    }
                    else {
                        par.flashvars = fv;
                    }
                    createSWF(att, par, replaceElemIdStr);
                }
            }

            /* Cross-browser dynamic SWF creation
            */
            function createSWF(attObj, parObj, id) {
                var r, el = getElementById(id);
                if (el) {
                    if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
                        attObj.id = id + "_obj";
                    }
                    if (browser.msie) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
                        var e = createElement("span");
                        var att = "";
                        for (var i in attObj) {
                            if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
                                if (toLower(i) == "data") {
                                    parObj.movie = attObj[i];
                                }
                                else if (toLower(i) == "styleclass") { // 'class' is an ECMA4 reserved keyword
                                    att += ' class="' + attObj[i] + '"';
                                }
                                else if (toLower(i) != "classid") {
                                    att += ' ' + i + '="' + attObj[i] + '"';
                                }
                            }
                        }
                        var par = "";
                        for (var j in parObj) {
                            if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
                                par += '<param name="' + j + '" value="' + parObj[j] + '" />';
                            }
                        }
                        
                        el.style.visibility = "hidden";
                        el.appendChild(e);
                        e.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" ' + att + '>' + par + '</object>';
                        el.style.visibility = "visible";
                        
                        objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
                        r = getElementById(attObj.id);
 
                    }
                    else { // well-behaving browsers
                        var o = createElement(OBJECT);
                        o.setAttribute("type", FLASH_MIME_TYPE);
                        for (var m in attObj) {
                            if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
                                if (toLower(m) == "styleclass") { // 'class' is an ECMA4 reserved keyword
                                    o.setAttribute("class", attObj[m]);
                                }
                                else if (toLower(m) != "classid") { // filter out IE specific attribute
                                    o.setAttribute(m, attObj[m]);
                                }
                            }
                        }
                        for (var n in parObj) {
                            if (parObj[n] != Object.prototype[n] && toLower(n) != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
                                createObjParam(o, n, parObj[n]);
                            }
                        }
                        el.appendChild(o);
                        r = o;
                    }
                }
                return r;
            }

            function createObjParam(el, pName, pValue) {
                var p = createElement("param");
                p.setAttribute("name", pName);
                p.setAttribute("value", pValue);
                el.appendChild(p);
            }

            /* Cross-browser SWF removal
            - Especially needed to safely and completely remove a SWF in Internet Explorer
            */
            function removeSWF(id) {
                var obj = getElementById(id);
                if (obj && obj.nodeName == "OBJECT") {
                    if (browser.msie) {
                        obj.style.display = "none";
                        (function() {
                            if (obj.readyState == 4) {
                                for (var i in obj) {
                                    if (typeof obj[i] == "function") {
                                        obj[i] = null;
                                    }
                                }
                                obj.parentNode.removeChild(obj);
                            }
                            else {
                                setTimeout(arguments.callee, 10);
                            }
                        })();
                    }
                    else {
                        obj.parentNode.removeChild(obj);
                    }
                }
            }

            /* Flash Player and SWF content version matching
            */
            function hasPlayerVersion(rv) {
                var pv = playerVersion, v = rv.split(".");
                v[0] = toInt(v[0]);
                v[1] = toInt(v[1]) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
                v[2] = toInt(v[2]) || 0;
                return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
            }

            /* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
            */
            var cleanup = function() {
                if (browser.usesAttachEvent) {
                    window.attachEvent("onunload", function() {
                        // cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
                        for (var j = 0; j < objIdArr.length; j++) {
                            removeSWF(objIdArr[j]);
                        }
                    });
                }
            } ();

            return {

                /// embed item
                embed: function(swfUrl, replaceElemIdStr, widthStr, heightStr, swfVersionStr, flashvarsObj, parObj, attObj) {
                    Vio.OnReady(function(){
                        widthStr += ""; // auto-convert to string
                        heightStr += "";
                        var att = {};
                        if (attObj && typeof attObj === OBJECT) {
                            for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
                                att[i] = attObj[i];
                            }
                        }
                        att.data = swfUrl;
                        att.width = widthStr;
                        att.height = heightStr;
                        var par = {};
                        if (parObj && typeof parObj === OBJECT) {
                            for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
                                par[j] = parObj[j];
                            }
                        }
                        if (flashvarsObj && typeof flashvarsObj === OBJECT) {
                            for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
                                if (typeof par.flashvars != UNDEF) {
                                    par.flashvars += "&" + k + "=" + flashvarsObj[k];
                                }
                                else {
                                    par.flashvars = k + "=" + flashvarsObj[k];
                                }
                            }
                        }
                        if (hasPlayerVersion(swfVersionStr)) { // create SWF
                            createSWF(att, par, replaceElemIdStr);
                        }
                        else if (canExpressInstall()) { // show Adobe Express Install
                            att.data = Vio.BaseURL + EXPRESS_INSTALL_LOCATION;
                            showExpressInstall(att, par, replaceElemIdStr);
                        } else {
                            // Show alt content
                            var el = getElementById(replaceElemIdStr);
                            el.innerHTML = "<p style=\"padding:1em;\">The minimum supported version of flash is " + swfVersionStr + ". Please visit <a href=\"http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash\" target=\"_blank\">Adobe</a> to get the latest version of the Flash plugin.</p>";
                        }
                    });
                },


                /// Get Flash Version
                getVersion: function() { return { major: playerVersion[0], minor: playerVersion[1], release: playerVersion[2] }; },

                /// Check Flash Version
                hasVersion: hasPlayerVersion,

                /// Remove Flash object 
                remove: function(objElemIdStr) {
                    removeSWF(objElemIdStr);
                }
            };
        } ();


        function objCheck(targetObject) {
            if (browser.msie) {
                return targetObject.getAttribute("classid") == "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
            } else {
                return targetObject.type == FLASH_MIME_TYPE;
            }
            return false;
        }

        return {
            Name : "Flash",
            Render: function(target) {
                var obj = Vio.$go(target.PlayerElement),
                me = target.Options.embedPlayer;
                if (obj && objCheck(obj)) {
                    // toJSON not needed for version 3.2 of the player forward
                    //obj.loadViostream(Vio.toJSON( { id: me.mediaId } ));
                    obj.loadViostream({ id: me.mediaId });
                } else {
                    Vio.$ee(target.PlayerElement);

                    var div = createElement("div");
                    div.id = "VioPlayer" + Vio.Rand();   
                                        
                    //Embed: function(swfUrl, replaceElemIdStr, widthStr, heightStr, swfVersionStr, flashvarsObj, parObj, attObj) {		
                    var flashVars = {
                        configURL: (Vio.BaseURL + "ConfigXml.axd?playerId=" + me.playerId),
                        defaultMediaId: me.mediaId
                    };

                    
                    swfobject.embed(Vio.BaseURL + "Flash/VioPlayer.swf?v=" + flashVer, div, me.playerWidth, me.playerHeight, "9.0.115", flashVars, {allowFullScreen : true, allowScriptAccess : 'always', wmode : "transparent"}, { id: div.id + "_obj" });
                    
                    target.PlayerElement.appendChild(div);
                }

            },
            CanPlay: function(extension) {
                return (/flv|mp3|mp4|gif|png|jpg|rtmp/i).test(extension);
            }
        }
    })()
});
Vio.Extend(Vio.Player.MediaPlayers, {
	"Quicktime": (function () {
		var UNDEF = "undefined",
        QUICKTIME_MIME = "video/quicktime",
        QUICKTIME_CLSS = "clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",
        browser = Vio.Browser;

		var hasQuicktime = (function () {
			if (navigator.plugins != null && navigator.plugins.length > 0) {
				for (i = 0; i < navigator.plugins.length; i++) {
					var plugin = navigator.plugins[i];
					if (plugin.name.indexOf("QuickTime") > -1) {
						return true;
					}
				}
			}
			else if (Vio.Browser.msie) {
				var qtAx = null
				try {
					qtAx = new ActiveXObject("QuickTime.QuickTime");
					if (qtAx != null) {
						return true;
					}
				}
				catch (e) {
				}
			}
			return false;
		})();

		function RenderQuicktime(div, url, width, height, params) {
			var attr = {};

			attr["width"] = width + "";
			attr["height"] = height + "";

			var embedCode = "<object ";

			if (Vio.Browser.msie) {
				attr["classid"] = QUICKTIME_CLSS;
				attr["codebase"] = "http://www.apple.com/qtactivex/qtplugin.cab";
				params["src"] = url;
			} else {
				attr["type"] = QUICKTIME_MIME;
				attr["pluginspage"] = "http://www.apple.com/quicktime/download/";
				attr["data"] = url;
			}
			params["qtsrc"] = url;

			for (var a in attr) {
				embedCode += (a + "=\"" + attr[a] + "\" ");
			}
			embedCode += ">";

			for (var a in params) {
				embedCode += "<param name=\"" + a + "\" value=\"" + params[a] + "\" />";
			}

			embedCode += "</object>";

			div.innerHTML = embedCode;

		}

		function objCheck(targetObject) {
			if (browser.msie) {
				return targetObject.getAttribute("classid") == QUICKTIME_CLSS;
			} else {
				return targetObject.type == QUICKTIME_MIME;
			}
		}

		return {
			Name: "Quicktime",
			Render: function Render(target) {
				var me = target.Options.embedPlayer;
				var pl = target.Options.player;
				var mb = Vio.Media.Find(me.mediaId);
				if (mb && mb.Urls.length > 0) {
					var exts = ["mov", "mp4", "mp3", "m3u8"];
					var i = 0;
					while (i < exts.length) {
						if (mb.HasUrl(exts[i])) {
							me.playerExtension = exts[i];
						}
						i++;
					}
					var url = mb.FindUrl(me.playerExtension, me.playerQuality);
					if (url) {
						var obj = Vio.$go(target.PlayerElement);
						if (obj && objCheck(obj)) {
							/// change media url
							console.log(url.Url);
							obj.SetURL(url.Url);
						} else {
							/// render quicktime object
							Vio.$ee(target.PlayerElement);
							var params = {
								'controller': true,
								'enablejavascript': true,
								'scale': (pl.scaling == "fit" ? "aspect" : "tofit"),
								'autoplay': (pl.autoplay == "always" ? true : false),
								'volume': (Math.round(100 * parseFloat(pl.volume_default || '0.8')))
							}

							var div = document.createElement("div");
							target.PlayerElement.appendChild(div);
							RenderQuicktime(div, url.Url, me.playerWidth, me.playerHeight, params);

						}
					} else {
						/// media item not available
						Vio.Log("media item not available");
					}
				} else {
					Vio.Media.LoadP(me.mediaId, function () {
						var newMb = Vio.Media.Find(me.mediaId);
						if (newMb && newMb.Urls.length > 0) { // if this isn't true then it's a lost cause
							Render(target);
						}
					});
				}
			},
			CanPlay: function (extension) {
				switch (extension) {
					case "mov":
					case "mp4":
					case "mp3":
						return true;
						break;
				}
				return false;
			}
		}
	})()
});
Vio.Extend(Vio.Player.MediaPlayers, {
    "WindowsMedia": (function() {
        var UNDEF = "undefined",
            WINDOWSMEDIA_MIME = "application/x-ms-wmp",
            WINDOWSMEDIA_CLASSID = "clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6";
        browser = Vio.Browser;
        function RenderWindowsMedia(div, url, width, height, params) {
            var attr = {};
            div.id = "VioPlayer" + Vio.Rand();

            attr["width"] = width + "";
            attr["height"] = height + "";

            var embedCode = "<object ";

            if (Vio.Browser.msie) {
                attr["classid"] = WINDOWSMEDIA_CLASSID;
                params["src"] = url;
            } else {
                attr["type"] = WINDOWSMEDIA_MIME;
                attr["data"] = url;
            }

            params["URL"] = url;
            params["FileName"] = url;

            for (var a in attr) {
                embedCode += (a + "=\"" + attr[a] + "\" ");
            }
            embedCode += ">";

            for (var a in params) {
                embedCode += "<param name=\"" + a + "\" value=\"" + params[a] + "\" />";
            }

            embedCode += "</object>";

            div.innerHTML = embedCode;

        }


        function objCheck(targetObject) {
            if (browser.msie) {
                return targetObject.getAttribute("classid") == WINDOWSMEDIA_CLASSID;
            } else {
                return targetObject.type == WINDOWSMEDIA_MIME;
            }
            return false;
        }


        return {
            Name: "Windows Media",
            Render: function Render(target) {

                var me = target.Options.embedPlayer;
                var pl = target.Options.player;
                var mb = Vio.Media.Find(me.mediaId);
                if (mb && mb.Urls.length > 0) {
                    var exts = ["wmv", "wma", "mp3"];
                    var i = 0;
                    while (typeof (me.playerExtension) == UNDEF && i < exts.length) {
                        if (mb.HasUrl(exts[i])) {
                            me.playerExtension = exts[i];
                        }
                        i++;
                    }

                    var url = mb.FindUrl(me.playerExtension, me.playerQuality)
                    if (url) {
                        var obj = Vio.$go(target.PlayerElement);
                        if (obj && objCheck(obj) && typeof (obj.newMedia) == "function") {
                            /// change media url
                            obj.currentMedia = obj.newMedia(url.Url);
                        } else {
                            Vio.$ee(target.PlayerElement);
                            var params = {
                                "AutoStart": (pl.autoplay == "always" ? 1 : 0),
                                "AllowScan": 1,
                                "EnablePositionControls": false,
                                "EnableFullScreenControls": true,
                                "ShowPositionControls": false,
                                "ShowTracker": 1,
                                "StretchToFit": (pl.scaling == "fit" ? 1 : 0),
                                "DisplaySize": 4,
                                "AutoSize": 0,
                                "uiMode": "mini",
                                "AllowChangeDisplaySize": 1,
                                "Volume": (Math.round(100 * parseFloat(pl.volume_default || '0.8')))
                            }
                            var div = document.createElement("div");
                            target.PlayerElement.appendChild(div);
                            RenderWindowsMedia(div, url.Url, me.playerWidth, me.playerHeight, params);
                        }
                    } else {
                        Vio.Log("no media");
                    }
                } else {
                    Vio.Media.LoadP(me.mediaId, function() {
                        var newMb = Vio.Media.Find(me.mediaId);
                        if (newMb && newMb.Urls.length > 0) { // if this isn't true then it's a lost cause
                            Render(target);
                        }
                    });
                }
            },
            CanPlay: function(extension) {
                switch (extension) {
                    case "wmv":
                    case "wma":
                    case "mp3":
                        return true;
                        break;
                }
                return false;
            }
        }
    })()
});
Vio.Extend({ BaseURL : "http://player.vioapi.com/v6.0.1/" });

