// ==UserScript==
// @name          Outlook Web Access Extensions
// @namespace     http://www2.hawaii.edu/~dburger
// @description   Extensions to using the bastard child Outlook Web Access
// ==/UserScript==

(
function() {
    var UNREAD_IMG = '/exchweb/img/icon-msg-unread.gif';
    var READ_IMG = '/exchweb/img/icon-msg-read.gif';

    function walkTheDom(node, func) {
        func(node);
        node = node.firstChild;
        while(node) {
          walkTheDom(node, func);
          node = node.nextSibling;
        }
    }

    function getToolbarTable() {
        var tables = document.getElementsByTagName('table');
        for (var i = 0; i < tables.length; i++) {
            var table = tables[i];
            if (table.className === 'trToolbar') return table;
        }
        return null;
    }

    function getFindNamesForm() {
        var forms = document.getElementsByTagName('form');
        return (forms.length == 1 && forms[0].name == 'galfind') ? forms[0] : null;
    }

    function getBaseHref() {
        var bases = document.getElementsByTagName('base');
        return (bases) ? bases[0].href : null;
    }

    function addToolbarButton(toolbarTable, text, func) {
        var row = toolbarTable.tBodies[0].rows[0];
        var newCell = row.insertCell(row.cells.length - 1);
        newCell.setAttribute('valign', 'middle');
        newCell.setAttribute('nowrap', 'nowrap');
        var font = document.createElement('font');
        font.setAttribute('size', '2');
        font.appendChild(document.createTextNode(text));
        var nobr = document.createElement('nobr');
        nobr.appendChild(font);
        var a = document.createElement('a');
        a.href = 'javascript:void(0);';
        a.addEventListener('click', func, true);
        a.appendChild(nobr);
        newCell.appendChild(a);
    }

    function changeSelectState(state) {
        var inputs = document.getElementsByTagName('input');
        for (var i = 0; i < inputs.length; i++) {
            var input = inputs[i];
            var evt = document.createEvent('MouseEvents');
            if (input.type == 'checkbox' && input.checked != state) {
                // this won't fire the events to color the row
                // input.checked = true;
                // so dispatch as an event instead
                evt.initEvent('click', true, false);
                input.dispatchEvent(evt);
            }
        }
    }

    function addSelectAll(toolbarTable) {
        addToolbarButton(toolbarTable, 'Select All', function() {
            changeSelectState(true);
        });
    }

    function addSelectNone(toolbarTable) {
        addToolbarButton(toolbarTable, 'Select None', function () {
            changeSelectState(false);
        });
    }

    function setProps(sXml, loadFunc, errorFunc) {
      GM_xmlhttpRequest({
          method: 'BPROPPATCH',
          url: getBaseHref(),
          headers: {
              'Accept-Language': 'en-us',
              'Content-Type': 'text/xml'
          },
          data: sXml,
          onload: loadFunc,
          onerror: errorFunc
      });
    }

    function changeReadStatus(status) {
        var selInputs = [];
        var inputs = document.getElementsByTagName('input');
        for (var i = 0; i < inputs.length; i++) {
            var input = inputs[i];
            if (input.type == 'checkbox' && input.checked) selInputs.push(input);
        }
        if (selInputs.length > 0) {
            var sFlags = 'd:flags="1"'; // suppress receipt
            var sXml = '<?xml version="1.0"?\><a:propertyupdate xmlns:a="DAV:"><a:set><a:prop><d:read xmlns:d="urn:schemas:httpmail:" ' + sFlags + '>';
            sXml += (status) ? '1':'0';
            sXml += '</d:read></a:prop></a:set><a:target>';
            for (var i = 0; i < selInputs.length; i++) {
                var input = selInputs[i];
                sXml += '<a:href>' + getBaseHref() + input.value + '</a:href>';
            }
            sXml += '</a:target></a:propertyupdate>';
            var loadFunc = function(res) {
                var parser = new DOMParser();
                var doc = parser.parseFromString(res.responseText, 'text/xml');
                var responses = doc.getElementsByTagNameNS('DAV:', 'response');
                var baseHrefLength = getBaseHref().length;
                for (var i = 0; i < responses.length; i++) {
                    var response = responses[i];
                    var href = response.getElementsByTagNameNS('DAV:', 'href')[0];
                    var id = href.firstChild.nodeValue.substring(baseHrefLength - 1);
                    for (var j = 0; j < selInputs.length; j++) {
                        var input = selInputs[j];
                        if (input.type == 'checkbox' && input.value == id) {
                            var tr = input.parentNode.parentNode;
                            walkTheDom(tr, function(node) {
                                if (node.nodeType == 3) {
                                    var text = node.nodeValue;
                                    var parent = node.parentNode;
                                    var grandParent = parent.parentNode;
                                    if (status && parent.tagName == 'B') {
                                        grandParent.removeChild(parent);
                                        var font = document.createElement('font');
                                        font.size = 2;
                                        font.color = 'black';
                                        font.appendChild(document.createTextNode(text));
                                        grandParent.appendChild(font);
                                    } else if (!status && parent.tagName == 'FONT') {
                                        grandParent.removeChild(parent);
                                        var b = document.createElement('b');
                                        b.appendChild(document.createTextNode(text));
                                        grandParent.appendChild(b);
                                    }
                                } else if (node.nodeType == 1 && node.tagName == 'IMG') {
                                    if (status && node.src.match(UNREAD_IMG + '$')) {
                                        node.src = READ_IMG;
                                    } else if (!status && node.src.match(READ_IMG + '$')) {
                                        node.src = UNREAD_IMG;
                                    }
                                }
                            });
                        }
                    }
                }
            };
            var errorFunc = function(res) {
                alert('Change of read status failed, code: ' + res.status);
            };
            setProps(sXml, loadFunc, errorFunc);
        }
    }

    function addMarkRead(row) {
        addToolbarButton(toolbarTable, 'R', function() {
            changeReadStatus(true);
        });
    }

    function addMarkUnread(row) {
        addToolbarButton(toolbarTable, 'U', function() {
            changeReadStatus(false);
        });
    }

    var toolbarTable = getToolbarTable();
    if (toolbarTable) {
        addSelectAll(toolbarTable);
        addSelectNone(toolbarTable);
        addMarkRead(toolbarTable);
        addMarkUnread(toolbarTable);
    }

    // if this is the find names popup form let <enter> work as submit
    var findNamesForm = getFindNamesForm();
    if (findNamesForm) {
        var inputs = document.getElementsByTagName('input');
        for (var i = 0; i < inputs.length; i++) {
            var input = inputs[i];
            if (input.type == 'text') {
                input.addEventListener('keypress', function(evt) {
                    if (evt.keyCode == 13) findNamesForm.submit();
                }, true);
            }
        }
    }
}

)();

