dojo.provide("sfly.page.video.VideoClientProxy");
var MBX = {};
var MBX_old = {};

var CentralDispatch = {
    currentKey: 1,
    getNextKey: function() {
        CentralDispatch.currentKey++;
        return new Date().getTime()+ "-" + CentralDispatch.currentKey;
    },
    requestData: function (url, callbacks, options) {
        var request = CentralDispatch.request({url: url, callbacks: callbacks, options: options});
        request.addToDom();
        return request;
    },

    requestData2: function(url, key, callbacks, options) {
        var request = CentralDispatch.request({ url: url, key: key, callbacks: callbacks, options: options });
        request.addToDom();
        return request;
    },
    
    receiveData: function (version, url, data) {
        CentralDispatch.RequestMap.runAllFor(url, data);
    },
    
    receiveData2: function(data, state) {
        CentralDispatch.RequestMap.runAllFor(state.key, data);
    },

    timeout: 60000 // 60 seconds
};

CentralDispatch.request = function(spec, my) {
    var that;
    that = {};
    that.url = spec.url;
    that.key = spec.key || spec.url;
    that.requestedUrl = null;

    my = my || {};
    my.timeout = null;
    my.options = spec.options || {};

    // Private methods
    my.setCallbacks = function() {
        if (typeof (spec.callbacks) === 'function') {
            my.callbacks = { onSuccess: spec.callbacks };
        } else {
            my.callbacks = spec.callbacks || {};
        }
    };

    my.setTimeout = function() {
        if (CentralDispatch.timeout) {
            if (window) {
                my.timeout = window.setTimeout(function() {
                    that.timeout();
                }, CentralDispatch.timeout);
            }
        }
    };

    my.setElement = function() {
        var element;
        element = document.createElement('script');
        element.src = that.requestedUrl;
        element.onerror = that.error;
        that.element = element;
    };

    my.setRequestUrl2 = function() {
        var url, date;
        url = that.url;
        
        if (my.options.skipCache) {
            // skip the cache and get the value from source
        }

    };

    my.setRequestedUrl = function() {
        var url, date;
        // TODO: Make the url using a library
        url = that.url;
        if (my.options.jsonp === "CentralDispatch" || my.options.skipCache) {
            url = url + "?";
        }
        if (my.options.jsonp === "CentralDispatch") {
            url = url + "callback=CentralDispatch.receiveData";
            if (my.options.skipCache) {
                url = url + "&";
            }
        }
        if (my.options.skipCache) {
            date = new Date();
            url = url + "nocache=" + date.valueOf();
        }
        that.requestedUrl = url;
    };

    my.process = function(func) {
        if (!my.executed) {
            my.executed = true;
            my.cleanupElement();
            func();
        }
    };

    my.cleanupElement = function() {
        if (that.element) {
            document.body.removeChild(that.element);
            that.element = null;
        }
    };

    my.cleanupTimeout = function() {
        if (my.timeout) {
            window.clearTimeout(my.timeout);
            my.timeout = null;
        }
    };

    // Public methods
    that.success = function(data) {
        my.process(function() {
            my.cleanupTimeout();
            if (my.callbacks.onSuccess) {
                my.callbacks.onSuccess(data, my.options.userData);
            }
        });
    };

    that.error = function(msg, url, line) {
        my.process(function() {
            CentralDispatch.RequestMap.remove(that);
            if (my.callbacks.onError) {
                my.cleanupTimeout();
                my.callbacks.onError(msg, url, line, my.options.userData);
            }
        });
    };

    that.timeout = function() {
        my.process(function() {
            CentralDispatch.RequestMap.remove(that);
            if (my.callbacks.onTimeout) {
                my.callbacks.onTimeout(that, my.options.userData);
            }
        });
    };

    that.addToDom = function() {
        document.body.appendChild(that.element);
    };

    that.isExecuted = function() {
        return my.executed;
    };

    // Init
    my.executed = false;
    my.setRequestedUrl();
    my.setCallbacks();
    my.setTimeout();
    my.setElement();
    CentralDispatch.RequestMap.add(that);

    return that;
};

CentralDispatch.RequestMap = function () {
    var klass = {}, requests = {}, findAllFor;

    findAllFor = function (url) {
        var regex, fullUrl;

        // Exit with an exact match if possible for speed
        if (requests[url]) {
            return requests[url];
        }

        // TODO: The following is innefficient in the case of many requests
        regex = new RegExp(url + '$');
        for (fullUrl in requests) {
            if (requests.hasOwnProperty(fullUrl)) {
                if (regex.test(fullUrl)) {
                    return requests[fullUrl];
                }
            }
        }
        // Incase we don't find anything
        return [];
    };

    klass.add = function (request) {
        requests[request.key] = requests[request.key] || [];
        requests[request.key].push(request);
    };

    klass.runAllFor = function (url, data) {
        var matches, current;
        matches = findAllFor(url);
        current = matches.pop();
        while (current) {
            // TODO: Should clone data so that functions don't spoil the fun for
            // others.
            try {
                current.success(data); 
                current = matches.pop();
            } catch (e) {
                // Silently ignore errors so that other callbacks will run
            }
        }
    };

    klass.remove = function (request) {
        var matches, i, match;
        matches = findAllFor(request.key);
        for (i = 0; i < matches.length; i += 1) {
            if (matches[i] === request) {
                match = i;
                break;
            }
        }

        if (match !== undefined) {
            matches.splice(match, 1);
        }
    };

    return klass;
}();

