/**
 * @fileOverview noovo.js defines NOOVO namespace together with utility functions and a few often used controls.
 */
var NOOVO;
if (!NOOVO) {
    NOOVO = {'widgets':{}, 'vote': {}, 'effects': {}};
}

// This constant should be automatically set on deployment
// this should be included in the template
$.media_url = MEDIA_URL;
$.fck_media_url = FCK_MEDIA_URL;

/**
  * @class
  * The util utility provides commonly needed functions for handling DOM
  * and basic RPC.
  * @constructor
  */
NOOVO.util = function () {
    return {

        _equalHeight: function (lp, force) {
            var p = $("#primary");
            var s = $("#secondary");

            var pimg = $("#primary img, #secondary img");
            var loaded = true;
            var loop = (typeof lp == 'number') ? lp : 300;

            for (var i = 0; i < pimg.length; i++) {
                if (!pimg[i].complete) {
                    loaded = false;
                    break;
                }
            }

            if ((!loaded || force) && loop > 0)  {
                setTimeout(function () { NOOVO.util._equalHeight(loop - 1, force); }, 500);
            }

            if (p.length && s.length) {
                p.height("auto");
                s.height("auto");

                var pH = p.height(), sH = s.height();
                var pT = p.css("paddingTop"), pB = p.css("paddingBottom"), sT = s.css("padding-top"), sB = s.css("padding-bottom");
                pT = parseInt(pT, 10);
                pB = parseInt(pB, 10);
                sT = parseInt(sT, 10);
                sB = parseInt(sB, 10);

                if (pH+pT+pB > sH+sT+sB) { s.height(pH+pT+pB-sT-sB); }
                else { p.height(sH+sT+sB-pT-pB); }
            }
        },

        /**
         * Check if element has a given class
         *
         * @name hasClass
         * @function
         * @memberOf NOOVO.util
         * @param {HTMLElement}
         * @param {String} Class name
         * @return {Boolean}
         */
        hasClass: function (elm, cls) {
            return $(elm).hasClass(cls);
        },

        /**
         * Close all open menus.
         *
         * @name closeMenus
         * @memberOf NOOVO.util
         * @function
         * @private
         */
        _closeMenus: function () {
            $("#filter-pick li").removeClass("active");
            $(".useroptions ul").addClass("noshow");
            $("span.discover small").addClass("noshow");
        },

        /**
         * Toggle visibility of editor console
         *
         * @name showHide
         * @function
         * @memberOf NOOVO.util
         */
        showHide: function () {
            /*
            function toggle() {
                $("#"+this.did).toggleClass("noshow");
                return false;
            }

            var elements = $(".expand").each(function (i) {
                var div_id = this.id.replace("a_", "");
                $(div_id).addClass("noshow");
                this.onclick = toggle;
                this.did = div_id;
            });*/
        }
    };
}();

/**
  * @class
  * The RPC part of util class.
  * @constructor
  */
NOOVO.util.RPC = function () {
    return {
        /**
         * Make XHR call
         *
         * @name call
         * @function
         * @memberOf NOOVO.util.RPC
         * @param {String} URL to call
         * @param {String} Call name
         * @param {Object} Arguments
         * @param {String} Function to handle event
         * @param {Boolean} True for POST requests
         */
        call: function ( url, method, args, ok_cb, post ) {
            var d = new Date();
            var seed = d.getTime();

            var host = "";
            if (document.location.host) {
                host = document.location.host;
            } else {
                if (document.location.hostname) {
                    host = document.location.hostname;
                }
            }
            var newurl = "http://"+host+"/services/rest/?rtype=json&iecache="+seed;
            var type= (post) ? "POST" : "GET";

            newurl += url;

            if (type === "POST") {
                args.csrfmiddlewaretoken = CSRF_TOKEN;
                $.post(newurl, args, ok_cb);
            } else {
                $.get(newurl, args, ok_cb);
            }
        }

    };
}();

/**
  * @class
  * Rich-text editor. Creates a widgEditor instance.
  * @constructor
  */
