/**

  Javascript localization functions. The basic principle is that perl does all the work and this is just a light interface with some caching to that.

  var myLocalize = new Localize(languangesArray, bundlesArray);
 
  // or set them after the constructor

  myLocalize.language = ["en"]; 
  myLocalize.bundles = ["common"]; 

  */


Localize = Class.create();

Localize.counter = 0;

Localize.prototype = {
    joinKey : "~`",
    logger : console.log,
    url : "/mpc/ajax_localize.pl",
    cgi : new CGI(""),
    languages : new Array(),
    bundles: new Array(),
    options: {},
    /* 
       the constructor
       */
    initialize: function(languages,bundles,callBack,options){
        this.languages = languages;
        this.bundles = bundles;
        Object.extend(this.options,options);
        this.clearResponders();
        this.cache = new Hash();
        if(this.options.lexicon){
            this.handleServerCacheJSON(this.options.lexicon);
        }else{
            this.getCache(callBack);
        }
    },
    getCache: function(callBack){
        var me = this;
        if(callBack == undefined){
            callBack = function(){};
        }
        var cgi = this.populateCGI();
        cgi.all=true;
        var myAjax = new Ajax.Request(
            this.url, 
            {
                parameters: cgi.toQueryString(),
                method: 'post', 
                onComplete: function(response){me.handleServerCache(callBack,response)},
                onExcpetion: console.log
            }
        );
    },
    handleServerCache: function(callBack,response){
        var result = eval("(" + response.responseText + ")");
        this.handleServerCacheJSON(result);
        callBack();
    },
    handleServerCacheJSON: function(json){
        for (var key in json) {
            var text = json[key];
            this.saveResultToCache(text,this.getKey(key,[]));
        }
    },
    /*
       internal function for clearing responders. This means the next request that gets sent out will not have all of the old requests in it still
       */
    clearResponders: function(){
        var me = this;
        var oldResponders = this.responders;
        var oldKeys = this.keys;
        this.responders = new Hash();
        this.keys = new CGI("");
        if(oldResponders != undefined){
            oldResponders.each(function(pair){
                var key = pair.key;
                if(!me.result[key]){
                    me.responders[key] = oldResponders[key];
                    me.keys[key] = oldKeys[key];
                }
            });
        }
    },
    /*
       create the internal cgi object that is responsible for setting the post parameters of the ajax call
       */
    populateCGI: function(){
        var cgi = new CGI("");
        cgi.keys = this.keys.toQueryString();
        cgi.joinKey = this.joinKey;
        cgi.languages = this.languages;
        cgi.bundles = this.bundles;
        return cgi;
    },
    /*
       our unique key for a string
       */
    getKey: function(phrase,variables){
        return phrase + this.joinKey + this.variablesToString(variables);
    },
    
    /**
      utility function for alerts
      */
    alert: function(phrase,variables){
        var f1 = function(text){
            alert(text);
        }
        this.prepareAndSend(phrase,variables,f1);
    },
    log: function(phrase,variables){
        var me = this;
        var f1 = function(text){
            me.logger(text.toString());
        };
        this.prepareAndSend(phrase,variables,f1);
    },
    say: function(phrase,variables,callBack){
        if(callBack == undefined){ callBack = function(){}};
        var string = this.prepareString(phrase,variables);
        if(!this.__lastResponseDone){
            this.sendRequest(callBack);
        }
        if(string.__done){
            return string.value;
        }
        return string;
    },
    /** 
       utility function for setting up and requesting
       */
    prepareAndSend: function(phrase,variables,object,accessor){
         this.prepare(phrase,variables,object,accessor);
         this.sendRequest();
    },
    /* 
       this is our main function
       */
    prepare: function(phrase,variables,object,accessor){
        var me = this;
        var key = this.getKey(phrase,variables);
        if(object == undefined){
            object = new Object();
        }
        var responder;
        if( typeof object != "function"){
            object.__localizationAccessor = accessor;
            responder = function(text,key){ 
                me.__objectResponderFucntion.call(object,text,key);
            }
        }
        else{
            responder = object;
        }
        var cached = this.cache[key];
     
        this.__lastResponseDone = false;
        if(cached == undefined){
            if(this.responders[key]){ //We already have a request for this key the responder needs to be appended though
                this.responders[key] = function(text,key){ 
                    this.responders[key](text,key);
                    responder(text,key);
                }
            }
            else{
                this.responders[key] = responder;
            }
            this.keys[key] = true;
        }
        else{
            responder(cached,key);
            this.__lastResponseDone = true;
        }
        return key;
    },
    variablesToString: function(variables){
        if(variables == undefined || variables.length == 0){
            return undefined;
        }
        return variables.join(this.joinKey);
    },
    /**
      bound to the object passed to prepare  not to the localization object.
      This is a responder function where an object is passed rathe than a callback function. 
      We are basically trying to guess what the callback should be.
      */
    __objectResponderFucntion: function(text,key){
        //use the accessor if we have it
        if(this.__localizationAccessor != undefined){
            this[this.__localizationAccessor] = text;
        }
        //try to set the object as best we can
        else if(this.value != undefined){
            this.value = text;
        }
        else if(this.innerHTML != undefined){
            this.innerHTML = text;
        }
        else if(this.textContent != undefined){
            this.textContent = text;
        }
        else{
            this.value = text; //not the best default???
        }
    },
    /*
       Send the request (If needed) back to the perl side
       */
    sendRequest: function(callBack){
        var me = this;
        if(callBack != undefined){
            this.callBack = callBack;
        }
        if(this.sendingRequest){
            var oldCallBack = this.callBack;
            this.callBack = function(){
                me.sendRequest(function(){});
                oldCallBack();
            }
            return;
        }
        if(this.callBack == undefined){
            this.callBack = function(){};
        }
        if(this.responders == undefined || $A(this.responders).length == 0){
            this.clearResponders(); //mainly for clearing the variables and phrases
            this.callBack();
            return; // nothing to do
        }
        var cgi = this.populateCGI();
        this.sendingRequest = true;
        var myAjax = new Ajax.Request(
            this.url, 
            {
                parameters: cgi.toQueryString(),
                method: 'post', 
                onComplete: function(response,json){ me.handleResponse(response,json) }
//                onExcpetion: console.log
            }
        );
    },
    /**
     handle the response from the ajax call 
    */
    handleResponse: function(request){
        this.result = eval("(" + request.responseText + ")");
        for (var key in this.result) {
            var text = this.result[key];
            try{
                this.responders[key](text,key);
            }
            catch(e){
//               console.log(e);
            }
            this.saveResultToCache(text,key);
        }
        this.clearResponders();
        this.sendingRequest = false;
        this.callBack();
    },
    /*
       for a given piece of text save it to the cache. To do this we have to look it its phrase and variables again
       */
    saveResultToCache: function(text,key){
       try{
            this.cache[key] = text;
        }
        catch(err){
//            console.log(err);
            throw err;
        }
    },
    /*
       Utility function that returns a text node that will be populated upon sendRequest
       */
    node: function(phrase, variables){
        var node = document.createTextNode("");
        var f1 = function(text){
            node.textContent = text;
        }
        this.prepare(phrase,variables,f1);
        return node;
    },
    /**
      Returns a mock string object which will be populated upon sendRequest. 
      
      !!!!!!!!!!!!!!!!!!!!!!!
      
            THIS DOES NOT WORK WITH "+" CONCATINATION   !!!!!!

      !!!!!!!!!!!!!!!!!!!!!!!

      */
    prepareString: function(phrase, variables){
        var string = new String("Dont Concatinate Me!!!!!");
        string.value = phrase;
        string.toString = function(){return string.value};
        this.prepare(phrase,variables,function(text){string.__done = true; string.value = text});
        return string;
    }
};
