// This file contains general-purpose LJ code

var LiveJournal = new Object;

// The hook mappings
LiveJournal.hooks = {};

LiveJournal.register_hook = function (hook, func) {
    if (! LiveJournal.hooks[hook])
        LiveJournal.hooks[hook] = [];

    LiveJournal.hooks[hook].push(func);
};

// args: hook, params to pass to hook
LiveJournal.run_hook = function () {
    var a = arguments;

    var hookfuncs = LiveJournal.hooks[a[0]];
    if (!hookfuncs || !hookfuncs.length) return;

    var hookargs = [];

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

    var rv = null;

    hookfuncs.forEach(function (hookfunc) {
        rv = hookfunc.apply(null, hookargs);
    });

    return rv;
};

LiveJournal.pageLoaded = false;

LiveJournal.initPage = function () {
    // only run once
    if (LiveJournal.pageLoaded)
        return;
    LiveJournal.pageLoaded = 1;

    // set up various handlers for every page
    LiveJournal.initPagePlaceholders();
    LiveJournal.initInboxUpdate();
    LiveJournal.initPolls();

    // run other hooks
    LiveJournal.run_hook("page_load");
};

// Do setup once the page is ready
DOM.addEventListener(window, "DOMContentLoaded", LiveJournal.initPage);

// Set up a timer to keep the inbox count updated
LiveJournal.initInboxUpdate = function () {
    // Don't run if not logged in or this is disabled
    if (! Site || ! Site.has_remote || ! Site.inbox_update_poll) return;

    // Don't run if no inbox count
    var unread = $("Inbox_Unread_Count");
    var unread_menu = $("Inbox_Unread_Count_Menu");
    if (! unread && ! unread_menu) return;

    // Update every five minutes
    window.setInterval(LiveJournal.updateInbox, 1000 * 60 * 5);
};

// Do AJAX request to find the number of unread items in the inbox
LiveJournal.updateInbox = function () {
    var postData = {
        "action": "get_unread_items"
    };

    var opts = {
        "data": HTTPReq.formEncoded(postData),
        "method": "POST",
        "onData": LiveJournal.gotInboxUpdate
    };

    opts.url = Site.currentJournal ? "/" + Site.currentJournal + "/__rpc_esn_inbox" : "/__rpc_esn_inbox";

    HTTPReq.getJSON(opts);
};

// We received the number of unread inbox items from the server
LiveJournal.gotInboxUpdate = function (resp) {
    if (! resp || resp.error) return;

    var unread = $("Inbox_Unread_Count");
    var unread_menu = $("Inbox_Unread_Count_Menu");
    if (! unread && ! unread_menu) return;

    var unread_count = resp.unread_count? " (" + resp.unread_count + ")" : "";
    if ( unread )
        unread.innerHTML = unread_count;
    if ( unread_menu )
        unread_menu.innerHTML = unread_count;
};

// Search for placeholders and initialize them
LiveJournal.initPagePlaceholders = function () {
    LiveJournal.initPlaceholders(document);
}

LiveJournal.initPlaceholders = function (srcElement) {
    var placeholders = DOM.getElementsByTagAndClassName(srcElement, "img", "LJ_Placeholder") || [];

    Array.prototype.forEach.call(placeholders, function (placeholder) {
        var parent = DOM.getFirstAncestorByClassName(placeholder, "LJ_Placeholder_Container", false);
        if (!parent) return;

        var container = DOM.filterElementsByClassName(parent.getElementsByTagName("div"), "LJ_Container")[0];
        if (!container) return;

        var html = DOM.filterElementsByClassName(parent.getElementsByTagName("div"), "LJ_Placeholder_HTML")[0];
        if (!html) return;

        var placeholder_html = unescape(html.innerHTML);

        var placeholderClickHandler = function (e) {
            Event.stop(e);
            // have to wrap placeholder_html in another block, IE is weird
            container.innerHTML = "<span>" + placeholder_html + "</span>";
            DOM.makeInvisible(placeholder);
        };

        DOM.addEventListener(placeholder, "click", placeholderClickHandler);

        return false;
    });
};