NOOVO.Editor = function () {
    var loaded = false;
    var editor = null;
    var richEditor = null;

    return {
        type : "inline",
        /**
         * Load necessary Javascript and stylesheets needed for rich text editor.
         *
         * @name load
         * @function
         * @memberOf NOOVO.Editor
         */
        load : function () {
            if (this.loaded) { return; }
            if (typeof(document.designMode) === "string" && (document.all || document.designMode === "off")) {
                $.getScript($.fck_media_url + 'fckeditor/fckeditor.js');
            }

            this.loaded = true;
        },
        /**
         * Create editor instance
         *
         * @name create
         * @function
         * @memberOf NOOVO.Editor
         * @param {HTMLElement}        Element that will be replace with editor
         */
        create : function (el, typ) {
            this.editor = null;

            var editor;

            var block_tags = {"p":1, "div":1};
            var tagname = (el) ? el.tagName.toLowerCase() : "div";
            var elm;
            this.oldValue = (el) ? el.innerHTML : "";
            if (typ === 'location') {
                var plval = [];
                $.each(["location"], function () {
                    plval.push($("span."+this, el).text());
                });
                editor = $('<form id="inline-editor"><ul class="captionvalue">'+
                    '<li><strong class="caption">'+gettext('Location')+'</strong><input type="text" id="id_city_tmp" value="'+plval[0]+'" />'+
                        '<a class="linkAdvanced" style="float:none;">'+gettext('Advanced')+'</a></li>'+
                    '<li><div id="id_location_container">'+
                        '<div class="geoSearch geoInline">'+
                            '<div class="selectedLocationInfo"></div>'+
                            '<ul class="tabnav"></ul>'+
                            '<div class="geoSearchForm">'+
                                '<div class="searchContainer">'+
                                '<div class="input">'+
                                    '<input type="text" style="width:140px;" />'+
                                    '<button>'+gettext("Search")+'</button>'+
                                '</div>'+
                                '<div class="input">'+
                                    '<input type="text" style="width:140px;" />'+
                                    '<span class="position"></span>'+
                                '</div>'+
                                '<p class="instructions"></p>'+
                                '<ol class="results"></ol>'+
                                '<button>'+gettext("Set Location")+'</button>'+
                            '</div>'+
                            '<div class="map" id="geosearch_map_0"></div>'+
                        '</div>'+
                    '</div>'+
                '</div></li>'+
                '</ul></form>')[0];
                NOOVO.Editor.type = "location";
            } else if (typ == 'tag') {
                editor = document.createElement("span");
                elm = document.createElement("input");
                elm.id = 'input-editor';
                elm.type = 'text';

                var obj = NOOVO.Inline._getObject(el);
                var data = "method=core.getFieldValue&mid="+obj.id+"&field="+obj.field;

                $.getJSON("/services/rest/?rtype=json", data, function (response) {
                    elm.value = response.value;
                });

                $(elm).bind("keypress keydown", function (ev) {
                    if (ev.keyCode == 13) {
                        $(elm).parent().find("button[value=Save]").trigger("click");
                        return false;
                    }
                });

                NOOVO.Editor.type = "inline";
            }
            else if (tagname in block_tags) {
                editor = document.createElement("form");
                elm = document.createElement("textarea");
                elm.id = "textarea-editor";
                if (typeof(document.designMode) === "string"
                        && (document.all || document.designMode === "off")
                        && !$(el).hasClass("plain_editor")) {
                    // designMode exists
                    $('<input type="hidden" name="editor_unescape" value="true" />').appendTo($(editor));
                    elm.className = "widgEditor";
                    var obj = NOOVO.Inline._getObject(el);
                    var data = "method=core.getFieldValue&mid="+obj.id+"&field="+obj.field;

                    $.getJSON("/services/rest/?rtype=json", data, function (response) {
                        if (elm.instance) {
                            elm.instance.SetHTML(response.value);
                        } else {
                            elm.value = response.value;
                        }
                    });
                } else {
                    elm.value = this.dom2txt(this.oldValue);
                }
                NOOVO.Editor.type = "block";
            }
            else {
                editor = document.createElement("span");
                elm = document.createElement("input");
                elm.id = "input-editor";
                elm.type = "text";
                elm.value = $.trim(this.oldValue);

                $(elm).bind("keypress keydown", function (ev) {
                    if (ev.keyCode == 13) {
                        $(elm).parent().find("button[value=Save]").trigger("click");
                        return false;
                    }
                });

                NOOVO.Editor.type = "inline";
            }

            editor.id = "inline-editor";
            if (elm) editor.appendChild(elm);

            if (editor.tagName.toLowerCase() === "span") {
                $("<br />").appendTo(editor);
            }

            this.editor = editor;

            return editor;
        },
        /**
         * Start editor
         *
         * @name run
         * @function
         * @memberOf NOOVO.Editor
         */
        run : function () {
            setTimeout(function () {
                $('textarea.widgEditor').richEditor({
                    base_path: $.fck_media_url
                });
                richEditor = $('textarea.widgEditor')[0];
            }, 1);
        },
        /**
         * Destroy editor instance
         *
         * @name destroy
         * @function
         * @memberOf NOOVO.Editor
         */
        destroy : function () {
            var editor = $("#textarea-editorWidgContainer")[0];
            if (!editor) { return; }

            var parent = editor.parentNode;

            // First take care of browser leak
            var buttons = editor.getElementsByTagName("*");
            $(buttons).each(function (i) {
                this.click = null;
            });

            // Now remove and destroy editor
            parent.removeChild(editor);

            this.editor = null;
        },
        /**
         * Retrieve editor content
         *
         * @name getText
         * @function
         * @memberOf NOOVO.Editor
         */
        getText : function () {
            function zeropad(val) {
                if (val.length == 1) {
                    return 0 + val;
                } else {
                    return val;
                }
            }

            var value;

            if (typeof(document.designMode) === "string"
                    && (document.all || document.designMode === "off")
                    && NOOVO.Editor.type === "block"
                    && richEditor) {
                richEditor.cleanHTML();
                value = richEditor.getHTML();
            } else if (typeof(document.designMode) === "string"
                    && (document.all || document.designMode === "off")
                    && document.getElementById("id_start_datetime_0")) {
                value = zeropad($("#id_start_datetime_2").val())
                            + '-' + zeropad($("#id_start_datetime_1").val())
                            + '-' + zeropad($("#id_start_datetime_0").val())
                            + ' ' + zeropad($("#id_start_datetime_3").val())
                            + ':' + zeropad($("#id_start_datetime_4").val())
                            + ',' + $("#id_duration_0").val()
                            + ' ' + $("#id_duration_1").val()
                            + ',' + $("#id_timezone").val();
            } else {
                value = this.editor.firstChild.value;
                value = NOOVO.Editor.txt2html(value);
            }

            return value;
        },
        /**
         * Translate DOM fragment to text.
         *
         * @name dom2txt
         * @function
         * @memberOf NOOVO.Editor
         * @param {HTMLElement}        Element to translate
         */
        dom2txt: function (elm) {
           function _translateDom(el) {
               var value = "";

               if (el.nodeType === 3) {
               // Text node. Just strip whitespace from edges and return it
               var lines = el.nodeValue.split("\n");
            for(var i=0;i<lines.length;i++) {
                lines[i] = $.trim(lines[i]);
            }
            value = lines.join(" ");
               }
               else if (el.nodeType === 1) {
               var tag = el.tagName.toLowerCase();

               var node = el.firstChild;
               while (node) {
                   value += _translateDom(node);
                   node = node.nextSibling;
               }

               switch (tag) {
                   case "p":
                   value += "\n\n";
                   break;
                   case "br":
                   value += "\n";
                   break;
                   case "div":
                   break;
                   default:
                   value = "<"+tag+">"+value+"</"+tag+">";
                   break;
               }
               }

               return value;
           }

           return _translateDom(elm);
        },
        /**
         * Translate structured text to HTML
         *
         * @name txt2html
         * @function
         * @memberOf NOOVO.Editor
         * @param {String}    Structured text
         */
        txt2html: function (txt) {
            var result = txt;
            // First create paragraphs
            var parts = result.split("\n\n");

            if (parts.length > 1) { // At least two paragraphs
                result = "<p>"+parts.join("</p><p>")+"</p>";
            }

            // Now add line break
            result = result.replace("\n", "<br />");

            return result;
        },
        customPaste: function (e) {
        },
        getLocationValues: function () {
            var values = {};
            $.each(["location", "country_id", "state_id", "location_x", "location_y"], function () {
                 values[this] = $("#"+this).val();
            });
            return values;
        },
        isRichEditor: function () {
            // returns true if richeditor
            if (typeof(document.designMode) === "string"
                    && (document.all || document.designMode === "off")
                    && NOOVO.Editor.type === "block"
                    && richEditor) {
                return true;
            }
            return false;
        }
    };
}();