// all of the Motionbox API will be here.
(function() {

    MBX_old.Client = function() {
        var klass = {};

        klass.nonHaBaseUrlFor = function(version) {
            if (version === 'dev1') {
                return 'http://localhost:3000';
            } else if (version.match("prod[1-3]")) {
                return 'http://www.motionbox.com';
            } else if (version.match("stg[0-9]+-[0-9]")) {
                return 'http://web.' + version.split('-')[0] + '.mbox';
            } else {
                throw ('Client.nonHaBaseUrlFor: Unknown version - ' + version);
            }
        };

        klass.baseUrlFor = function(version) {
            if (version === 'dev1') {
                return 'http://localhost:3000';
            } else if (version.match("prod[1-3]")) {
                return 'http://ha.motionbox.com';
            } else if (version.match("stg[0-9]+-[0-9]")) {
                return 'http://web.' + version.split('-')[0] + '.mbox';
            } else {
                throw ('Client.baseUrlFor: Unknown version - ' + version);
            }
        };

        klass.pathFor = function(version) {
            if (version === 'dev1') {
                return '/v2/ha';
            } else if (version === 'prod1') {
                return '/v2/ha';
            } else if (version.match("prod[2-3]")) {
                return '/s/ha';
            } else if (version.match("stg[0-9]+-[0-9]")) {
                return '/s/ha';
            } else {
                throw ('Client.pathFor: Unknown version - ' + version);
            }
        };

        klass.baseHaUrlFor = function(version) {
            return klass.baseUrlFor(version) + klass.pathFor(version);
        };

        klass.version = function(token) {
            return token.split('.')[0];
        };

        klass.secret = function(token) {
            return token.split('.')[1];
        };

        klass.HALocation = function(resource, token) {
            var version = klass.version(token);
            return [klass.baseHaUrlFor(version), '/', resource].join('');
        };

        klass.metadataUrlFor = function(resource, uid, token, collection) {
            var version, secret, folder, file;
            version = token.split('.')[0];
            secret = token.split('.')[1];
            folder = [secret.charAt(0), secret.charAt(1), secret.charAt(2), secret.charAt(3)].join('/');
            if (version.match("prod[2-3]") || version.match("stg[0-9]+-2")) {
                file = [uid, secret].join('-') + '.js';
                if (collection) {
                    return [klass.HALocation(resource, token), collection, folder, file].join('/');
                } else {
                    return [klass.HALocation(resource, token), folder, file].join('/');
                }
            } else {
                if (collection) {
                    file = [collection, uid, secret].join('-') + '.js';
                } else {
                    file = [uid, secret].join('-') + '.js';
                }
                return [klass.HALocation(resource, token), folder, file].join('/');
            }
        };

        klass.requestData = function(url, callback, options) {
            options = options || {};
            if (options.skipCache !== false) {
                options.skipCache = true;
            }
            CentralDispatch.requestData(url, callback, options);
        };

        klass.setTimeout = function(timeout) {
            CentralDispatch.timeout = timeout;
        };

        return klass;
    } ();



    MBX_old.domHelper = function() {
        var self = {};

        self.generateScriptTag = function(src) {
            var element = document.createElement('script');
            element.type = 'text/javascript';
            element.src = src;
            return element;
        };

        return self;
    } ();



    MBX_old.Folder = function() {
        var klass, allForUserCallbacks, foldersMetadataUrlFor;

        klass = {};
        allForUserCallbacks = {};

        foldersMetadataUrlFor = function(uid, token) {
            return MBX_old.Client.metadataUrlFor('folders', uid, token, 'user');
        };

        klass.findAll = function(parent, uid, token, callback, options) {
            if (parent === 'user') {
                MBX_old.Client.requestData(foldersMetadataUrlFor(uid, token), callback, options);
            } else {
                throw ('Folder.findAll: unknown parent');
            }
        };

        klass.allForUserMetadataReceive = function(uid, data) {
            // silently ignore that this call is deprecated
        };

        return klass;
    } ();


    MBX_old.Player = function() {
        var klass, hdPlayerEmbed, flashPlayerEmbed;
        klass = {};

        hdPlayerEmbed = function(uid, token, type, opts) {
            var ret, width, height, wmode, wmodeEmbed, flashvars, params, attributes, id;
            opts = opts || {};
            width = opts.width || '416';
            height = opts.height || '312';
            if (!opts.wmode || (opts.wmode === 'none')) {
                wmode = '';
                wmodeEmbed = '';
            }
            else {
                wmode = '<param name="wmode" value="' + opts.wmode + '">';
                wmodeEmbed = 'wmode="' + opts.wmode + '"';
            }
            if (type !== 'hd' && type !== 'sd') {
                type = 'sd';
            }
            id = uid + Math.floor(Math.random * 100000);

            ret = ['<object width="',
               width,
               '" height="',
               height,
               '" id="progressive_player_',
               id,
               '" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" style="visibility: visible;">',
               '<param value="http://bg-video.cp.motionbox.com/motionboxons/flash/VideoPlayer.swf" name="movie"/>',
               '<param value="always" name="allowScriptAccess"/>',
               '<param value="true" name="allowFullscreen"/>',
               wmode,
               '<param value="video_uid=',
               uid,
               '&security_token=',
               token,
               '&type=',
               type,
               '" name="flashvars">',
               '<!--[if !IE]>-->',
               '<object width="', width, '" height="', height,
               '" name="progressive_player" allowscriptaccess="always" allowfullscreen="true" data="http://bg-video.cp.motionbox.com/motionboxons/flash/VideoPlayer.swf" type="application/x-shockwave-flash" ',
               wmodeEmbed,
               ' flashvars="video_uid=',
               uid, '&security_token=', token, '&type=', type, '">',
               '<!--<![endif]-->',
                   '<h2>To watch the video, you\'ll first need to  <a href="http://www.adobe.com/go/getflashplayer">install the flash player</a>.</h2>',
               '<!--[if !IE]>-->',
               '</object>',
               '<!--<![endif]-->',
               '</object>'
              ].join('');
            return ret;
        };

        klass.embedFor = function(uid, token, type, opts) {
            return hdPlayerEmbed(uid, token, type, opts);
        };

        return klass;
    } ();



    MBX_old.Thumbnail = function() {
        var klass = {};

        // BEGIN nasty code duplication on account of thumbnail location
        klass.pathFor = function(version) {
            if (version === 'dev1') {
                return '/v2/ha';
            } else if (version.match("prod[1-3]")) {
                return '/v2/ha';
            } else if (version.match("stg[0-9]+-[0-9]")) {
                return '/v2/ha';
            } else {
                throw ('Thumbnail.pathFor: Unknown version - ' + version);
            }
        };

        klass.baseHaUrlFor = function(version) {
            return MBX_old.Client.baseUrlFor(version) + klass.pathFor(version);
        };

        klass.HALocation = function(resource, token) {
            var version = token.split('.')[0];
            return [klass.baseHaUrlFor(version), '/', resource].join('');
        };

        klass.metadataUrlFor = function(resource, uid, token, collection) {
            var secret, folder, file;
            secret = token.split('.')[1];
            folder = [secret.charAt(0), secret.charAt(1), secret.charAt(2), secret.charAt(3)].join('/') + '/';
            if (collection) {
                file = [collection, uid, secret].join('-') + '.js';
            } else {
                file = [uid, secret].join('-') + '.js';
            }
            return [klass.HALocation(resource, token), '/', folder, file].join('');
        };
        // END nasty code duplication on account of thumbnail location

        klass.urlFor = function(uid, token, quality) {
            return klass.metadataUrlFor(quality + 's', uid, token, 'video');
        };

        return klass;
    } ();



    MBX_old.Upload = {
        status: function(url, callback, options) {
            options = options || {};
            options.jsonp = options.jsonp || "CentralDispatch";
            if (!url.match(".js$")) {
                url = url + ".js";
            }
            MBX_old.Client.requestData(url, callback, options);
        }
    };



    MBX_old.User = function() {
        var klass = {},
        callbacks = {},
        metadataUrlFor;

        metadataUrlFor = function(uid, token) {
            return MBX_old.Client.metadataUrlFor('users', uid, token);
        };

        klass.find = function(uid, token, callback, options) {
            MBX_old.Client.requestData(metadataUrlFor(uid, token), callback, options);
        };

        klass.metadataReceive = function(uid, data) {
            // silently ignore that this call is deprecated
        };

        return klass;
    } ();


    MBX_old.Video = function() {
        var klass = {},
        allForFolderCallbacks = {},
        videoCallbacks = {},
        collectionMetadataUrlFor,
        pathForVideo,
        metadataUrlFor;

        pathForVideo = function(version) {
            return 'v2/ha';
        };

        collectionMetadataUrlFor = function(parent, uid, token) {
            return MBX_old.Client.metadataUrlFor('videos', uid, token, parent);
        };

        metadataUrlFor = function(uid, token) {
            var version, secret, folder, file;
            version = token.split('.')[0];
            secret = token.split('.')[1];
            folder = [secret.charAt(0), secret.charAt(1), secret.charAt(2), secret.charAt(3)].join('/');
            file = [uid, secret].join('-') + '.js';
            return [MBX_old.Client.baseUrlFor(version), pathForVideo(version), 'videos', folder, file].join('/');
        };

        klass.encodeUrlFor = function(uid, token, format) {
            var version, base;
            version = MBX_old.Client.version(token);
            return MBX_old.Client.nonHaBaseUrlFor(version) +
               "/v2/videos/" +
               uid +
               "/encode.js?callback=CentralDispatch.receiveData&security_token=" +
               MBX_old.Client.secret(token) +
               "&encodeFormat=" +
               format +
               "&nocache=" +
               (new Date()).valueOf();
        };

        klass.allForFolderMetadataReceive = function(uid, data) {
            // silently ignore that this call is deprecated
        };

        klass.metadataReceive = function(uid, data) {
            // silently ignore that this call is deprecated
        };

        klass.findAll = function(parent, uid, token, callback, options) {
            if (parent === 'folder') {
                MBX_old.Client.requestData(collectionMetadataUrlFor('folder', uid, token), callback, options);
            } else {
                throw ('Video.findAll: unknown parent');
            }
        };

        klass.find = function(uid, token, callback, options) {
            MBX_old.Client.requestData(metadataUrlFor(uid, token), callback, options);
        };

        klass.encode = function(uid, token, format, callback, options) {
            var url = klass.encodeUrlFor(uid, token, format);
            options = options || {};
            options.expectedUrl = options.expectedUrl || url.split("?")[0];
            return CentralDispatch.requestData(url, callback, options);
        };

        klass.encodingProgress = function(idsAndTokens, callback, options) {
            var url = klass.encodingProgressUrlFor(idsAndTokens);
            options = options || {};
            options.jsonp = options.jsonp || "CentralDispatch";
            return MBX_old.Client.requestData(url, callback, options);
        };

        klass.encodingProgressUrlFor = function(idsAndTokens) {
            var uids, version, i;
            uids = [];
            for (i = 0; i < idsAndTokens.length; i += 1) {
                uids[i] = idsAndTokens[i].uid;
            }
            version = MBX_old.Client.version(idsAndTokens[0].securityToken);
            return MBX_old.Client.baseUrlFor(version) +
               "/v2/encoding_progress/" +
               uids.join("-") + '.js';
        };

        return klass;
    } ();

})();