// handy utilities to create elements with just text in them
function _textSpan () { return _textElements("span", arguments); }
function _textDiv  () { return _textElements("div", arguments);  }

function _textElements (eleType, txts) {
    var ele = [];
    for (var i = 0; i < txts.length; i++) {
        var node = document.createElement(eleType);
        node.innerHTML = txts[i];
        ele.push(node);
    }

    return ele.length == 1 ? ele[0] : ele;
};

var PollPages = {
    "hourglass": null
};

LiveJournal.initPolls = function (element) {
    var ele = element || document;
    var pollLinks = DOM.getElementsByTagAndClassName(ele, 'a', "LJ_PollAnswerLink") || [];

    // attach click handlers to each answer link
    Array.prototype.forEach.call(pollLinks, function (pollLink) {
        DOM.addEventListener(pollLink, "click", LiveJournal.pollAnswerLinkClicked.bindEventListener(pollLink));
    });

    var pollClears = DOM.getElementsByTagAndClassName(ele, 'a', "LJ_PollClearLink") || [];

    // attach click handlers to each clear link
    Array.prototype.forEach.call(pollClears, function (pollClear) {
        DOM.addEventListener(pollClear, "click", LiveJournal.pollClearLinkClicked.bindEventListener(pollClear));
    });

    var pollButtons = DOM.getElementsByTagAndClassName(ele, 'input', "LJ_PollSubmit") || [];

    // attaches a click handler to all poll submit buttons
    Array.prototype.forEach.call(pollButtons, function (pollButton) {
        DOM.addEventListener(pollButton, "click", LiveJournal.pollButtonClicked.bindEventListener(pollButton));
    });

    var pollChange = DOM.getElementsByTagAndClassName(ele, 'a', "LJ_PollChangeLink") || [];

    // attaches a click handler to all poll change answers buttons
    Array.prototype.forEach.call(pollChange, function (pollChange) {
        DOM.addEventListener(pollChange, "click", LiveJournal.pollChangeClicked.bindEventListener(pollChange));
    });

    var pollDisplay = DOM.getElementsByTagAndClassName(ele, 'a', "LJ_PollDisplayLink") || [];

    // attaches a click handler to all poll display answers buttons
    Array.prototype.forEach.call(pollDisplay, function (pollDisplay) {
        DOM.addEventListener(pollDisplay, "click", LiveJournal.pollDisplayClicked.bindEventListener(pollDisplay));
    });

    var pollForms = DOM.getElementsByTagAndClassName(ele, 'form', "LJ_PollForm") || [];

    // attach submit handlers to each poll form
    Array.prototype.forEach.call(pollForms, function (pollForm) {
        DOM.addEventListener(pollForm, "submit", LiveJournal.pollFormSubmitted.bindEventListener(pollForm));
    });

    var pollRespondentsLinks = DOM.getElementsByTagAndClassName(document, 'a', "LJ_PollRespondentsLink") || [];

    // attach click handlers to each link to show respondents to a poll
    Array.prototype.forEach.call(pollRespondentsLinks, function (pollRes) {
        DOM.addEventListener(pollRes, "click", LiveJournal.pollRespondentsLinkClicked.bindEventListener(pollRes));
    });

    var pollUserLinks = DOM.getElementsByTagAndClassName(document, 'a', "LJ_PollUserAnswerLink") || [];

    // attach click handlers to each answer link
    Array.prototype.forEach.call(pollUserLinks, function (pollLink) {
        DOM.addEventListener(pollLink, "click", LiveJournal.pollUserAnswerLinkClicked.bindEventListener(pollLink));
    });
};

LiveJournal.pollButtonClicked = function (e) {
    // shows the hourglass. The submit event wouldn't update the coordinates, so the click event
    // had to be used for this
    if (!PollPages.hourglass) {
        var coords = DOM.getAbsoluteCursorPosition(e);
        PollPages.hourglass = new Hourglass();
        PollPages.hourglass.init();
        PollPages.hourglass.hourglass_at(coords.x, coords.y+25);    // 25 is added to the y axis, otherwise the button would cover it
        PollPages.e = e;
    }

    return true;
};