NOOVO.EEditor = function () {
    return {
        type : "block",
        create: function(el, typ, editor) {
            var plval = [];

            if (typ === "place") {
                $.each([/*"place",*/ "venue", "address", "location"], function () {
                    plval.push($("span."+this, el).text());
                });
                return $('<form id="inline-editor"><ul class="captionvalue" style="font-size:60%;">'+
                    '<li><strong class="caption">'+gettext('Venue')+'</strong><input type="text" id="venue" value="'+plval[0]+'" /></li>'+
                    '<li><strong class="caption">'+gettext('Address')+'</strong><input type="text" id="address" value="'+plval[1]+'" /></li>'+
                    '<li><strong class="caption">'+gettext('Location')+'</strong><input type="text" id="id_city_tmp" value="'+plval[2]+'" />'+
                    '<a class="linkAdvanced" style="float:none;">'+gettext('Advanced')+'</a></li>'+
                    '<li><div id="id_location_container">'+
                        '<div class="geoSearch geoInline">'+
                            '<div class="selectedLocationInfo"></div>'+
                            '<ul class="tabnav"></ul>'+
                            '<div class="geoSearchForm">'+
                                '<div class="searchContainer">'+
                                '<div class="input">'+
                                    '<input type="text" style="width:140px;" />'+
                                    '<button>'+gettext("Search")+'</button>'+
                                '</div>'+
                                '<div class="input">'+
                                    '<input type="text" style="width:140px;" />'+
                                    '<span class="position"></span>'+
                                '</div>'+
                                '<p class="instructions"></p>'+
                                '<ol class="results"></ol>'+
                                '<button>'+gettext("Set Location")+'</button>'+
                            '</div>'+
                            '<div class="map" id="geosearch_map_0"></div>'+
                        '</div>'+
                    '</div>'+
                '</div></li>'+
                '</ul></form>')[0];
            } else {
                $.ajax({url: "/fragment/datetime/", success: function (html) {
                        $("button:first", editor).before(html);
                        // Parse original values and set values accordingly
                        var fd = $("span.type_eventdate").attr("efrom").replace(/-/g, " ").replace(/:/g, " ").split(" "),
                            td = $("span.type_eventdate").attr("eto").replace(/-/g, " ").replace(/:/g, " ").split(" ");
                            tz = $("span.type_eventdate").attr("tz");
                        var ed = $("#inline-editor")[0], k=0, j=0;
                        var ftd, ttd, deltad, dunit, duration=0;
                        var delta = [2008, 1, 1, 0];

                        $.each(fd, function (i) {
                            fd[i] = parseInt(this, 10);
                        });
                        $.each(td, function (i) {
                            td[i] = parseInt(this, 10);
                        });
                        $.each(["day", "month", "year", "hour", "minute"], function (k, val) {
                            // Minutes are special case
                            j = (k<4) ? fd[k]-delta[k] :fd[4]*5;
                            k = (k===2) ? 0 : ((k===0) ? 2 : k); // Switch 2 and 0
                            $("select[name^=start_datetime_"+k+"]", ed)[0].selectedIndex = j;
                        });
                        // And duration...
                        ftd = new Date(fd[0], fd[1]-1, fd[2], fd[3], fd[4], fd[5]);
                        ttd = new Date(td[0], td[1]-1, td[2], td[3], td[4], td[5]);
                        deltad = new Date(ttd-ftd);
                        if (deltad.getMinutes()) {
                            dunit = 0;
                            duration = deltad.getMinutes();
                        }
                        else if (deltad.getHours() !== 1) {
                            // TIMEZONES. Dubious implementation!
                            dunit = 1;
                            duration = deltad.getHours()-1;
                        } else {
                            dunit = 2;
                            duration = deltad.getTime()/86400000;
                        }
                        $('option[value^=' + tz + ']')[0].selected = true;
                        $("select[name^=duration_1]")[0].selectedIndex = dunit;
                        if (typeof duration == 'number' && duration > 0) {
                            $("input[name^=duration_0]").val(duration);
                        }
                    }
                });
            }
        },
        getValues: function () {
            var values = {};
            $.each([/*"place",*/ "venue", "address", "location", "country_id", "state_id", "location_x", "location_y"], function () {
                 values[this] = $("#"+this).val();
            });
            return values;
        }
    };
}();

/**
  * @class
  * Inpage editor.
  * @constructor
  */
