var _log = function(level, msg) {
    if(console.log)
        console.log("[" + String(level) + "] " + String(msg));
};
var log = {
    'error': function(msg) { _log('error', msg); },
    'info' : function(msg) { _log('info', msg); }
};

var kEscKey = 27;

/* Array Remove */ 
Array.prototype.remove = function(from, to) {
    var rest = this.slice((to || from) + 1 || this.length);
    this.length = from < 0 ? this.length + from : from;
    return this.push.apply(this, rest);
};


/* main IQE namespace */
var IQE = {};
IQE.applyDecorator = function(el, obj) {
    /* make a new instance of the decorator for the element, apply it */
    if(typeof(obj) != "function") {
        log.error("second argument must be a function declaration");
        return;
    }
    var o = new obj();
    $(_.bind(o.init, o, el));
};
IQE.applyDecoratorForClass = function(cls, obj) {
    if(arguments.length != 2) {
        log.error("We need a classname and a function decl!");
        return;
    }
    if(typeof(cls) != "string") {
        log.error("first argument must be a classname");
        return;
    }
    log.info("applying decorator to class " + cls);

    $("." + cls).each(function(i, el) {
        IQE.applyDecorator(el, obj);
    });
};
IQE.local_redir = function(loc_obj, params) {
    if(typeof(params) != typeof({}))
        var new_loc = loc_obj.toString();
    else {
        // construct the new loc w/ the passed-in params
        var new_loc = loc_obj.pathname;
        var args = _.reduce(_.map(_.keys(params), function(a) { return String(a) + "=" + String(params[a]); }),
                        function(a,b) { 
                            return (a.length > 0 ? String(a) + "&" + String(b) : String(b));
                        }, "");
        new_loc += "?" + args;
        if(loc_obj.hash.length > 0)
            new_loc += "#" + loc_obj.hash;
    }
    log.info("redirecting to " + String(new_loc));
    window.location = new_loc;
};

IQE.currentApiKey = _.memoize(function() {
    if($("#IQ_current_apikey_val").length > 0)
        return $("#IQ_current_apikey_val").val();
    return null;
});

IQE.getCookie = function(name) {
    /*
    lifted from https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/
    */
    var cookieValue = null;
    if (document.cookie && document.cookie != '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
          var cookie = jQuery.trim(cookies[i]);
          // Does this cookie string begin with the name we want?
          if (cookie.substring(0, name.length + 1) == (name + '=')) {
            cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
            break;
          }
        }
    }
    return cookieValue;
}
IQE.getIQETimestamp = function() {
    // This functions contstructs 
    // a valid timestamp for the IQEngines
    // Api.
    var t = new Date(),
        formatted = String('0000' + t.getUTCFullYear()).slice(-4)   + 
                    String('00'   + (t.getUTCMonth()+1)).slice(-2)  + // plus 1 because months are 0 indexed in js
                    String('00'   + t.getUTCDate()).slice(-2)       +
                    String('00'   + t.getUTCHours()).slice(-2)      +
                    String('00'   + t.getUTCMinutes()).slice(-2)    +
                    String('00'   + t.getUTCSeconds()).slice(-2)    ;
    return formatted;
};
IQE.doAjax = function(url, params) {
    /*
     * setup the ajax call, passing any state-specific parameters as well
     */
    if(!_.isObject(params))
        if(_.isObject(url))
            params = url;
        else
            params = {};

    if(_.isString(url))
        params['url'] = url

    if(!_.isObject(params['data']))
        params['data'] = {};

    if(IQE.currentApiKey() != null)
        params['data']['ak'] = IQE.currentApiKey();

    if(IQE.getCookie('csrftoken') != null) {
        if(!_.isObject(params['headers']))
            params['headers'] = {}
        params['headers']['X-CSRFToken'] = IQE.getCookie('csrftoken');
    }

    log.info("making an ajax call to " + String(url));
    $.ajax(params);
};

var ApikeyReloader = function() { _.bindAll(this); };
ApikeyReloader.prototype = {
    menuEl : null,
    displayEl : null,
    isShown : false,
    init : function(el) {
        this.menuEl = $(el).find(".menu").first();
        this.displayEl = $(el).find(".anchor").first();

        this.displayEl.children().wrap("<a href=''></a>");
        $(document).keypress(this.handleKeypress);
        $("body").click(this.handleGlobalClick);

        this.wrapPageHeader(el);
        this.positionMenu();

        this.displayEl.on('click', 'a', this.doMenuToggle);
        this.menuEl.on('click', 'a', this.doKeyChanged);

        $(el).show();
    },
    handleGlobalClick : function(e) {
        if(!(this.isInElement({x:e.pageX, y:e.pageY}, this.menuEl) ||
                    this.isInElement({x:e.pageX, y:e.pageY}, this.displayEl)))
            this.doHideMenu();
    },
    isInElement : function(coord, el) {
        var j_el = $(el);
        return (coord.x > j_el.offset().left) &&
                (coord.x < j_el.offset().left + j_el.outerWidth()) &&
                (coord.y > j_el.offset().top) &&
                (coord.y < j_el.offset().top + j_el.outerHeight());
    },
    handleKeypress : function(e) {
        if(e.keyCode == kEscKey)
            this.doHideMenu();
    },
    wrapPageHeader : function(switcher) {
        var hdr = $("#IQ_contentbody .page-header").first();
        if(hdr != "undefined") {
            $("body").append($(switcher).detach());
            var x = hdr.offset().left + hdr.width() - $(switcher).width() - 20;
            var y = hdr.offset().top;
            $(switcher).css({'position':'absolute'});
            $(switcher).offset({left:x, top:y});
            $(hdr).css({'padding':'0 ' + String($(switcher).outerWidth(true)) + 'px 0 0'});
        } else {
            log.error("couldn't find header!");
        }
    },
    positionMenu : function() {
        var x = this.displayEl.outerWidth() - this.menuEl.outerWidth();
        this.menuEl.css({'left':String(x) + "px"});
    },
    doMenuToggle : function(e) {
        e.preventDefault();
        if(this.isShown) {
            this.doHideMenu();
        } else {
            this.doShowMenu();
        }
    },
    doHideMenu : function() {
        this.menuEl.hide();
        this.displayEl.removeClass('open');
        this.isShown = false;
    },
    doShowMenu : function() {
        this.menuEl.show();
        this.displayEl.addClass('open');
        this.isShown = true;
    },
    doKeyChanged : function(e) {
        log.info("got apikey change");
        e.preventDefault();
        var key_re = RegExp("\\bJ_key_([\\S]+)\\b");
        var el = e.target;
        var varvalue = null;
        while(el.tagName.toUpperCase() != "body" && varvalue == null) {
            if(key_re.test($(el).attr('class'))) {
                varvalue = key_re.exec($(el).attr('class'))[1];
            } else {
                el = $(el).parent()[0];
            }
        }

        if(varvalue == null || varvalue.length < 1) {
          log.error("couldn't extract param name from element " + String(e.target));
          return false;
        }
        log.info("varvalue: " + varvalue);
        var params = {
          'ak': String(varvalue)
        };
        this.doHideMenu();
        IQE.local_redir(window.location, params);
    }
};

var UTF8 = {

    // public method for url encoding
    encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    },

    // public method for url decoding
    decode : function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;

        while ( i < utftext.length ) {

            c = utftext.charCodeAt(i);

            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            }
            else if((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i+1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else {
                c2 = utftext.charCodeAt(i+1);
                c3 = utftext.charCodeAt(i+2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        }

        return string;
    }

}
    