LiveJournal.pollFormSubmitted = function (e) {
    Event.stop(e);

    var formObject = LiveJournal.getFormObject(this);  //gets the form ready for serialization

    var opts = {
        "url"    : LiveJournal.getAjaxUrl("pollvote"),
        "method" : "POST",
        "data"   : "action=vote&" + HTTPReq.formEncoded(formObject),
        "onData" : LiveJournal.pollUpdateContainer,
        "onError": LiveJournal.pollUpdateContainer
    };

    HTTPReq.getJSON(opts);

    return false;
};

LiveJournal.pollChangeClicked = function (e) {
    Event.stop(e);

    var opts = {
        "url"    : LiveJournal.getAjaxUrl("pollvote"),
        "method" : "POST",
        "data"   : "action=change&pollid=" + this.getAttribute("lj_pollid"),
        "onData" : LiveJournal.pollUpdateContainer,
        "onError": LiveJournal.pollUpdateContainer
    };

    HTTPReq.getJSON(opts);

    return false;
};

LiveJournal.pollDisplayClicked = function (e) {
    Event.stop(e);

    var opts = {
        "url"    : LiveJournal.getAjaxUrl("pollvote"),
        "method" : "POST",
        "data"   : "action=display&pollid=" + this.getAttribute("lj_pollid"),
        "onData" : LiveJournal.pollUpdateContainer,
        "onError": LiveJournal.pollUpdateContainer
    };

    HTTPReq.getJSON(opts);

    return false;
};

LiveJournal.pollUpdateContainer = function (results) {
    if (! results) return false;

    if (PollPages.hourglass) {
        PollPages.hourglass.hide();
        PollPages.hourglass = null;
    }

    if (results.error) return LiveJournal.ajaxError(results.error);

    resultsDiv = document.getElementById("poll-"+results.pollid+"-container");

    resultsDiv.innerHTML = results.results_html;

    LiveJournal.initPolls();
};



LiveJournal.getFormObject = function (form) {

    var inputs = form.getElementsByTagName("input");

    var formObject = new Object();

    for (var i = 0; i < inputs.length; i++) {
        var obj = inputs[i];

        if (obj.type == "checkbox") {
            if (!formObject[obj.name]) {
                formObject[obj.name] = new Array();
            }
            if (obj.checked)
                formObject[obj.name].push(obj.value);
        }
        else if (obj.type == "radio") {
           if (obj.checked) {
              formObject[obj.name] = obj.value;
           }
        }
        else
        {
            formObject[obj.name] = obj.value;
        }
    }

    var selects = form.getElementsByTagName("select");

    for (var i = 0; i < selects.length; i++) {
        var sel = selects[i];
        formObject[sel.name] = sel.options[sel.selectedIndex].value;
    }

    return formObject;

};

LiveJournal.pollClearLinkClicked = function (e) {
    Event.stop(e);

    var pollid = this.getAttribute("lj_pollid");
    var inputelements = DOM.getElementsByTagAndClassName(document, 'input', "poll-"+pollid ) || [];
    var inputelement;

    // clear all options of this poll
    for (var i = 0; i < inputelements.length; i++) {
        inputelement = inputelements[i];
        // text fields
        if (inputelement.type == 'text') {
            inputelement.value = "";
        } else {
        // checboxes and radio buttons
            inputelements[i].checked = false;
        }
    }

    var selectelements = DOM.getElementsByTagAndClassName(document, 'select', "poll-"+pollid ) || [];
    // drop-down selects
    for (var i = 0; i < selectelements.length; i++) {
        selectelements[i].selectedIndex = 0;
    }
}