NOOVO.Inline = function () {
    var ONEdit = false; // On top of edit button

    return {
        /**
         * Scan page and prepare triggers for inline editors.
         *
         * @name init
         * @function
         * @memberOf NOOVO.Inline
         */
        init : function () {
            var clss, j, widgEditor = false;
            var elms = $(".editable, .leditable");
            $(".editable, .leditable").each(function (i) {
                widgEditor = true;

                // Find type
                clss = this.className.split(" ");
                for(j=0;j<clss.length;j++) {
                    if (clss[j].slice(0,5) === "type_") {
                        this.edit_type = clss[j].slice(5);
                        break;
                    }
                }

                if ($(this).hasClass("editable")) {
                    $(this).mouseover(NOOVO.Inline.onover);
                } else {
                    $(this).mouseover(function (e) { this.style.background = "#cdcdcd";this.style.color="#333"; });
                    $(this).mouseout(function (e) { this.style.background = null;this.style.color = null; });
                    $(this).click(NOOVO.Inline.lonselect);
                }
            });

            if (widgEditor) {
                NOOVO.Editor.load();
            }
        },
        /**
         * Find editable node and extract its metadata
         *
         * @name _getObject
         * @function
         * @memberOf NOOVO.Inline
         * @param {HTMLElement}        Starting point for search inside of editable node
         * @private
         */
        _getObject : function (el) {
            var oldnode, node = el.parentNode;
            var re = new RegExp('^editable_');
            var obj = {'field': ""};

            var orig = el.parentNode.nextSibling;

            if (el.edit_type) {
                obj.field = el.edit_type;
            }

            do {
                if (node.id  && re.test(node.id)) {
                    var parts = node.id.slice(9).split("_");
                    obj.id = parts[0];
                    return obj;
                }
                oldnode = node;
                node = node.parentNode;
            } while (node !== oldnode);
        },
        /**
         * Editor buttons handler
         *
         * @name buttonHandler
         * @function
         * @memberOf NOOVO.Inline
         * @param {Event}
         * @private
         */
        buttonHandler: function (e) {
            function saved(response) {

                var srvObj;
                eval("srvObj="+response);

                if (orig.tagName.toLowerCase().slice(0,1) === "h") {
                    // Special case. Headings with links to articles. Live links alone
                    while (orig.firstChild.nodeType !== 3) {
                        orig = orig.firstChild;
                    }
                }
                // Find type
                var typ = null;
                var clss = orig.className.split(" ");
                for(j=0;j<clss.length;j++) {
                    if (clss[j].slice(0,5) === "type_") {
                        typ = clss[j].slice(5);
                        break;
                    }
                }

                $(orig).removeClass("notitle");
                if (typ == 'tag') {
                    orig.innerHTML = srvObj.value;
                } else if (typ == 'eventdate') {
                    orig.innerHTML = srvObj.value;
                } else if (srvObj.value) {
                    orig.innerHTML = srvObj.value;
                } else {
                    orig.innerHTML = gettext("No title");
                    $(orig).addClass("notitle");
                    return;
                }

                // Now fade-in
                if (!fdel.id) {
                    var n = document.getElementById("fadein-element");
                    if (n) { n.id = null; }
                    fdel.id = "fadein-element";
                }

                $("#" + fdel.id).effect("highlight", { color: "#ffff33" }, 1750);
            }

            function savedEvent(response) {
                var srvObj, pl = [];
                eval("srvObj="+response);

                saveE += 1;
                //if (saveE === 8) {
                if (saveE === 7) {
                    // Done. Saved
                    $.each([/*"place",*/ "venue", "address", "location"], function () {
                        if (value[this]) {
                            pl.push('<span class="'+this+'">'+value[this]+'</span>');
                        }
                    });
                    if (value['state_id']) {
                        pl.push('<span class="state">' + GeoSearch.getStateFromId(value['state_id']) + '</span>');
                    }
                    if (value['country_id']) {
                        pl.push('<span class="country">' + GeoSearch.getCountryFromId(value['country_id']) + '</span>');
                    }
                    var o = $(orig)
                    var inputs = $('input', o);
                    o.empty();
                    o.append(pl.join(", "))
                    o.append(inputs);
                    //orig.innerHTML = pl.join(", ");
                    // Now fade-in
                    if (!fdel.id) {
                        var n = document.getElementById("fadein-element");
                        if (n) { n.id = null; }
                        fdel.id = "fadein-element";
                    }
                    $("#" + fdel.id).effect("highlight", { color: "#ffff33" }, 1750);

                    var lon = value['location_x'] === '' ? 181 : parseFloat(value['location_x']);
                    if (isNaN(lon)) lon = 181;
                    var lat = value['location_y'] === '' ? 91 : parseFloat(value['location_y']);
                    if (isNaN(lat)) lat = 91;
                    repositionGoogleMapMarker(lon, lat);
                }
            }

            function savedLocation(response) {
                var srvObj, pl = [];
                eval("srvObj="+response);

                saveE += 1;
                if (saveE === 5) {
                    // Done. Saved
                    $.each(["location"], function () {
                        if (value[this]) {
                            pl.push('<span class="'+this+'">'+value[this]+'</span>');
                        }
                    });
                    if (value['state_id']) {
                        pl.push('<span class="state">' + GeoSearch.getStateFromId(value['state_id']) + '</span>');
                    }
                    if (value['country_id']) {
                        pl.push('<span class="country">' + GeoSearch.getCountryFromId(value['country_id']) + '</span>');
                    }
                    var o = $(orig)
                    var inputs = $('input', o);
                    o.empty();
                    o.append(gettext('Location') + ': ');
                    o.append(pl.join(", "));
                    o.append(inputs);
                    //orig.innerHTML = pl.join(", ");
                    // Now fade-in
                    if (!fdel.id) {
                        var n = document.getElementById("fadein-element");
                        if (n) { n.id = null; }
                        fdel.id = "fadein-element";
                    }
                    $("#" + fdel.id).effect("highlight", { color: "#ffff33" }, 1750);

                    var lon = value['location_x'] === '' ? 181 : parseFloat(value['location_x']);
                    if (isNaN(lon)) lon = 181;
                    var lat = value['location_y'] === '' ? 91 : parseFloat(value['location_y']);
                    if (isNaN(lat)) lat = 91;
                }
            }

            var saveE = 0, target = e.target;
            var fdel = target.parentNode.nextSibling;
            var value, obj, data = "";
            var url = "&method=";
            var orig = NOOVO.Inline.editor.nextSibling;

            e.stopPropagation();

            if (target.value === "Save") {
                console.log("in inline save");


                url = "/services/rest/?rtype=json";
                obj = NOOVO.Inline._getObject(target);

                console.log(obj);
                console.log(target);

                if (!obj.id) {
                    console.error('Missing object id, check for object root accessor.');
                    return false;
                }
                if (obj.field === 'pagetitle') {
                    var active = $("li.active.removable");
                    if (active.length == 0) {
                        cosole.error("Missing active navigation item.");
                        return false;
                    }
                    var page_id = $("[name=page_id]", active).val();
                    var new_title = NOOVO.Editor.getText();
                    var oid = obj.id;
                    $.post(url,
                            { method: "core.setPageTitle",
                              csrfmiddlewaretoken: CSRF_TOKEN,
                              page_id: page_id,
                              title: NOOVO.Editor.getText()
                            },
                            function (rsp) {
                                $("h2.type_pagetitle").text(new_title).effect("highlight", { color: "#ffff33" }, 1750);;
                                $("a span", active).text(new_title);
                            });
                    NOOVO.Inline.destroyEditor();
                    return false;
                } else if (obj.field === "joinedplace") { // Event places => special case
                    value = NOOVO.EEditor.getValues();
                    $.each([/*"place",*/ "venue", "address", "location", "country_id", "state_id", "location_x", "location_y"], function () {
                        data = "method=core.setField&mid="+obj.id+"&field="+this+"&value="+encodeURIComponent(value[this]);
                        data += "&csrfmiddlewaretoken="+CSRF_TOKEN;
                        $.post(url, data, savedEvent);
                    });
                    NOOVO.Inline.destroyEditor();
                    return false;
                }
                else if (obj.field === "location") {        // Save multifield location -> special case
                    value = NOOVO.Editor.getLocationValues();
                    $.each(["location", "country_id", "state_id", "location_x", "location_y"], function () {
                        data = "method=core.setField&mid="+obj.id+"&field="+this+"&value="+encodeURIComponent(value[this]);
                        data += "&csrfmiddlewaretoken="+CSRF_TOKEN;
                        $.post(url, data, savedLocation);
                    });
                    NOOVO.Inline.destroyEditor();
                    return false;
                }

                var method = 'core.setField';
                if (/^feed_/.test(obj.field)) {
                    method = 'core.setFeedField';
                    obj.field = obj.field.substr(5);
                }

                value = NOOVO.Editor.getText();
                rich_editor = NOOVO.Editor.isRichEditor();

                data = "method=" + method + "&mid="+obj.id+"&field="+obj.field+"&value="+encodeURIComponent(value);
                data += "&csrfmiddlewaretoken=" + CSRF_TOKEN
                        + ((rich_editor) ? "&editor_unescape=true" : "");
                console.warn("data save:" + data);
                $.post(url, data, saved);
            }
            NOOVO.Inline.destroyEditor();
            return false;
        },
        /**
         * Create inline editor instance.
         *
         * @name createEditor
         * @function
         * @memberOf NOOVO.Inline
         * @param {HTMLElement}        Element to be replaced with editor.
         * @private
         */
        createEditor: function (el) {
            var edit_type, editor;
            if (NOOVO.Inline.editor) { return; }

            // Find type
            var clss = el.className.split(" ");
            for(var j=0;j<clss.length;j++) {
                if (clss[j].slice(0,5) === "type_") {
                    edit_type = clss[j].slice(5);
                    break;
                }
            }

            var node = el;
            if (el.tagName.toLowerCase().slice(0,1) === "h") {
                // Special case. Headings with links to articles. Live links alone
                while (node.childNodes && node.childNodes.length > 0 && node.childNodes[0].nodeType !== 3) {
                    node = node.childNodes[0];
                }
            }

            if (edit_type === "joinedplace") {
                editor = NOOVO.EEditor.create(node, "place");
            }
            else if (edit_type === "eventdate") {
                editor = $('<form id="inline-editor" style="font-size:60%; float:left;margin: 15px 0;"></form>')[0];
                NOOVO.EEditor.create(node, "date", editor);
            }
            else if (edit_type === "location") {
                editor = NOOVO.Editor.create(node, 'location');
            } else if (edit_type == 'tag') {
                editor = NOOVO.Editor.create(node, 'tag');
            }
            else {
                editor = NOOVO.Editor.create(node);
                console.warn(el);
                $('<link type="text/css" rel="stylesheet" href="'+$.media_url+'css/uni-form.css" />').appendTo($("head")[0]);
                if (NOOVO.Editor.type === "block"
                    && edit_type !== "abstract"
                    && edit_type !== "excerpt"
                    && !$(el).hasClass("plain_editor"))
                {
                    // Add media picker
                    $.ajax({url: "/fragment/media_picker/", success: function (html) {
                            $("button:first", editor).before(html);

                            // Layout corrections
                            $("#from-computer-tab, #from-computer").addClass("noshow").removeClass("active");
                            $("#from-noovo").removeClass("noshow");
                            $("#from-noovo-tab").addClass("active");
                            $("#from-noovo").parent().addClass("uniForm");
                            var tmp = $("#media-search-text").get(0);
                            if (tmp) {
                                tmp.size = 30;
                            }
                            $(".collapsable").collapsable();
                        }
                    });
                }

                // Photo detail page is a special case. Reformat CSS a bit
                if ($(el).hasClass("photoname")) {
                    $(editor).css("width", "270px");
                    $("input", editor).css("width", "260px");
                }
            }

            // Add cancel and save buttons
            var buttons = ["Cancel", "Save"];
            for(var i=0;i<buttons.length;i++) {
                var elm = document.createElement("button");
                elm.innerHTML = gettext(buttons[i]);
                elm.value = buttons[i];
                $(elm).click(this.buttonHandler);
                elm.edit_type = el.edit_type;

                editor.appendChild(elm);
            }

            $(editor).css({'display':'none', 'margin-left':  $(el).css("padding-left")});
            el.style.display="none";
            el.parentNode.insertBefore(editor, el);
            editor.edit_type = el.edit_type;
            if (editor.tagName.toLowerCase() === "form" && edit_type !== "joinedplace") {
                NOOVO.Editor.run();
            }
            editor.style.display="block";
            NOOVO.Inline.editor = editor;

            if (edit_type === "joinedplace" ||
                edit_type === "location")
            {
                PLACE_NAME_URL = '/geosearch/';
                var geosearchForm = $('div.geoSearch:first');
                geosearchForm.bind('toggledisplay', function(e, display) {
                    if (display) {
                            $('#id_city_tmp').css('visibility', 'hidden');
                            geosearchForm.parent().parent().prev().children('.linkAdvanced:first').text( gettext("Hide") );
                    }
                    else {
                            $('#id_city_tmp').css('visibility', 'visible');
                            geosearchForm.parent().parent().prev().children('.linkAdvanced:first').text( gettext("Advanced") );
                    }
                });
                var geoSearchObj = new GeoSearch(geosearchForm,
                                                'geosearch_map_0',
                                                $('#id_city_tmp'),
                                                null,
                                                {
                                                  city:'location',
                                                  countryId:'country_id',
                                                  stateId:'state_id',
                                                  longitude:'location_x',
                                                  latitude:'location_y'
                                                });
                geosearchForm.parent().parent().prev().children('.linkAdvanced:first').click(function() { geoSearchObj.displayForm(); });
            }
        },
        /**
         * Destroy inline editor instance.
         *
         * @name destroyEditor
         * @function
         * @memberOf NOOVO.Inline
         * @private
         */
        destroyEditor: function () {
            var editor = $("#inline-editor")[0];
            var parent = editor.parentNode;
            var orig = editor.nextSibling;

            // First take care of browser leak
            var buttons = $("#inline-editor button");
            for(var i=0;i<buttons.lenght;i++) {
                buttons[i].onclick = null;
            }

            NOOVO.Editor.destroy();

            // Now remove and destroy editor
            orig.style.display = "block";

            parent.removeChild(editor);
            NOOVO.Inline.editor = null;
        },
        /**
         * onmouseover handler. Add pencil icon if it doesn't exist in DOM yet.
         *
         * @name onover
         * @function
         * @memberOf NOOVO.Inline
         * @param {Event}
         * @private
         */
        onover: function (e) {
            var a, img;
            // Add edit button, if there isn't one yet
            var links = this.getElementsByTagName("a");
            for(var i=0;i<links.length;i++) {
                if (links[i].className === "itemedit") {
                    return;
                }
            }

            a = document.createElement("a");
            a.className = "itemedit";
            a.href = "#";
            a.onclick = NOOVO.Inline.onselect;
            img = document.createElement("img");
            $(img).css({'width': "16px", 'height': "16px"});
            img.src = $.media_url+"images/icons/pencil.png";
            a.appendChild(img);

            if (this.tagName.toLowerCase().slice(0,1) === "h") {
                this.appendChild(a);
            } else {
                this.insertBefore(a, this.firstChild);
            }
        },
        /**
         * oncancel handler. Cancel editor and restore original state.
         *
         * @name oncancel
         * @function
         * @memberOf NOOVO.Inline
         * @param {Event}
         * @private
         */
        oncancel: function (e) {
           NOOVO.Inline.destroyEditor();
        },
        /**
         * onclick handler. Instantiate an editor.
         *
         * @name onselect
         * @function
         * @memberOf NOOVO.Inline
         * @param {Event}
         * @private
         */
        onselect: function (e) {
            var el = this.parentNode;

            el.removeChild(this);

            NOOVO.Inline.createEditor(el);
            return false;
        },
        /**
         * onclick handler for onover editor. Instantiate an editor.
         *
         * @name lonselect
         * @function
         * @memberOf NOOVO.Inline
         * @param {Event}
         * @private
         */
        lonselect: function (e) {
            NOOVO.Inline.createEditor(this);
            return false;
        }
    };
}();