// define the new S360 APIs
var S360 = {};
var VideoApiConfig = {};

(function() {

    var _s360paths = {
        getVideo: function(id) { return "/abstract_assets/" + id; }
    };
    var _api = VideoApiConfig = {
        env : "dev",
        uid : "",
        host : "share",
        useS360: false,
        embed: "http://360.sorensonmedia.com/PUBID/embedv2.js?autoPlay=true",
        shareproxy: "http://cmd.shutterfly.com/commands",
        s360Root: "http://360services.sorensonmedia.com",
        s360proxy: "http://360services.sorensonmedia.com/restful_proxy/shutterfly.php",
        
        createUser: function(){ return {host:"share", url: _api.shareproxy+ "user/register"}; },
        prepareUpload: function(){ return {host:"share", url: _api.shareproxy+ "misc/prepareupload"}; },
        getUser: function(){ return {host:"share", url: _api.shareproxy+ "/user/get"};},
        upgradeUser: function(){ return {host:"share", url: _api.shareproxy+ "/user/upgrade"};},
        getFolders: function(){ return {host:"share", url: _api.shareproxy+ "/user/folders"};},
        getVideos: function(){ return {host:"share", url: _api.shareproxy+ "/folder/videos"};},
        
        getAssets: function(){ return {host: "share", url: _api.shareproxy+ "/user/getassets"};},
        getThumbCompatibility: function(){ return {host: "share", url: _api.shareproxy+ "/video/getthumbcompatibility"};},
        startEncode: function(){ return {host:"share", url: _api.shareproxy + "/video/transcode"}; },
        editVideo: function() { return {host: "share", url: "video/edit"};},
        deleteVideo: function() { return {host: "share", url: "video/delete"}; },
       
        getVideosById: function(){ return {host:"s360", url: _api.s360proxy, verb: "GET", path:"/abstract_assets"};},
        getVideo: function(){ return {host:"s360", url: _api.s360proxy, verb: "GET", path: "/abstract_assets" }; },        
        encodeProgress: function() { return {host:"s360", url: _api.s360proxy, verb: "GET", path: "/transcode" }; },
        updateS360RootUrl: function(cfg) {
            switch(cfg.env) {
                case "local": 
                case "dev":   return "http://shutterfly.360.sorensonmedia.info";
                case "beta":  
                case "zulu": 
                case "stage": 
                case "prod": default: return "http://360services.sorensonmedia.com";
            }

        },
        updateEmbed: function(cfg) {
            switch(cfg.env) {
                case "local": case "dev": return "http://shutterfly.360.sorensonmedia.info/PUBID/embed.js?autoPlay=true";
                case "beta": case "zulu": case "stage": case "prod": default: return "http://360.sorensonmedia.com/PUBID/embedv2.js?autoPlay=true";
            }
        },
        updateS360ProxyUrl: function(cfg) {
            var end = "/restful_proxy/shutterfly.php";
            var root = "http://360services.sorensonmedia.com";
            switch(cfg.env) {
                case "local": // return "http://360services.shutterfly.360.sorensonmedia.info" + end;
                case "dev": root = "http://360services.shutterfly.360.sorensonmedia.info"; break;
                case "beta": end = "/restful_proxy/beta_shutterfly.php"; break;
                case "zulu": 
                case "stage": 
                case "prod": default: break;
            }
            return root + end;
        },
        Initialize: function(data) {
            var config = VideoApiConfig;
            config.useS360 = data.useS360 || false;
            config.env = (data.env || "dev").toLowerCase();
            config.host = data.host || "share";          
            config.embed= _api.updateEmbed(config);
            config.s360Root = _api.updateS360RootUrl(config);
            config.s360proxy = _api.updateS360ProxyUrl(config);
            config.uid = data.uid || "";
            config.migration_cb = data.migration_callback;
            config.playGif = data.playGif|| ["",""];
            config.progressGif = data.progressGif;
            config.cmdserver = (data.cmdserver || "cmd.shutterfly.com");
            config.shareproxy = "http://" + config.cmdserver + "/commands/videoapi";
            MBX = MBX_new;
        }
    };
   
    function getApiEndPoint(api) {
        return _api[api]();
    };
    function isArray(o) { return Object.prototype.toString.apply(o) === "[object Array]"; };


    S360.Client = function() {
        var klass = {};
        var count = 1;
        
        klass.getNextKey = function() {
            var id = count ++;
            return new Date().getTime()+ "-" + id;
        };
        
        klass.getExtraArgs = function(key) {
            return escape("{ \"key\": \"" + key + "\" }");
        };
        
        klass.getShareUrl = function(api, key) {
            var format = "proxy?uid={0}&callback={3}&extraArguments={4}&";
            var url = "";
            var proxy = getApiEndPoint(api);
            if (proxy.host != "share") {
                // error
            } else {
                url = proxy.url + "?callback=CentralDispatch.receiveData2&extraArguments=" + klass.getExtraArgs(key) + "&";
                // otherwise the userid will be retrieved from the Session
                // append uid only if coming from lbx
                if (_api.host != "share") url += "uid=" + _api.uid + "&";
            }
            return url;
        };

        klass.getS360Url = function(api, path, key) {
            var format = "proxy?method={0}&path={1}&data={2}&callback={3}&extraArguments={4}";
            var proxy = getApiEndPoint(api);
            var url = proxy.url + "?method=" + proxy.verb + "&path=" + proxy.path + 
                "&callback=CentralDispatch.receiveData2&extraArguments=" + klass.getExtraArgs(key) + "&";
            return url;
        };

        return klass;
    } ();

    S360.User = function() {
        var klass = {};
        klass.find = function(uid, callbacks, options) {
            var key = CentralDispatch.getNextKey();
            var url = S360.Client.getShareUrl("getUser", key);
            CentralDispatch.requestData2(url, key, callbacks, options);
        };

        klass.findFolders = function(uid, callbacks, options) {
            var key = CentralDispatch.getNextKey();
            var url = S360.Client.getShareUrl("getFolders", key);
            CentralDispatch.requestData2(url, key, callbacks, options);
        };

        klass.findVideos = function(uid, callbacks, options) {
        };
        
        klass.upgradeUrl = function() {
        };

        return klass;
    } ();

    S360.Folder = function() {
        var klass = {};

        klass.findVideos = function(folderid, callbacks, options) {
            var key = CentralDispatch.getNextKey();
            var url = S360.Client.getShareUrl("getVideos", key);
            CentralDispatch.requestData2(url, key, callbacks, options); 
        };

        klass.editFolder = function(uid, folderid, data, callbacks, options) {
        };

        klass.deleteFolder = function(uid, folderid, callbacks, options) {
        };

        return klass;
    } ();

    S360.Video = function() {

        var klass = {};

        klass.find = function(videoids, callbacks, options) {
            // we need to find the video
            var key = CentralDispatch.getNextKey();
            // var url = S360.Client.getShareUrl("getVideo", key);
            // url += "videoid=" + videoid + "&";
            var url = S360.Client.getS360Url("getVideo", null, key);
            var temp=[];
            for(var i=0; i<videoids.length; i++) temp.push("id[]=" + videoids[i] + "&");
            var edata = escape(temp.join("") + "custom_format=shutterfly&");
            url += "data=" + edata;
            CentralDispatch.requestData2(url, key, callbacks, options); 
        };
        klass.encode = function(file, format, callbacks, options) {
            // sorenson
            var videoid = file.abstract_asset_id || file.sourceId;
            var title = file.name || file.title;
            var key = CentralDispatch.getNextKey();
            var dest = S360.Client.getShareUrl("startEncode", key);
            dest += "videoid=" + videoid + "&title=" + escape(title) + "&format=" + format + "&";
            CentralDispatch.requestData2(dest, key, callbacks, options);
        };

        klass.encodingProgress = function(videoids, callbacks, options) {
        };

        klass.thumbUrl = function(videoid, callback, options) {
        };

        klass.thumbUrlCompatiblity = function(mbxId, mbxToken, callback, options) {
        };

        return klass;
    } ();

    S360.Migration = function() {
        var klass = {};

        klass.migrateVideo = function(mbxId, mbxtoken, callback, options) {
        };

        klass.thumbUrl = function(mbxId, mbxToken, callback, options) {
        };

        return klass;
    } ();

    S360.Outage = function() {
        var klass = {};

        klass.check = function() {

        };

        return klass;
    } ();
    
    S360.Upload = function() {
        var klass = {};
        
        klass.status = function(url, callbacks, options) {
        };
    } ();

})();