// invocant is the pollLink from above
LiveJournal.pollAnswerLinkClicked = function (e) {
    Event.stop(e);

    if (! this || ! this.tagName || this.tagName.toLowerCase() != "a")
    return true;

    var pollid = this.getAttribute("lj_pollid");
    if (! pollid) return true;

    var pollqid = this.getAttribute("lj_qid");
    if (! pollqid) return true;

    var page     = this.getAttribute("lj_page");
    var pagesize = this.getAttribute("lj_pagesize");

    var action = "get_answers";

    // Do ajax request to replace the link with the answers
    var params = {
        "pollid"   : pollid,
        "pollqid"  : pollqid,
        "page"     : page,
        "pagesize" : pagesize,
        "action"   : action
    };

    var opts = {
        "url"    : LiveJournal.getAjaxUrl("poll"),
        "method" : "POST",
        "data"   : HTTPReq.formEncoded(params),
        "onData" : LiveJournal.pollAnswersReceived,
        "onError": LiveJournal.ajaxError
    };

    HTTPReq.getJSON(opts);

    if (!PollPages.hourglass) {
        var coords = DOM.getAbsoluteCursorPosition(e);
        PollPages.hourglass = new Hourglass();
        PollPages.hourglass.init();
        PollPages.hourglass.hourglass_at(coords.x, coords.y);
        PollPages.e = e;
    }

    return false;
};

LiveJournal.pollAnswersReceived = function (answers) {
    if (! answers) return false;

    if (PollPages.hourglass) {
        PollPages.hourglass.hide();
        PollPages.hourglass = null;
    }

    if (answers.error) return LiveJournal.ajaxError(answers.error);

    var pollid = answers.pollid;
    var pollqid = answers.pollqid;
    if (! pollid || ! pollqid) return false;
    var page     = answers.page;

    var answerPagEle;
    var answerEle;
    if (page) {
        answerPagEle = DOM.getElementsByTagAndClassName(document, 'div', "lj_pollanswer_paging")[0];
        answerEle    = DOM.getElementsByTagAndClassName(document, 'div', "lj_pollanswer")[0];
    } else {
        var linkEle = $("LJ_PollAnswerLink_" + pollid + "_" + pollqid);
        if (! linkEle) return false;

        answerPagEle = document.createElement("div");
        DOM.addClassName(answerPagEle, "lj_pollanswer_paging");

        answerEle = document.createElement("div");
        DOM.addClassName(answerEle, "lj_pollanswer");

        linkEle.parentNode.insertBefore(answerEle,    linkEle);
        linkEle.parentNode.insertBefore(answerPagEle, linkEle);

        linkEle.parentNode.removeChild(linkEle);
    }

    answerPagEle.innerHTML  = answers.paging_html ? answers.paging_html : "";
    answerEle.innerHTML     = answers.answer_html ? answers.answer_html : "(No answers)";

    if (typeof ContextualPopup != "undefined")
        ContextualPopup.setup();

    LiveJournal.initPolls();
};

LiveJournal.pollRespondentsLinkClicked = function (e) {
    Event.stop(e);

    if (! this || ! this.tagName || this.tagName.toLowerCase() != "a")
    return true;

    var pollid = this.getAttribute("lj_pollid");
    if (! pollid) return true;

    var action = "get_respondents";

    answerEle = $("LJ_PollRespondentsLink_" + pollid);
    if (! answerEle) return false;

    var params = {
        "pollid"   : pollid,
        "action"   : action
    };

    var opts = {
        "url"    : LiveJournal.getAjaxUrl("poll"),
        "method" : "POST",
        "data"   : HTTPReq.formEncoded(params),
        "onData" : LiveJournal.pollRespondentsReceived,
        "onError": LiveJournal.ajaxError
    };

    HTTPReq.getJSON(opts);

    if (!PollPages.hourglass) {
        var coords = DOM.getAbsoluteCursorPosition(e);
        PollPages.hourglass = new Hourglass();
        PollPages.hourglass.init();
        PollPages.hourglass.hourglass_at(coords.x, coords.y);
        PollPages.e = e;
    }

    return false;
}

LiveJournal.pollRespondentsReceived = function (answers) {
    if (! answers) return false;

    if (PollPages.hourglass) {
        PollPages.hourglass.hide();
        PollPages.hourglass = null;
    }

    if (answers.error) return LiveJournal.ajaxError(answers.error);

    var pollid = answers.pollid;
    if (! pollid) return false;

    answerEle = $("LJ_PollRespondentsLink_" + pollid);
    if (! answerEle) return false;

    var answer = answers.answer_html ? answers.answer_html : "(No answers)";
    var newAnswerEle = document.createElement("span");
    newAnswerEle.innerHTML = answer;
    answerEle.parentNode.replaceChild(newAnswerEle, answerEle);

    if (typeof ContextualPopup != "undefined")
        ContextualPopup.setup();

    LiveJournal.initPolls();
};