/**
  * @class
  * DHTML slider.
  * @constructor
  */
NOOVO.widgets.Slider = function (id, orientation, resolution) {
    /**
     * Set size of a slider.
     *
     * @name setSize
     * @function
     * @memberOf NOOVO.widgets.Slider
     * @param {Int}    Width
     * @param {Int}    Height
     */
    this.setSize = function (width, height) {
        this.width = width;
        this.height = height;
    };

    /**
     * drag handler.
     *
     * @name drag
     * @function
     * @memberOf NOOVO.widgets.Slider
     * @param {Event}
     * @private
     */
    this.drag = function (event) {
        function moveHandler(e) {
            var x; var y; var newvalue;
            if (!e) { e=window.event; }

            if (sl.orientation !== "vertical") {
                x = e.clientX - deltaX;
                if (x<0) { x=0; }
                if (x>sl.width-10) { x=sl.width-10; }
                sl.s.style.left=(x) + "px";
                newvalue = parseInt(x/sl.width * sl.resolution, 10);
            } else {
                if (sl.orientation !== "horizontal") {
                    y = e.clientY - deltaY;
                    if (y<0) { y=0; }
                    if (y>sl.height-10) { y=sl.height-10; }
                    sl.s.style.top=(y) + "px";
                    newvalue = parseInt(y/sl.height * sl.resolution, 10);
                }
            }
            if (newvalue !== sl.value) {
                sl.value = newvalue+1;
                sl.onChange(newvalue+1);
            }
        }

        function upHandler(e) {
            $(document).unbind("mouseup", upHandler);
            $(document).unbind("mousemove", moveHandler);
        }

        if (!event) { var event = window.event; }
        var deltaX=event.clientX - parseInt(sl.s.style.left, 10);
        var deltaY=event.clientY - parseInt(sl.s.style.top, 10);

        $(document).mousemove(moveHandler);
        $(document).mouseup(upHandler);
    };

    /**
     * onchange handler. Define your own.
     *
     * @name onChange
     * @function
     * @memberOf NOOVO.widgets.Slider
     * @param {Int}    Slider current value
     */
    this.onChange = function (value) {
        alert(value);
    };

    /**
     * Set slider's starting value.
     *
     * @name setStart
     * @function
     * @memberOf NOOVO.widgets.Slider
     * @param {Int}
     */
    this.setStart = function (value) {
        // Use only AFTER you defined onChange
        this.value = value;
        this.onChange(value);
        this.moveSlide(value);
    };

    /**
     * Move slider to specified value
     *
     * @name moveSlide
     * @function
     * @memberOf NOOVO.widgets.Slider
     * @param {Int}
     * @private
     */
    this.moveSlide = function (value) {
        var length = this.height;
        var l;

        if (this.orientation === "horizontal") {
            length = this.width;
        }

        l = parseFloat(length/this.resolution, 10) * value;
        if (this.orientation === "horizontal") {
            this.s.style.left=(l)+"px";
        } else {
            this.s.style.top=(l)+"px";
        }
    };

    /**
     * Create a slider instance.
     *
     * @name createSlider
     * @function
     * @memberOf NOOVO.widgets.Slider
     * @private
     */
    this.createSlider = function() {
        var rel = document.createElement("div");
        $(rel).css({'display': 'none', 'position': 'relative'});
        $(rel).attr("id", this.id+"_slider");

        var bar = document.createElement("div");
        $(bar).css({'position': 'absolute', 'background-color': '#ccc'});
        if (this.orientation === "horizontal") {
            $(bar).css({'left': "0px",
                'top': (parseInt(this.height/2, 10)-1)+"px",
                'width': (this.width)+"px",
                'height': "2px"});
            rel.style.height = "2px";
        } else {
            $(bar).css({'left': (parseInt(this.width/2, 10)-1)+"px",
                'top': "0px",
                'width': "2px",
                'height': (this.height)+"px"});
            rel.style.height = (this.height)+"px";
        }
        rel.appendChild(bar);

        // Set slider image as background element to fix IE quirk
        var img = document.createElement("div");
        $(img).css({'background-image': 'url("'+$.media_url+'images/buttons/slider_button.png")',
            'background-repeat' : "no-repeat",
            'width' : "11px",
            'height' : "10px",
            'padding' : "0",
            'position' : "absolute",
            'left' : 0,
            'top' : 0
        });

        img.onmousedown = this.drag;
        this.s = img;

        rel.appendChild(img);
        document.getElementById(this.id).appendChild(rel);
    };

    /**
     * Display slider on page.
     *
     * @name show
     * @memberOf NOOVO.widgets.Slider
     * @function
     */
    this.show = function() {
        this.s.parentNode.style.display="block";
    };

    // Initialize class
    this.id = id;
    this.orientation = "horizontal";
    this.resolution = 10;
    this.height = 10;
    this.width = 100;
    this.s = null;
    this.value=0;
    var sl = this;

    if (orientation !== undefined && orientation === "vertical") {
        this.orientation = "vertical";
        this.setSize(10, 100);
    }
    if (resolution !== undefined) {
        this.resolution = resolution;
    }

    this.createSlider();
};