var MBX_new = {};
// define the mapping between S360 and the MBX api
(function() {

    function isS360(token) {
        return (/^s360/).test(token);
    }
    function isMigrated(mbxId, token) {
        return isS360(token);
    };
    function isFunction(o) { return Object.prototype.toString.apply(o) === "[object Function]"; };
    function isUndefined(o) { return typeof o === "undefined"; };

    function extend(value, props) {
        if (props) {
            for (var prop in props) {
                value[prop] = props[prop];
            }
        }
        return value;
    };
    function forEach(o, cb) {
        var i = 0, val, len = o.length, obj;
        if (isUndefined(len)) {
            for(var name in o) {
                if (o.hasOwnProperty(name)) {
                    obj = o[name];
                    if (cb.call(obj, obj, name) === false) break;
                }
            }
        } else {
            for( i=0; i < len; i++) {
                val = o[i];
                if (cb.call(val, val, i) === false) break;
            }
        }
    };
//    function merge(value, props) {
//        if (props) {
//            // Apply to each argument object...
//            forEach(Array.prototype.slice.call(arguments, 1), function(o) {
//                if (value === null || value === undefined) {
//                    // Make value like rhs.
//                    value = new o.constructor();
//                }
//                for (var prop in o) {
//                    if (typeof o[prop] == "object") {
//                        // Merge properties.
//                        value[prop] = merge(value[prop], o[prop]);
//                    } else {
//                        value[prop] = o[prop];
//                    }
//                }
//            });
//        }
//        return value;
//    };
    function converToISO8601String(inputString) {	 
        // fix the uploadedAt to have a ISO8601/rfc3339 format	 
        var uploadedAt = inputString.replace(" ","T");	 
        uploadedAt += "Z";	 
        return uploadedAt;
    };
    function convertArrayToLiteral(array, key, convert, result) {
        var item, i, val;
        result = result || {};
        for(i = 0; i < array.length; i++) {
            item = array[i];
            if (item && item[key]) {
                val = item[key];
                item = (convert) ? convert(item) : item;
                result[val] = item;
            }
        }
        return result;
    };
        
    MBX_new.User = function () {
        var klass = {};
        
        klass.find = function(uid, token, callbacks, options) {
            if (VideoApiConfig.useS360) {
                if (isS360(token)) {
                    S360.User.find(VideoApiConfig.uid, callbacks, options);
                } else {
                    // we have an error
                    if(callbacks && callbacks.onError) callbacks.onError("APi operation not compatible", "", "", options.userData);
                }
            } else {
                MBX_old.User.find(uid, token, callbacks, options);
            }
        };
        
        return klass;
    } ();
    
    MBX_new.Folder = function () {
        var klass = {};
        
        // get all the folders for a user
        klass.findAll = function (parent, useruid, usertoken, callbacks, options) {
            if (VideoApiConfig.useS360) {
                if (isS360(usertoken)) {
                    S360.User.findFolders(useruid, callbacks, options); 
                } else {
                    if(callbacks && callbacks.onError) callbacks.onError("APi operation not compatible", "", "", options.userData);
                    return;
                }
            } else {
                MBX_old.Folder.findAll(parent, useruid, usertoken, callbacks, options);
            }
        };
        
        return klass;
    } ();
    
    MBX_new.Video = function() {
        var klass = {};

        function translateStatus(input) {
            //Created
            //Awaiting Transcode
            //Transcode Failed
            //Retired
            //Error
            //Live
            //Retired/Deleted
            //Deleted Permanently
            //Undefined

            switch(input.toLowerCase()) {
                case "awaiting transcode":
                    return "encoding";
                case "live":
                    return "playable";
                case "retired":
                case "deleted":
                case "deleted permanently":
                    return "removed_user";
                case "created":
                case "undefined":
                    return "available_for_encoding";
                case "transcode failed":
                case "error":
                default:
                    return "failed";
            }
        };
        function parseResponse(data) {
            var videos = [], video = {};
            if (data.abstract_asset_list) {
                var arr = data.abstract_asset_list;
                var count = arr.length;
                for(var i=0; i<count; i++) {
                    video = klass.translateVideoBlob(arr[i]);
                    videos.push(video);
                }
            }
            return videos;
        };
        
        klass.getPublishingId = function(sourceToken, format) {
            var parts = sourceToken.split(".");
            // 3 parts;
            return format == "sd" ? 
                    ( parts.length >= 2 ? parts[1] : "") : 
                    ( parts.length >= 3 ? parts[2] : "");
        };
        
        klass.translateVideoBlob = function(s360Blob) {
            var output = {status: "failed"};
            if (s360Blob) {
                var baseFormat = {
                    duration: s360Blob.duration,
                    height: 0,
                    width: 0,
                    status: "",
                    downloadUrl: "",
                    estimatedEncodingTime: null,
                    encodingProgress: null,
                    format: "",
                    streamingUrl: ""
                };
                extend(output, {
                    title: s360Blob.display_name,
                    duration:s360Blob.duration,
                    sourceWidth:0,
                    sourceHeight:0,
                    uid: s360Blob.id,
                    securityToken: "s360",
                    userUid: s360Blob.subaccount_id,
                    description: s360Blob.description,
                    hasSource : s360Blob.has_source,
                    status: translateStatus(s360Blob.status),
                    uploadedAt: converToISO8601String(s360Blob.upload_date),
                    formats: { thumbnail: {}, sd : {}, hd : {} }
                });
                if (output.status == "playable") output.status = "available";
                if (output.status == "encoding") output.status = "available";
                output.thumbnail = s360Blob.thumbnail;
                // lets add thumbnail, sd and if available hd
                var thumb = output.formats.thumbnail;
                var sd = output.formats.sd;
                var hd = output.formats.hd;
                // create the thumbnail stream
                extend(output.formats.thumbnail, baseFormat);
                thumb.status = translateStatus(s360Blob.status);
                thumb.progressiveUrl = s360Blob.thumbnail;
                thumb.downloadUrl = s360Blob.thumbnail;
                // create SD stream
                extend(sd, baseFormat);
                extend(sd, s360Blob.format_list.sd);
                sd.status = translateStatus(sd.status);
                if(sd.status == "available") sd.status = "encoding";
                sd.downloadUrl = (sd.download || sd.dowload) + "&download=true";
                // create HD stream only if we have the hasSource
                extend(hd, baseFormat);
                extend(hd, s360Blob.format_list.hd);
                hd.status = translateStatus(hd.status);
                hd.downloadUrl = (hd.download || hd.dowload) + "&download=true";

                if (output.hasSource === 0){
                    if (hd.status == "available_for_encoding") {
                        // we don't add the stream
                        hd.status = "available";
                    }
                }
                output.securityToken += "." + (sd.status == "playable" ? sd.publishing_id : "");
                output.securityToken += "." + (hd.status == "playable" ? hd.publishing_id : "");
                if (VideoApiConfig.env == "dev") {
                    if(sd.downloadUrl) sd.downloadUrl = sd.downloadUrl.replace("http://360.sorensonmedia.com", VideoApiConfig.s360Root);
                }
            }
            return output;
        };
        
        klass.find = function(videouid, videotoken, callbacks, options) {
            // this API is backward compatible
            if (VideoApiConfig.useS360) {
                if (isS360(videotoken)) {
                    var cb = {
                        onSuccess: function(d, udata){
                            // we have a response
                            var cbs = callbacks;
                            var videos = parseResponse(d);
                            if (isFunction(callbacks)) cbs(videos[0], udata);
                            else if (cbs.onSuccess) cbs.onSuccess(videos[0], udata);
                        },
                        onTimeout: function(d, udata){
                            var cbs = callbacks;
                            if (cbs.onTimeout) cbs.onTimeout(d, udata);
                        },
                        onError: function(msg, url, line, udata){
                            var cbs = callbacks;
                            if (cbs.onError) cbs.onError(msg, url, line, udata);
                        }
                    };
                    S360.Video.find([videouid], cb, options);
                } else {
                    if(callbacks && callbacks.onError) callbacks.onError("APi operation not compatible", "", "", options.userData);
                }
            } else {
                MBX_old.Video.find(videouid, videotoken, callbacks, options);
            }
        };
        
        klass.findByIds = function(videoids, callbacks, options) {
            var cb = {
                onSuccess: function(d, udata){
                    // we have a response
                    var cbs = callbacks;
                    var videos = parseResponse(d);
                    var lookup = convertArrayToLiteral(videos, "uid", null);
                    if (isFunction(callbacks)) cbs(lookup, udata);
                    else if (cbs.onSuccess) cbs.onSuccess(lookup, udata);
                },
                onTimeout: function(d, udata){
                    var cbs = callbacks;
                    if (cbs.onTimeout) cbs.onTimeout(d, udata);
                },
                onError: function(msg, url, line, udata){
                    var cbs = callbacks;
                    if (cbs.onError) cbs.onError(msg, url, line, udata);
                }
            };
            S360.Video.find(videoids, cb, options);
        };

        // Get all videos in a folder
        klass.findAll = function(parent, folderuid, foldertoken, callbacks, options) {
            if (VideoApiConfig.useS360) {
                if ( !isS360(foldertoken)) {
                    callbacks.onError("APi operation not compatible", "", "", options.userData);
                    return;
                }
                // this API is not backward compatible
                // find all the videos in the folder.
                var cb = {
                    onSuccess: function(d, udata){
                        // we have a response
                        var cbs = callbacks;
                        var videos = parseResponse(d);
                        if (isFunction(callbacks)) cbs(videos, udata);
                        else if (cbs.onSuccess) cbs.onSuccess(videos, udata);
                    },
                    onTimeout: function(d, udata){
                        var cbs = callbacks;
                        if (cbs.onTimeout) cbs.onTimeout(d, udata);
                    },
                    onError: function(msg, url, line, udata){
                        var cbs = callbacks;
                        if (cbs.onError) cbs.onError(msg, url, line, udata);
                    }
                };
                S360.Folder.findVideos(folderuid, cb, options);
            } else {
                MBX_old.Video.findAll(parent, folderuid, foldertoken, callbacks, options);
            }
        };
        
        // initiate a hd encode
        klass.encode = function(videoid, videotoken, format, callbacks, options) {
            // this API is not backward compatible
            if (!isS360(videotoken)) {
                alert("HD encoding is currently unavailable. please try again later.");
                if ( callbacks && callbacks.onError)
                    callbacks.onError("API operation not compatible", "", "", options.userData);
                return;
            } else {
                S360.Video.encode({sourceId: videoid}, format, callbacks, options);
                return;
            }
        };
        
        function encodingStream(vid) { // the vid is translated to MBX format so will have thumbnail, sd and hd formats
            var hasThumb = false, hasSd = false, hasHd = false;
            if (vid && vid.formats) {
                hasThumb = (vid.formats.thumbnail && vid.formats["thumbnail"].progressiveUrl);
                hasSd = (vid.formats.sd && vid.formats["sd"].status == "playable");
                hasHd = (vid.formats.hd && vid.formats["hd"].status == "playable");
            }
            return hasThumb ? ( hasSd ? (hasHd ? "" : "hd") : "sd" ) : "sd";
        };
        function transformProgressBlob(assetid, format, input) {
            var result = {}, frmt;
            result.encodingFormat = format;
            frmt = result[format] = {};
            if(input.error) {
                frmt.status = "error";
            } else {
                result.queueWaitTime = null;
                frmt.status = "encoding";
                switch(input.status_description) {
                    case "Published":
                        frmt.status = "playable"; break;
                    case "Error":
                        frmt.status = "failed"; break;
                    case "Downloading":
                    case "Waiting":
                        result.queueWaitTime = 300; break;
                    case "Transcoding":
                    case "Finished":
                    default:
                        frmt.encodingProgress = input.percent_complete; break;
                }
            }
            result.status = frmt.status;
            return result;
        };
        function trackSuccess(blobs, callbacks, options) {
            // see if any video has got the status of Finished.
            var ids = [];
            forEach(blobs, function(o, aid) {
                if (o[o.encodingFormat].status == "playable") {
                    ids.push(aid);
                }
            });
            if (ids.length > 0) {
                // we have some statuses to verify, so lets make a call to the get video assets api
                var cb = {
                    onSuccess: function(d, udata) {
                        var cbs = callbacks, vblobs = {}, pblobs = blobs;
                        // we are supposed to get back all the provided ids which are valid
                        if (d && d.abstract_asset_list) {
                            vblobs = convertArrayToLiteral(d.abstract_asset_list, "id", klass.translateVideoBlob);
                            forEach(vblobs, function(o, n) {  
                                // lets see if we have this in the pblobs
                                if (pblobs[n]) {
                                    pblobs[n] = { queueWaitTime:null, 
                                                    "sd": o.formats["sd"], 
                                                    "hd": o.formats["hd"], 
                                                    "thumbnail": o.formats["thumbnail"]};
                                }
                            });
                        }
                        try {
                        if (isFunction(cbs)) cbs(pblobs, options);
                        else if (cbs.onSuccess) cbs.onSuccess(pblobs, options);
                        } catch (e) {console.debug("failed " + pblobs);}
                    },
                    onTimeout: function(d, udata) {
                        var cbs = callbacks;
                        if (cbs.onTimeout) cbs.onTimeout(d, udata);
                    },
                    onError: function(msg, url, line, udata) {
                        var cbs = callbacks;
                        if (cbs.onError) cbs.onError(msg, url, line, udata);
                    }
                };
                // call the proxy for the list of videos
                S360.Video.find(ids, cb, options);
                return false;
            } else {
                return true;
            }
        };
        function encodingProgressSuccess(callbacks, vlookup, elookup, d, udata) {
            var i, frmt, aid, arr, t1;
            // we have a response
            var cbs = callbacks, pblobs = {};
            if (d.results) {
                for(i=0, arr=d.results;i<arr.length;i++) {
                    aid = arr[i].abstract_asset_id;
                    frmt = elookup[aid];
                    pblobs[aid] = transformProgressBlob(aid, frmt, arr[i]);
                }
                // match for the lookups
                if (trackSuccess(pblobs, cbs, udata)) {
                    if (isFunction(cbs)) cbs(pblobs, udata);
                    else if (cbs.onSuccess) cbs.onSuccess(pblobs, udata);
                }
            } else {
                if (cbs.onError) cbs.onError("Empty results received from server.", "", "", udata);
            }
        };                
        // get the progress of the video
        klass.encodingProgress = function(videoBlobList, callbacks, options) {
            // this API is not backward comptible
            var blob, lookup = {}, search=[], elookup = {}, format, hasMbx;
            // convert the input array into lookup
            convertArrayToLiteral(videoBlobList, "uid", null, lookup);
            // generate the list to query
            forEach(lookup, function(o, aid) {
                if (isS360(o.securityToken)) {
                    var format = encodingStream(o);
                    if (format) {
                        search.push("abstract_asset_id[]=" + o.uid + "&");
                        elookup[o.uid] = format;
                    }
                } else {
                    // we should not be handling motionbox videos going forward
                    hasMbx = true;
                }
            });
            // create the callback
            var cb = {
                onSuccess: function(d, udata) {
                    var vlookup = lookup, cbs = callbacks, el = elookup;
                    encodingProgressSuccess(cbs, vlookup, el, d, udata);
                },
                onTimeout: function(d, udata){
                    var cbs = callbacks;
                    if (cbs.onTimeout) cbs.onTimeout(d, udata);
                },
                onError: function(msg, url, line, udata){
                    var cbs = callbacks;
                    if (cbs.onError) cbs.onError(msg, url, line, udata);
                }
            };
            if (hasMbx) {
                // Console.write("Motionbox videos are no longer supported.");
                    if(callbacks && callbacks.onError) callbacks.onError("APi operation not compatible", "", "", options.userData);
            } else {
                // we need to make the call.
                var key = CentralDispatch.getNextKey();
                var url = S360.Client.getS360Url("encodeProgress", null, key);
                var edata = escape( search.join("") + "custom_format=shutterfly&");
                url += "data=" + edata;
                CentralDispatch.requestData2(url, key, cb, options);
            }
        };

        return klass;
    } ();
    
    MBX_new.Player = function () {
        var klass= {};
        // get the embed for the video
        klass.embedFor = function(videoid, videotoken, format, options) {
            if (isS360(videotoken)) {
                var id = options.id || CentralDispatch.getNextKey(), item = options.item;
                var thumb = "", width = options.width, height = options.height || 200, encoding = false;
                if (item) {
                    thumb = item.thumbnail;
                    encoding = (thumb)? false: true;
                    if(item.status && item.status == "encoding")encoding = true;
                }
                var pubId = MBX_new.Video.getPublishingId(videotoken, format);
                var mouseover="MBX.Player.swapPlay(this, false);";
                var mouseout="MBX.Player.swapPlay(this, true);";
                var imgTag = "<img src='" + VideoApiConfig.playGif[0] + "' " +
                                (options.lazyLoad) ? ("onmouseout=\"" + mouseout + "\" " +
                                    "onmouseover=\"" + mouseover + "\" ") : "" +
                                "style='vertical-align:middle; text-align:center;'/>";
                var startDiv = "<div id='s360-embed-" + id + "' style='position: relative;' >";
                //lets calculate the position of the play button
				// reduce the play button to 61
                var pos = parseInt( ((height/2) - 61) + "");
                var arr = [
                ,   "<div id='s360-embed-" + id + "' style='position: relative;text-align:center;'>"
                ,       "<img id='mx-item-img-" + id + "' src='", thumb, "' "
                ,           " style='max-width:", width, "px;max-height:", height, "px;"
                ,           "position:relative; border:0;background-image:url(" , VideoApiConfig.progressGif , ");"
                ,           "background-repeat:no-repeat;background-position:center;'/>"
                ,       "<div onclick=\"MBX.Player.swapNode('" + id + "','" + pubId + "'," + width + "," + height + ");\" "
                ,               "style='cursor: pointer; position: absolute; left: 0px; top: " + pos + "px; height: 70px; width:", width, "px; text-align:center'>"
                ,           "<a href=\"#\" >"
                ,               "<img src='" + VideoApiConfig.playGif[0] + "' onmouseout=\"" + mouseout + "\" onmouseover=\"" + mouseover + "\" style='vertical-align:middle; text-align:center;'/>"
                ,           "</a>"
                ,       "</div>"
                ,   "</div>"];
                var enc = [
                ,   "<div id='s360-embed-" + id + "' style='position: relative;background-color:#060606;height: " + height + "px;width:" +width  + "px;'>"
                ,       "<div style='position: absolute; left: 0px; top: " + pos + "px; height: 70px; width:", width, "px; text-align:center'>"
                ,           "<img id='mx-item-img-" + id + "' class='thumb-poster' src='", VideoApiConfig.progressGif, "' "
                ,               " style='width:66px;height:66px;position:relative; border:0;'/><div style='height: 20px;'></div>"
                ,           "<span style='display:block; color:#D0D0D0;font-weight:bold;'>Processing video please wait.</span>"
                ,       "</div>"
                ,   "</div>"];
                if (encoding) return enc.join("");
                else return arr.join("");
            } else {
                return MBX_old.Player.embedFor(videoid, videotoken, format, options);
            }
        };
        klass.swapPlay = function(img, mouseout) {
            if (mouseout) {
                img.src = VideoApiConfig.playGif[0];
            } else {
                img.src = VideoApiConfig.playGif[1];
            }
        };
        
        klass.swapNode = function(id, pubId, width, height) {
            // make sure that there is no item in the dom with the same name
            var ele = document.getElementById(pubId);
            if(ele) {
                ele.id = pubId + "-" + new Date().getTime();
            }
            var embed = "<a href=\"#\" onclick=\"return(false);\" rel=\"videoGUID=" + pubId + "&\" "+
            "style=\"display:block;width:" + width + "px;height:" + height + "px; "+
                "background-image:url(" + VideoApiConfig.progressGif + ");"
                + "background-repeat:no-repeat;background-position:center;"
                + "background-color: #060606; \" "
                + " id=\"" + pubId + "\" "+
            "width=\"" + width + "\" height=\"" + height + "\" ></a> ";
            var img = document.getElementById("s360-embed-" + id);
            img.innerHTML = embed;
            var element;
            element = document.createElement('script');
            element.src = VideoApiConfig.embed.replace("PUBID", pubId);
            document.body.appendChild(element);
        };
        
        return klass;
    } ();
    
    
    MBX_new.Thumbnail = function () {
        var klass = {};
        
        function handleMigration(){
        
        };
        
        // gets the thumbnail for the video
        klass.urlFor = function(videoid, videotoken, asset) {
            // asset is always 'thumbnail'
            var thumb = "";
            if (isS360(videotoken)) {
                // we should already have the url, but unfortunately we don't have it, so we might want to make a call back
                // to get the mapping and in turn call the function which needs to be triggered once the mapping found
                S360.Migration.migrateVideo(videoid, videotoken, {onSuccess: handleMigration});
            } else {
                thumb = MBX_old.Thumbnail.urlFor(videoid, videotoken, 'thumbnail');
            }
            return thumb;
        };
        
        return klass;
    } ();
    
    MBX_new.Client = function () {
        var klass = {};
        
        klass.setTimeout = function(value) {
        };
        
        return klass;
    } ();
    
})();