LiveJournal.pollUserAnswerLinkClicked = function (e) {
    Event.stop(e);

    if (! this || ! this.tagName || this.tagName.toLowerCase() != "a")
    return true;

    var pollid = this.getAttribute("lj_pollid");
    if (! pollid) return true;

    var userid = this.getAttribute("lj_userid");
    if (! userid) return true;

    var action = "get_user_answers";

    answerEle = $("LJ_PollUserAnswerLink_" + pollid + "_" + userid);
    if (! answerEle) return false;

    	// Do ajax request to replace the link with the answers
    var params = {
        "pollid"   : pollid,
        "userid"   : userid,
        "action"   : action
    };

    var opts = {
       	"url"    : LiveJournal.getAjaxUrl("poll"),
       	"method" : "POST",
       	"data"   : HTTPReq.formEncoded(params),
       	"onData" : LiveJournal.pollUserAnswersReceived,
       	"onError": LiveJournal.ajaxError
    };

    HTTPReq.getJSON(opts);

    if (!PollPages.hourglass) {
       	var coords = DOM.getAbsoluteCursorPosition(e);
       	PollPages.hourglass = new Hourglass();
       	PollPages.hourglass.init();
       	PollPages.hourglass.hourglass_at(coords.x, coords.y);
       	PollPages.e = e;
    }
    return false;
};

LiveJournal.pollUserAnswersReceived = function (answers) {
    if (! answers) return false;

    if (PollPages.hourglass) {
        PollPages.hourglass.hide();
        PollPages.hourglass = null;
    }

    if (answers.error) return LiveJournal.ajaxError(answers.error);

    var pollid = answers.pollid;
    var userid = answers.userid;
    if (! pollid || ! userid) return false;

    var linkEle = $("LJ_PollUserAnswerLink_" + pollid + "_" + userid);
    if (! linkEle) return false;

    answerEle = $("LJ_PollUserAnswerRes_" + pollid + "_" + userid);
    if (! answerEle) return false;

    answerEle.innerHTML = answers.answer_html ? answers.answer_html : "(No answers)";
	linkEle.innerHTML = "";
	answerEle.style.display = "block";

    if (typeof ContextualPopup != "undefined")
        ContextualPopup.setup();
};

// gets a url for doing ajax requests
LiveJournal.getAjaxUrl = function (action) {
    // if we are on a journal subdomain then our url will be
    // /journalname/__rpc_action instead of /__rpc_action
    return Site.currentJournal
        ? "/" + Site.currentJournal + "/__rpc_" + action
        : "/__rpc_" + action;
};

// generic handler for ajax errors
LiveJournal.ajaxError = function (err) {
    if (LJ_IPPU) {
        LJ_IPPU.showNote("Error: " + err);
    } else {
        alert("Error: " + err);
    }
};

// utility method to get all items on the page with a certain class name
LiveJournal.getDocumentElementsByClassName = function (className) {
  var domObjects = document.getElementsByTagName("*");
  var items = DOM.filterElementsByClassName(domObjects, className) || [];

  return items;
};

// utility method to add an onclick callback on all items with a classname
LiveJournal.addClickHandlerToElementsWithClassName = function (callback, className) {
  var items = LiveJournal.getDocumentElementsByClassName(className);

  items.forEach(function (item) {
    DOM.addEventListener(item, "click", callback);
  })
};

// given a URL, parse out the GET args and return them in a hash
LiveJournal.parseGetArgs = function (url) {
    var getArgsHash = {};

    var urlParts = url.split("?");
    if (!urlParts[1]) return getArgsHash;
    var getArgs = urlParts[1].split("&");
    for (var arg in getArgs) {
        if (!getArgs.hasOwnProperty(arg)) continue;
        var pair = getArgs[arg].split("=");
        getArgsHash[pair[0]] = pair[1];
    }

    return getArgsHash;
};