/**
  * @class
  * DHTML gallery control.
  * @constructor
  */
NOOVO.widgets.Carousel = function (init_obj) {
    var rthis = this;

    /**
     * Hide unnecessary buttons.
     *
     * @name _hideButtons
     * @function
     * @memberOf NOOVO.widgets.Carousel
     * @private
     */
    this._hideButtons = function () {
        var f = this.first;
        var l = this.last;
        var p = this.prev;
        var n = this.next;
        if (!$("li.noshow", rthis.carousel).length) {
            p.style.visibility = "hidden";
            p.onclick = null;
            if (f) {
                f.style.visibility = "hidden";
                f.onclick = null;
            }
        } else {
            p.style.visibility = "visible";
            p.onclick = this._previousImage;
            if (f) {
                f.style.visibility = "visible";
                f.onclick = this._firstImage;
            }
        }

        var lis = this.carousel.getElementsByTagName("li");
        if (lis.length) {
            var topoff = lis[0].offsetTop;
            for(var i=0;i<lis.length;i++) {
                if (lis[i].offsetTop !== topoff) {
                    n.style.visibility = "visible";
                    n.onclick = this._nextImage;
                    if (l) {
                        l.style.visibility = "visible";
                        l.onclick = this._lastImage;
                    }
                    return;
                }
            }
        }
        n.style.visibility = "hidden";
        n.onclick =  null;
        if (l) {
            l.style.visibility = "hidden";
            l.onclick =  null;
        }
    };

    /**
     * Slide to next image.
     *
     * @name _nextImage
     * @function
     * @memberOf NOOVO.widgets.Carousel
     * @private
     */
    this._nextImage = function () {
        var li;
        if ($("li.noshow", rthis.carousel).length) {
            li = $("li.noshow:last", rthis.carousel).next();
        } else {
            li = $("li:first", rthis.carousel);
        }
        $(li).addClass("noshow");
        rthis._hideButtons();
    };

    /**
     * Slide to previous image.
     *
     * @name _previousImage
     * @function
     * @memberOf NOOVO.widgets.Carousel
     * @private
     */
    this._previousImage = function () {
        $("li.noshow:last", rthis.carousel).removeClass("noshow");
        rthis._hideButtons();
    };

    /**
     * Slide to first image.
     *
     * @name _firstImage
     * @function
     * @memberOf NOOVO.widgets.Carousel
     * @private
     */
    this._firstImage = function () {
        $("li.noshow", rthis.carousel).removeClass("noshow");
        rthis._hideButtons();
    };

    /**
     * Slide to last image.
     *
     * @name _lastImage
     * @function
     * @memberOf NOOVO.widgets.Carousel
     * @private
     */
    this._lastImage = function () {
        // Remove items as long as next image button is active
        while(rthis.next.onclick) {
            rthis._nextImage();
        }
    };


    this._setSize = function (e) {
        var sizes=[-1,20,45,75];
        var size = sizes[e.data.size];

        $(rthis.carousel).height(size+24);
        $("img", rthis.carousel).attr("width", size).attr("height", size);
    }

    /**
     * Initialize carousel control.
     *
     * @name init
     * @function
     * @memberOf NOOVO.widgets.Carousel
     * @param {Object}    Settings object
     * @private
     */
    this.init = function (init_obj) {
        if (!init_obj) { return; }


        if (init_obj.carousel) {
            this.carousel = document.getElementById(init_obj.carousel);
        }
        if (init_obj.next) {
            this.next = document.getElementById(init_obj.next);
        }
        if (init_obj.prev) {
            this.prev = document.getElementById(init_obj.prev);
        }
        if (init_obj.first) {
            this.first = document.getElementById(init_obj.first);
        }
        if (init_obj.last) {
            this.last = document.getElementById(init_obj.last);
        }
        if (init_obj.fullsize) {
            this.fullsize = document.getElementById(init_obj.fullsize);
        }
        if (init_obj.options) {
            var j = 0;
            $("#"+init_obj.options+" a").each(function (i) {
                if ($(this).hasClass("selectall")) {
                    return;
                }
                j += 1;
                $(this).bind("click", {size: j}, rthis._setSize);
            });
            $("#"+init_obj.options+" a.selectall").click(this.selectAll);
        }

        if (!this.carousel) {
            return;
        }

        if (this.prev) {
            this.prev.onclick = this._previousImage;
        }
        if (this.next) {
            this.next.onclick = this._nextImage;
        }
        if (init_obj.select) {
            $(this.carousel).bind("click", function (ev) { init_obj.select(ev); return false; });
        } else {
            $(this.carousel).click(this.selectPhoto);
        }

        this._hideButtons();
    };

    /**
     * Display bigger version of selected photo.
     *
     * @name selectPhoto
     * @memberOf NOOVO.widgets.Carousel
     * @function
     * @param {Event}
     * @private
     */
    this.selectPhoto = function(e) {
        var target = e.target;

        var img_url = target.src.split("@");

        rthis.fullsize.src = img_url[0]+"@500.jpg";
    };

    /**
     * Select all images
     *
     * @name selectAll
     * @memberOf NOOVO.widgets.Carousel
     * @function
     * @param {Event}
     * @private
     */
    this.selectAll = function(e) {
        $("li", rthis.carousel).addClass("active");
        return false;
    }

    this.carousel =  null;
    this.options = null;
    this.next = null;
    this.prev = null;
    this.first = null;
    this.last = null;
    this.fullsize = null;

    if (init_obj) {
        this.init(init_obj);
    }
};

/**
  * @class
  * DHTML menu
  * @constructor
  */
