if (!window.Presto) {
    var Presto = {};
}

Presto.OnDemand = {

    queue: [],

    pending: null,

    checkCondition: function() {

        var p = this.pending, self = this;
               
        var requestComplete = function() {
            
            if(!p.requestCompleted){

                if (p.callback) {
                    var arr = [p.url];
                    if(p.args) {
                        for(var i=0; i< p.args.length; i++) {
                            arr.push(p.args[i]);    
                        }
                    }
                    p.callback.onSuccess.apply(p.callback.scope, arr);
                }

                p.requestCompleted = true;
            }
            if(self.queue.length > 0) {
                var req = self.queue.shift();
                self.requireScript(req.url, req.callback, req.condition, req.args);
            }
        };

        if (p.condition && typeof p.condition == 'function') {

            if (!p.condition()) {

                var elapsed = 1000;
                var interval = setInterval(function() {
                    //console.log(p.condition()+' check '+p.url);
                    if (p.condition()) {
                        clearInterval(interval);
                        requestComplete();
                    }
                    else {
                        elapsed += 1000;
                        if (elapsed > 30000) {
                            clearInterval(interval);
                            if (p.callback) {
                                clearInterval(interval);
                                p.callback.onFailure.apply(p.callback.scope, ['30 second timed out.']);
                            }
                        }
                    }
                }, elapsed);

            } else {
                requestComplete();
            }
        } else {
            requestComplete();
        }
    },
    matchUrl: function(url, otherUrl){
           
           if(url && otherUrl){
               function endsWith(src, pattern) {
                   var d = src.length - pattern.length;
                   return d >= 0 && src.lastIndexOf(pattern) === d;
               }
               if(/(http|https):\/\//.test(url)){
                   
                   // then we need to check we're not trying to load a script 
                   // from another hub
                   
                   // trim off the ip address
                   var relUrl = url.substring(url.indexOf('//')+2);
                   relUrl = relUrl.substring(relUrl.indexOf('/'));
                   
                   if (endsWith(otherUrl, relUrl)) {
                       return true;
                   }         
               }
               if (endsWith(otherUrl, url)) {
                   //console.log(url + ' script already exists.. skipping');
                   return true;
               } 
            }
            return false;
        },
    requireScript: function(url, callback, condition) {

        var self = this;

        var request = {
            url: url,
            callback: callback,
            condition: condition,
            args: Array.prototype.slice.call(arguments, 3)
        };

        if (this.pending && !this.pending.requestCompleted) {
            //console.log('queue '+url);
            this.queue.push(request);
            return;
        }

        this.pending = request;

        //console.log('load '+url);
        if(condition)condition();
            
        var scripts = document.getElementsByTagName('script');
        var found = false;
        if (scripts) {
            for (var i = 0; i < scripts.length; i++) {

                if (this.matchUrl(url, scripts[i].src)) {
                    found = true;
                    break;
                } 
            }
        }

        if (!found) {
            //console.log(url + ' script loading');
            var p = this.pending;

            var script = document.createElement('script');
            script.setAttribute('type', 'text/javascript');
            if (p.callback || p.condition) {

                script.onreadystatechange = function(response) {

                    // jcp :
                    // notice on IE, when we refresh, we might only see complete event
                    // also, setting handler to null doesnt prevent complete and loaded events
                    // coming through, may need to delete function.

                    if (this.readyState == "loaded" || this.readyState == 'complete') {
                        this.onreadyStateChange = null;
                        self.checkCondition();
                    }
                };
                // Firefox
                script.onload = function(response) {
                    script.onload = null;
                    self.checkCondition();
                };
            }
            var head = document.getElementsByTagName('head')[0];
            var insert = head.appendChild(script);
            script.src = p.url;
        }
        else {
            self.checkCondition();
        }
    },

    requireCSS: function(url, callback) {
        var links = document.getElementsByTagName('link');
        var found = false;

        if (links) {
            for (var i = 0; i < links.length; i++) {

                if (this.matchUrl(url, links[i].href)) {
                    found = true;
                    break;
                } 
            }
        }
        if (!found) {
            var link = document.createElement('link');
            link.setAttribute('type', 'text/css');
            link.setAttribute('rel', 'stylesheet');
            // @todo: <link> does not have the onload property like <script> .. hence callback is not possible
            var head = document.getElementsByTagName('head')[0];
            var insert = head.appendChild(link);
            link.href = url;
            if (callback) {
                callback.onSuccess();
            }
        } else {
            if (callback) {
                callback.onSuccess();
            }
        }
    }

};

/* Jacob Derechin */
//// RB (return blank) function returns "" if the parameter is undefined or null if not it returns the same value that was recieved
///**
// * @private
// */
//function RB(a)
//{
//return  ( typeof(a) !="undefined" && !!a)?a:""
//}
//// INB (if not blank) function return "" if the second parameter is null if not null it returns the concatenation of the first second and third parameter
///**
// * @private
// */
//function INB(a,b,c){
//b=RB(b);
//return (!!b&&b.length>0)?RB(a)+b+RB(c):""
//}
////BVL (blank value) if the first parameter is "" or null then it return the second value
///**
// * @private
// */
//function BVL(a,b)
//{
//    return (RB(a)=="")?b:a
//}
/* finished modification*/

if (!window.Ema) {
/**
 * @namespace  Namespace for the Enterprise Mashlet API for Presto. 
 */
    var Ema = {

       /**
        * @private
        */
        containers: {},

       /**
        * @private
        */
        prestoConnection: null,

       /**
        * @private
        */
        isReady: false,

       /**
        * @private
        */
        debug: function(msg) {
            //        console.log(msg);
        },
       /**
        * @private
        */
        getMashlet:function(property, value) {
            var resultArr = [];
            for (var cnt in Ema.containers) {
                for (var msh in Ema.containers[cnt].mashlets) {
                    if (Ema.containers[cnt].mashlets[msh][property] == value) {
                        resultArr.push(Ema.containers[cnt].mashlets[msh]);
                    }
                }
            }
            return resultArr;
        },

       /**
        * Declares a namespace to use in mashlet types.
        * @param {String} name  The namespace, in JavaScript dot notation, to declare.
        * @example
        * Ema.namespace('MyPackage'); 
        * MyPackage.MyMashlet = function(); 
        */
        namespace : function() {
            //Presto.namespace(arguments[0]);
            var a = arguments, o = null, i, j, d, rt;
            for (i = 0; i < a.length; ++i) {
                d = a[i].split(".");
                rt = d[0];
                eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
                for (j = 1; j < d.length; ++j) {
                    o[d[j]] = o[d[j]] || {};
                    o = o[d[j]];
                }
            }
        },

        /**
        * @private
        */
        getContainer: function(serverUrl, resourcesBase, callback) {

            //        console.log('get mashlet container ' + serverUrl);

            if (!serverUrl) {
                serverUrl = "";
            }

            if (!resourcesBase) {
                resourcesBase = serverUrl + "/static";
            }
            var server = serverUrl || 'local';
            // we load the resources from the Container. The assumption is that
            // all Servers have the same version of these resources and hence they need to be
            // loaded only once
            Presto.OnDemand.requireCSS(resourcesBase + '/mashlet/css/mashlet.css');

            var condition = function() {
                return (window.Presto && Ema && Ema.Container);
            };

            Presto.OnDemand.requireScript(resourcesBase + '/mashlet/js/mashlet-core.js', {
                onSuccess:function() {

                    var container = this.containers[server];
                    var mashletsConfig = null;

                    if (!container) {
                        //console.log("Creating a new Container");
                        container = new Ema.Container(serverUrl, resourcesBase, mashletsConfig);
                        this.containers[server] = container;

                    }
                    // REAP 3903
                    Presto.OnDemand.requireScript(serverUrl + "/mashlets/loadconfig.jsp?server=" + server, {
                        onSuccess: function() {
                            //console.log('loadconfig SUCCESS');
                            callback.onSuccess.apply(callback.scope || window, [this.containers[server]]);
                        },
                        onFailure: function(err) {
                            //console.log('loadconfig FAILED - ');
                            //console.log(err);
                            callback.onFailure.apply(callback.scope || this, [err]);
                        },
                        scope: this
                    }, function() {
                        return(Ema.containers[server].mashletsConfig);
                    });

                },

                onFailure: function(err) {
                    callback.onFailure.apply(callback.scope || this, [err]);
                },

                scope: this

            }, condition);

        },


       /**
        * Dynamically loads the mashlet instance identified in the configuration parameter. Loading mashlets 
        * allows you to control when mashlet instances are rendered and also allows you to pass parameters
        * dynamically.
        * @param {Object} config  A configuration parameter that identifies the mashlet instance to
        *                         load plus any parameters to initialize the mashlet. This object contains
        *                         the following properties:
        * @config {String} name  The mashlet instance name to load. 
        * @config {String} el  The ID of the target DOM node where the mashlet instance should be rendered.
        * @config {String} serverUrl  An optional property for the URL to the application server that 
        *                             hosts the Mashlet Framework for this mashlet instance. If omitted, 
        *                             defaults to "".
        * @config {String} resourceBase  An optional property to identify the relative URL to shared 
        *                                Presto resources used by the Mashlet Framework. If omitted, this
        *                                defaults to /static. 
        * @config {Object} callback  An optional property in the form { onSuccess:, onFailure:, scope:} 
        *                            that is the callback to use to handle errors from the load function
        *                            or post-load actions. If omitted, successful loads do nothing further, 
        *                            failures are logged to the console, and the scope is the mashlet
        *                            container.
        * @config {Object} args  An optional object with properties that should override mashlet instance
        *                        preferences. You can define new properties in this object, but they are 
        *                        not persisted with mashlet preferences. 
        * @example
        * Ema.load(
        *          {serverUrl: 'http://myserver:myport/', 
        *           el: 'target1',
        *           name: 'HelloWorld.Mashlet',  
        *           args: {helloString: 'My Hello World String'}, 
        *           callback: onSuccess: function(mashletInstance) { ... }, 
        *                     onFailure: function(e) { alert('could not load mashlet...');}, 
        *                     scope: this)} 
        *         );
        */
        load: function(config) {

            //config.preferences is private
            if (!(config.name || config.preferences)) {
                throw new Error('Ema.load() requires either "name" or "preferences" to load the Mashlet');
            }
            if (!config.serverUrl) {
                config.serverUrl = "";
            }

            Ema.getContainer(config.serverUrl, config.resourcesBase, {
                onSuccess: function(container) {
                    //console.log('container loaded');
                    //console.log(container);

                    container.load(config);
                },
                onFailure: function(err) {

                    throw new Error(err);
                },
                scope: this
            });


        },

       /**
        * @private
        */
        publishEvent: function(eventId) {

            var args = [];
            for (var i = 1; i < arguments.length; i++) {
                args.push(arguments[i]);
            }

            for (i = 0; i < this.containers.length; i++) {

            }
            this.fireEvent(eventId, args);

        }

    };
}