NOOVO.widgets.Filter = function () {
    return {
        /**
         * Initialize menu.
         *
         * @name init
         * @memberOf NOOVO.widgets.Filter
         * @function
         */
        init: function () {
            /**
             * Close all open menus.
             *
             * @name closeMenus
             * @memberOf NOOVO.widgets.Filter
             * @function
             * @private
             */
            function closeMenus(e) {
                $("#filter-pick li").removeClass("active");
               // if (e) { e.stopPropagation(); }
            }

            /**
             * Open a menu.
             *
             * @name showFilter
             * @memberOf NOOVO.widgets.Filter
             * @function
             * @param {Event}
             * @private
             */
            function showFilter(e) {
                var target = e.target;
                e.stopPropagation();

                while(target.tagName.toLowerCase() != "li")
                    target = target.parentNode;

                if ($(target).hasClass("active")) {
                    // Already open => close it
                    NOOVO.util._closeMenus();
                    return false;
                }
                NOOVO.util._closeMenus();

                if (target.getElementsByTagName("ul").length == 0) return;

                $(target).addClass("active");
                return false;
            }

            var chld = document.getElementById("filter-pick");
            if (!chld) { return; }

            NOOVO.util._closeMenus();
            $("html").click(closeMenus);
            $("#filter-pick").click(closeMenus);
            $("#filter-pick span").click(showFilter);
        }
    };
}();

/*
 * Timer prototype. NOT READY FOR PRODUCTION.
 */
NOOVO.timer = function (){

    function onUnLoad() {
        // Final ping
        var host = "", img;
        var seed = (new Date()).getTime();
        if (document.location.host) {
            host = document.location.host;
        } else {
            if (document.location.hostname) {
                host = document.location.hostname;
            }
        }
        var newurl = "http://"+host+"/services/rest/?rtype=json&iecache="+seed;
        counter = Math.min(counter, endAfter);
        newurl += method+"&count="+counter;
        img = new Image();
        img.src = newurl;
    }

    var start = new Date(), endAfter = 1000*60*1; // 1 minutes
    var method = "&method=core.timer&url="+document.location.pathname;
    var freq=1000*3; // 3 sec
    var counter = 0, oldcounter = 0;

    return {

        init: function () {
            $(window).focus(NOOVO.timer.startCounter)
                .blur(NOOVO.timer.stopCounter)
                .mouseover(NOOVO.timer.startCounter)
                .mouseout(NOOVO.timer.stopCounter)
                .unload(onUnLoad);
        },

        startCounter: function () {
            if (!start) {
                start = new Date();
            }
        },

        stopCounter: function () {
            if (start) {
                var now = new Date();
                counter += now-start;
                start = null;
            }
        }
    }
}();


NOOVO.favoritizer = function() {

    return {
        init: function() {
            $('.favorite').each(function() {
                $(this).click(NOOVO.favoritizer.toggleFavorite);
            });
        },

        toggleFavorite: function() {
            var me = $(this);
            var id = parseInt(me.attr('id').replace(/[^0-9]/g, ''), 10);
            if (isNaN(id) || id <= 0) {
                console.error('toggleFavorite error: id=' + id);
                return;
            }
            var isFav = me.hasClass('fav');

            data = ['method=core.setFavorite',
                    'mid=' + id,
                    'field=favorite',        // just something
                    'value=' + (isFav ? '0' : '1'),
                    CSRF_NAME + '=' + CSRF_TOKEN];
            $.post("/services/rest/?rtype=json", data.join('&'), function(resp) { NOOVO.favoritizer.saved(id, resp); });

            return false
        },

        saved: function(id, resp) {
            try {
                resp = eval('(' + resp + ')');
                if (resp && typeof resp.favorite !== 'undefined') {
                    if (resp.favorite) $('#fav_' + id).addClass('fav');
                    else $('#fav_' + id).removeClass('fav');
                }
            }
            catch(e) {
                console.log('Exception in NOOVO.favoritizer.saved: ' + e);
            }
        }
    };
}();

NOOVO.LocationEditor = function() {
    var locEditor = null;
    var container = null;
    var callbackFunction = null;
    var accessorId = 0;

    return {

        init: function(accId, cnt, callback) {
            container = $(cnt);
            accessorId = accId;
            if ($.isFunction(callback)) callbackFunction = callback;
        },

        create: function() {
            container.empty();

            if (!locEditor) {
                locEditor = $('<ul>'+
                    '<p class="simple"><span>'+gettext('Location')+':</span><input type="text" id="id_city_tmp" />'+
                        '<a class="linkAdvanced">'+gettext('Advanced')+'</a><br clear="all" /></p>'+
                    '<div id="id_location_container">'+
                        '<div class="geoSearch geoInline">'+
                            '<div class="selectedLocationInfo"></div>'+
                            '<ul class="tabnav" style="padding-left:0;"></ul>'+
                            '<div class="geoSearchForm">'+
                                '<div class="searchContainer">'+
                                '<div class="input">'+
                                    '<input type="text" style="width:140px;" />'+
                                    '<button>'+gettext("Search")+'</button>'+
                                '</div>'+
                                '<div class="input">'+
                                    '<input type="text" style="width:140px;" />'+
                                    '<span class="position"></span>'+
                                '</div>'+
                                '<p class="instructions"></p>'+
                                '<ol class="results"></ol>'+
                                '<button>'+gettext("Set Location")+'</button>'+
                            '</div>'+
                            '<div class="map" id="geosearch_map_0"></div>'+
                        '</div>'+
                    '</div>'+
                '</div>' +
                '<p class="submit"><button type="button">' + gettext('Cancel') + '</button>' +
                '<button type="button">' + gettext('Save') + '</button><br clear="all" /></p>');

                locEditor.find('#id_city_tmp').val($('#id_location').val());
                container.append(locEditor[0]);

                PLACE_NAME_URL = '/geosearch/';
                var geosearchForm = locEditor.find('div.geoSearch:first');
                geosearchForm.bind('toggledisplay', function(e, display) {
                    if (display) {
                            $('#id_city_tmp').hide().prev().hide();

                            locEditor.find('.linkAdvanced:first').text( gettext("Hide") );
                    }
                    else {
                            $('#id_city_tmp').show().prev().show();
                            locEditor.find('.linkAdvanced:first').text( gettext("Advanced") );
                    }
                });
                var geoSearchObj = new GeoSearch(geosearchForm,
                                                'geosearch_map_0',
                                                $('#id_city_tmp'),
                                                null,
                                                {
                                                  city:'id_location',
                                                  countryId:'id_country_id',
                                                  stateId:'id_state_id',
                                                  longitude:'id_location_x',
                                                  latitude:'id_location_y'
                                                });
                locEditor.find('.linkAdvanced:first').click(function() { geoSearchObj.displayForm(); });
                locEditor.find('ul.tabnav>li:first').css('margin-left', '0');
                locEditor.find('p.submit>button:first').
                    click(function() { NOOVO.LocationEditor.destroy(); }).
                    next('button').click(function() { NOOVO.LocationEditor.save(); });
                container.show();
            }
        },

        save: function() {
            var accId = parseInt(accessorId, 10);
            var url = "/services/rest/?rtype=json";

            if (isNaN(accId) || accId <= 0) {
                console.error('Invalid accessor id (' + accessorId + ')!');
            }

            var data = {mid:accId,
                        method: 'core.setLocation',
                        csrfmiddlewaretoken: CSRF_TOKEN};

            $.each(["id_location", "id_country_id", "id_state_id", "id_location_x", "id_location_y"], function () {
                data[this.replace(/^id_/, '')] = $('#' + this).val();
            });

            $.post(url, data, NOOVO.LocationEditor.saved);
        },

        saved: function(resp) {
            NOOVO.LocationEditor.destroy();
            if (callbackFunction) {
                var tmpLoc = {}
                $.each(["id_location", "id_country_id", "id_state_id", "id_location_x", "id_location_y"], function () {
                    tmpLoc[this.replace(/^id_/, '')] = $('#' + this).val();
                });
                callbackFunction(tmpLoc);
            }
        },

        toggle: function() {
            if (locEditor) NOOVO.LocationEditor.destroy();
            else NOOVO.LocationEditor.create();
        },

        destroy: function() {
            if (locEditor) {
                container.find('*').unbind();
                container.empty();
                container.hide();
                locEditor = null;
            }
        }
    };
}();

NOOVO.ga = function () {
    var GA_GROUPS = {
        group: {
            name: "Group",
            actions: { create: "Create group", join: "Join group" }
        },
        people: {
            name: "People",
            actions: { add: "Add friend", invite: "Invite friend", send_message: "Send message" }
        },
        publish: {
            name: "Publish",
            actions: {
                video: "Publish video",
                post: "Publish post",
                event: "Publish event",
                file: "Publish file",
                photo: "Publish photo",
                bookmarklet: "Publish from bookmarklet"
            }
        },
        page: {
            name: "Page",
            actions: { add: "Add page", subscribe: "Subscribe to a feed" }
        },
        item: {
            name: "Item",
            actions: { take_it: "Take it", forward: "Forward" }
        }
    };

    return {
        trace: function (group_id, event_id, val, i) {
            try {
                if (pageTracker && typeof pageTracker._trackEvent == 'function') {
                    var ga_group = GA_GROUPS[group_id];

                    if (!ga_group) {
                        console.warn("Unknown event group id: " + group_id);
                        return;
                    }

                    var action = ga_group.actions[event_id];

                    if (!action) {
                        console.warn("Unknown action:" + event_id + " for group " + group_id);
                        action = "Unknown action";
                    }
                    console.log("ga_track(): gname=" + ga_group.name + ", action=" + action + ", val=" + ((val) ? val : USERNAME));
                    pageTracker._trackEvent(ga_group.name, action, (val) ? val : USERNAME, (i) ? i : 0);
                }
            } catch (ex) {
                console.warn(ex);
            }
        }
    }
}();

NOOVO.notifier = function() {
    var form = null;
    var ppicker = null;
    var accessorId = 0;
    var slotId = 0;
    var slotContentTypeId = 0;
    var infoBlock = null;
    var okButton = null;

    return {

        init: function(accId, slId, slCtId) {
            accessorId = accId;
            slotId = slId;
            slotContentTypeId = slCtId;

            var link = $('.notifylink:first');
            form = $('.notifyform:first');
            infoBlock = $('<div class="notifier infoBlock"></div>').insertBefore(form);

            ppicker = $('#peoplePicker');

            if (ppicker.length == 0 || link.length == 0 || form.length == 0) {
                return;
            }

            link.bind('click', function() {
                if (form.hasClass("noshow")) {
                    form.removeClass("noshow").hide().slideDown();
                } else {
                    form.slideUp("normal", function () { form.addClass("noshow"); });
                }
            });

            link.one('click', function() {
                ppicker.trigger('show');
                $('ul.tabs>li:first', ppicker).css('margin', '0');
            });

            $('.ctrlHolder>button:first', form).bind('click', function() { form.slideUp("normal", function () {form.addClass("noshow");} ); });
            okButton = $('.ctrlHolder>button:eq(1)', form).bind('click', function() {
                NOOVO.notifier.commit();
            });

            $('.ctrlHolder>textarea:first', form).val('');
        },

        commit: function() {
            function messageHighlight(msg) {
                infoBlock.text(msg)
                         .fadeIn("normal", function () {
                                setTimeout(function () {
                                    infoBlock.fadeOut("normal");
                                }, 6000);
                        });
            }

            var selected_people = $("#selectedPeople")[0].getAllResources();
            var emails = [];
            var people = [];

            for (idx in selected_people) {
                if ('uploader_id' in selected_people[idx]) {
                    var id = parseInt(selected_people[idx]['uploader_id'], 10);
                    if (!isNaN(id) && id > 0) people.push(id);
                }
                else emails.push(selected_people[idx]['id']);
            }
            if (emails.length || people.length) {
                var url = "/services/rest/?rtype=json";
                var data = {         method: 'people.sendContentNotifications',
                                url: window.location.href.replace(/#notify$/, ''),
                                people: people.join(','),
                                emails: emails.join(','),
                                message: $.trim(form.find('div.ctrlHolder>textarea:first').val()),
                                aid: accessorId,
                                slid: slotId,
                                slctid: slotContentTypeId,
                                csrfmiddlewaretoken: CSRF_TOKEN,
                                rtype: 'json'
                           };
                 var dimensions = {
                    width: okButton.outerWidth() + "px",
                    height: okButton.outerHeight() + "px"
                };
                okButton.css(dimensions).addClass("submitted").attr("disabled", "disabled").text(".");

                $.ajax({
                    url: url,
                    type: 'POST',
                    data: data,
                    dataType: 'json',
                    error: function () {
                        messageHighlight(gettext("Couldn't forward this. Please, try again later."));
                        okButton.removeClass("submitted").removeAttr("disabled").text(gettext("Forward"));
                    },
                    success: function (response) {
                        if (response == "true") {
                            messageHighlight(gettext("Couldn't forward this. Please, try again later."));
                            okButton.removeClass("submitted").removeAttr("disabled").text(gettext("Forward"));
                        } else {
                            okButton.removeClass("submitted").removeAttr("disabled").text(gettext("Forward"));
                            form.slideUp("normal", function () {
                                    form.addClass('noshow').find('div.ctrlHolder>textarea:first').val('');
                            });
                            messageHighlight(gettext("We forwarded this successfully."));
                        }
                    }
                });

                NOOVO.ga.trace("item", "forward", null, emails.length + people.length);

            } else {
                messageHighlight(gettext("Select at least one person or add an email."));
            }
        },

        sent: function(resp) {
            form.addClass('noshow').find('div.ctrlHolder>textarea:first').val('');
        }
    }
}();

NOOVO.util.setMouseoverHandler = function (index) {
    var open_image = 0;
    var num_elements = $(".set-image img",this).length;
    $(".set-image", this).mousemove(function (e) {
        var new_image = parseInt((e.clientX / 35) + e.clientY * 0.08) % num_elements;
        $("#set_image_"+open_image, this).addClass("noshow");
        $("#set_image_"+new_image, this).removeClass("noshow");
        open_image = new_image;
    });
};

/*
 * Initalize toolkit on document load (fallback on window)
 */
(function ( ) {
    $(document).ready(function () {
        NOOVO.Inline.init();
        NOOVO.util.showHide();

        NOOVO.widgets.Filter.init();
        NOOVO.timer.init();
        NOOVO.favoritizer.init();
        NOOVO.util._equalHeight();
        $("html").click(NOOVO.util._closeMenus);

        if (NOOVO._onload) {
            $(NOOVO._onload.onDom).each(function (){
                this();
            });
        }
    });
})( );
