
function jellybrations_setup()
{
    if (!document) {
        return;
    }
    var body = document.getElementsByTagName('body').item(0);
    if (!octalClass_inlist(body, 'page_jellybrations')) {
        return;
    }

    /** Get the text content of a sub-node with tag 'name' */
    function subElemText(node, subnodename) {
        var subnodes = node.getElementsByTagName(subnodename);
        if (!subnodes || subnodes.length != 1) {
            return '';
        }
        return octalDomText(subnodes.item(0));
    }

    /** Remove all the children node from a node */
    function nodeRemoveChildren(elem) {
        while (elem.firstChild) {
            elem.removeChild(elem.firstChild);
        }
    }


    /** Replace all the children from a node with a new child node */
    function nodeReplaceChildren(elem, newchild) {
        nodeRemoveChildren(elem);
        elem.appendChild(newchild);
    }


    /** Renumber and re-mark as odd/even the orderitem rows on a page */
    function renumberRows(doc) {
        var tbody;

        tbody = doc.getElementById('orderitems_rows');
        if (tbody && tbody.childNodes && tbody.childNodes.length) {
            var rows = tbody.getElementsByTagName('tr');
            for (var i = 0; i < rows.length; ++i) {
                var row = rows.item(i);
                var n = (i % 2 == 0) ? (i / 2) : ((i - 1) / 2);

                octalClass_setlist(row, [(n % 2 == 0) ? 'even' : 'odd']);
                if ((i % 2 == 0) && row.firstChild) {
                    nodeReplaceChildren(row.firstChild,
                            doc.createTextNode(n + 1));
                }
            }
        }

        tbody = doc.getElementById('orderitems_occasions');
        if (tbody && tbody.childNodes && tbody.childNodes.length) {
            var rows = tbody.getElementsByTagName('tr');
            for (var i = 0; i < rows.length; ++i) {
                var row = rows.item(i);
                octalClass_setlist(row, [(i % 2 == 0) ? 'even' : 'odd']);
                if (row.firstChild) {
                    nodeReplaceChildren(row.firstChild,
                            doc.createTextNode(i + 1));
                }
            }
        }
    }


    function updatePage(doc, response)
    {
        if (!response || !response.responseXML) {
            return false;
        }

        var list;
        list = response.responseXML.getElementsByTagName('err');
        if (list && list.length) {
            alert(octalDomText(list.item(0)));
            return false;
        }

        list = response.responseXML.getElementsByTagName('size');
        for (var i = 0; i < list.length; ++i) {
            updatePostage(doc, list.item(i));
        }

        list = response.responseXML.getElementsByTagName('item');
        for (var i = 0; i < list.length; ++i) {
            var item = list.item(i);
            var id = item.getAttribute('id');
            if (doc.getElementById('jb_item_row_' + id)) {
                updateRow(doc, item);
            }
            else {
                createRow(doc, item);
            }
        }
        renumberRows(doc);
        return true;
    }


    /** Remove rows for a given order item */
    function removeRow(doc, id)
    {
        var row;
        row = doc.getElementById('jb_item_row_' + id);
        if (row) {
            row.parentNode.removeChild(row);
        }
        row = doc.getElementById('jb_item_message_' + id);
        if (row) {
            row.parentNode.removeChild(row);
        }
        row = doc.getElementById('jb_item_occasion_' + id);
        if (row) {
            row.parentNode.removeChild(row);
        }
    }


    /** Event handler for when the user clicks 'remove' */
    function removeHandler(e)
    {
        e = e ? e : window.event;
        var source = octalEventSrc(this, e);

        var nameparts = source.getAttribute('name').split('_');
        var id = nameparts[nameparts.length - 1];
        var response = octalXmlHttpSync(
                ajaxbase + '/../jellybrations/order.xml?remove=' + id);

        if (!response.responseXML) {
            alert(id + ': No response from server!');
            return octalEventCancel(e);
        }

        var list;
        list = response.responseXML.getElementsByTagName('err');
        if (list && list.length) {
            alert(id + ': ' + octalDomText(list.item(0)));
            return octalEventCancel(e);
        }
        list = response.responseXML.getElementsByTagName('ok');
        if (!list || !list.length) {
            alert(id + ': No confirmation! ' + response.responseText);
            return octalEventCancel(e);
        }

        removeRow(source.ownerDocument, id);
        updatePage(document, octalXmlHttpSync(ajaxbase
                    + '/../jellybrations/order.xml'
                    + '?list=1'));
        return true;
    }


    /** Show the message box for an orderitem, based on checkbox */
    function showItemMessage(messageUseElem)
    {
        var nameparts = messageUseElem.getAttribute('name').split('_');
        var id = nameparts[nameparts.length - 1];

        var messagerow = messageUseElem.ownerDocument.getElementById(
                'jb_item_message_' + id);
        if (messagerow) {
            messagerow.style.display = messageUseElem.checked ? '' : 'none';
        }
    }


    /** Event handler for orderitem "message" checkbox */
    function messageUseHandler(e)
    {
        e = e ? e : window.event;
        var source = octalEventSrc(this, e);

        showItemMessage(source);

        return true;
    }


    /** Show/hide the "occasion" text box, and set text */
    function occasionShowTextBox(row, force)
    {
        var select = row.getElementsByTagName('select').item(0);
        var textbox = row.getElementsByTagName('input').item(0);
        var value = jb_occasiondefs[select.value];

        if (value) {
            if (force || !textbox.value) {
                textbox.value = value;
            }
            textbox.style.display = '';
        }
        else {
            textbox.value = '';
            textbox.style.display = 'none';
        }

        return true;
    }


    /** "Occasion" select box onchange handler */
    function occasionChangeHandler(e)
    {
        e = e ? e : window.event;
        var source = octalEventSrc(this, e);

        occasionShowTextBox(source.parentNode.parentNode, true);

        return true;
    }


    function tdSetColSpan(td, cols) {
        if (octalIE == 6 || octalIE == 7) {
            td.colSpan = cols;
        }
        else {
            td.setAttribute('colspan', cols);
        }
    }


    /** Create new rows in tables for a new order item.
     *
     * \param doc Document to add rows to.
     * \param item XML order item containing data to create rows from.
     */
    function createRow(doc, item)
    {
        var id = item.getAttribute('id');
        var tbody;
        var tr;
        var td;
        var input;
        var select;
        var option;
        var value;

        tbody = doc.getElementById('orderitems_rows');
        if (tbody) {
            tr = doc.createElement('tr');
            tr.setAttribute('id', 'jb_item_row_' + id);

            /* Row number */
            td = doc.createElement('td');
            tr.appendChild(td);

            /* Size */
            td = doc.createElement('td');
            td.appendChild(doc.createTextNode(
                        jb_sizes[subElemText(item, 'size')]));
            tr.appendChild(td);

            /* Price */
            td = doc.createElement('td');
            td.appendChild(doc.createTextNode(subElemText(item, 'price')));
            tr.appendChild(td);

            /* Edge */
            td = doc.createElement('td');
            if (subElemText(item, 'size') != '10pointed') {
                select = doc.createElement('select');
                select.setAttribute('name', 'jb_edge_' + id);
                for (var edge in jb_edges) {
                    option = doc.createElement('option');
                    option.setAttribute('value', edge);
                    option.appendChild(doc.createTextNode(jb_edges[edge]));
                    select.appendChild(option);
                }
                select.value = subElemText(item, 'edge');
                td.appendChild(select);
            }
            else {
                td.appendChild(doc.createTextNode('Pointed'));
            }
            tr.appendChild(td);

            /* Message? */
            value = subElemText(item, 'message');
            td = doc.createElement('td');
            tdSetColSpan(td, 2);
            var messageuse = octalFormInputElementCreate(doc, {
                    'type': 'checkbox',
                    'class': 'checkbox',
                    'name': 'jb_messageuse_' + id,
                    'value': '1',
                    'checked': value.length ? 'checked' : '' });
            td.appendChild(messageuse);
            tr.appendChild(td);

            /* Adhesive? */
            value = parseInt(subElemText(item, 'adhesive'));
            td = doc.createElement('td');
            tdSetColSpan(td, 2);
            td.appendChild(octalFormInputElementCreate(doc, {
                        'type': 'checkbox',
                        'class': 'checkbox',
                        'name': 'jb_adhesive_' + id,
                        'value': '1',
                        'checked': value ? 'checked' : '' }));
            tr.appendChild(td);

            /* Remove */
            td = doc.createElement('td');
            input = octalFormInputElementCreate(doc, {
                    'type': 'button',
                    'class': 'button',
                    'name': 'jb_remove_' + id,
                    'value': 'Remove' });
            octalAddEventListener(input, 'click', removeHandler);
            td.appendChild(input);
            tr.appendChild(td);

            tbody.appendChild(tr);

            /* Message */
            tr = doc.createElement('tr');
            tr.setAttribute('id', 'jb_item_message_' + id);

            td = doc.createElement('td');
            tdSetColSpan(td, 9);
            td.appendChild(octalFormInputElementCreate(doc, {
                        'type': 'text',
                        'class': 'text',
                        'name': 'jb_message_' + id,
                        'value': subElemText(item, 'message')}));
            tr.appendChild(td);

            tbody.appendChild(tr);

            octalAddEventListener(messageuse, 'click', messageUseHandler);
            showItemMessage(messageuse);
        }

        tbody = doc.getElementById('orderitems_occasions');
        if (tbody) {
            tr = doc.createElement('tr');
            tr.setAttribute('id', 'jb_item_occasion_' + id);

            td = doc.createElement('td');
            tr.appendChild(td);

            td = doc.createElement('td');
            select = doc.createElement('select');
            select.setAttribute('name', 'jb_occasion_' + id);
            for (var occasion in jb_occasions) {
                option = doc.createElement('option');
                option.setAttribute('value', occasion);
                option.appendChild(doc.createTextNode(jb_occasions[occasion]));
                select.appendChild(option);
            }
            select.value = subElemText(item, 'occasion');
            octalAddEventListener(select, 'change', occasionChangeHandler);
            td.appendChild(select);
            tr.appendChild(td);

            td = doc.createElement('td');
            td.appendChild(octalFormInputElementCreate(doc, {
                        'type': 'text',
                        'class': 'text',
                        'name': 'jb_occasionmsg_' + id,
                        'value': subElemText(item, 'occasionmsg')}));
            tr.appendChild(td);

            tbody.appendChild(tr);

            occasionShowTextBox(tr, false);
        }
    }


    function updateRow(doc, item)
    {
        var id = item.getAttribute('id');
        var tr = doc.getElementById('jb_item_row_' + id);
        if (!tr
                || tr.childNodes.length < 3)
        {
            return;
        }
        nodeReplaceChildren(tr.childNodes.item(2),
                doc.createTextNode(subElemText(item, 'price')));
    }


    function updatePostage(doc, item)
    {
        var id = item.getAttribute('id');
        if (!id) {
            return;
        }
        var tr = doc.getElementById('jb_size_row_' + id);
        if (!tr
                || tr.childNodes.length < 5)
        {
            return;
        }
        nodeReplaceChildren(tr.childNodes.item(2),
                doc.createTextNode(subElemText(item, 'price')));
        nodeReplaceChildren(tr.childNodes.item(4),
                doc.createTextNode(subElemText(item, 'postage')));

        tr.childNodes.item(3).firstChild.value = subElemText(item, 'count');
    }


    /** Handler for user wanting new items */
    function quantityChangeHandler(e)
    {
        e = e ? e : window.event;
        var source = octalEventSrc(this, e);
        var doc = source.ownerDocument;

        var nameparts = source.getAttribute('name').split('_');
        var size = nameparts[nameparts.length - 1];
        var response = octalXmlHttpSync(ajaxbase
                + '/../jellybrations/order.xml'
                + '?size=' + size
                + '&count=' + source.value);

        if (!updatePage(doc, response)) {
            alert(size + ',' + source.value + ': Unable to update!');
            return octalEventCancel(e);
        }

        return true;
    }


    /** Change the "edge" image on the page to that at a given URL */
    function edgeChange(url)
    {
        var edgeimg = document.getElementById('edgeexampleimg');
        if (edgeimg) {
            edgeimg.setAttribute('src', url);
        }

        var edgelist = document.getElementById('edgeexampleselect');
        if (edgelist) {
            var buttons = edgelist.getElementsByTagName('table');
            for (var i = 0; i < edgelinks.length; ++i) {
                var button = buttons.item(i);
                var a = button.getElementsByTagName('a').item(0);
                if (a.getAttribute('href') == url) {
                    octalClass_add(button, 'hi');
                }
                else {
                    octalClass_remove(button, 'hi');
                }
            }
        }
    }


    /** Event handler for "edge" preview buttons */
    function edgeHandler(e)
    {
        e = e ? e : window.event;
        var source = octalEventSrc(this, e);

        edgeChange(source.getAttribute('href'));

        return octalEventCancel(e);
    }

    function refererShowTextbox(elem)
    {
        var textbox = elem.parentNode.getElementsByTagName('input').item(0);

        switch (elem.value) {
        case '':
        case 'friend':
        case 'florist':
        case 'weddingfayre':
        case 'wedclick':
        case 'weddingservices4u':
        case 'google':
            textbox.style.display = 'none';
            break;

        case 'other':
            textbox.style.display = '';
            break;

        default:
            alert('Unexpected referer ' + elem.value);
            break;
        }
    }


    /** Referer change handler */
    function refererChangeHandler(e)
    {
        e = e ? e : window.event;
        var source = octalEventSrc(this, e);

        refererShowTextbox(source);

        return true;
    }


    /* Code to actually be run on setup */
    var tbody;

    // add quantity change handlers.
    tbody = document.getElementById('jb_sizes');
    if (tbody) {
        var inputs = tbody.getElementsByTagName('select');
        for (var i = 0; i < inputs.length; ++i) {
            octalAddEventListener(inputs.item(i), 'change', quantityChangeHandler);
        }
    }

    /* Add the "edge" preview button handlers */
    var edgelist = document.getElementById('edgeexampleselect');
    if (edgelist) {
        var edgelinks = edgelist.getElementsByTagName('a');
        for (var i = 0; i < edgelinks.length; ++i) {
            octalAddEventListener(edgelinks.item(i), 'click', edgeHandler);
            if (i == 0) {
                edgeChange(edgelinks.item(i).getAttribute('href'));
            }
        }
    }

    // add "message" checkbox and "remove" button change handlers.
    tbody = document.getElementById('orderitems_rows');
    if (tbody) {
        var inputs = tbody.getElementsByTagName('input');
        for (var i = 0; i < inputs.length; ++i) {
            var item = inputs.item(i);

            if (item.getAttribute('type') == 'button') {
                octalAddEventListener(item, 'click', removeHandler);
            }
            else if (item.getAttribute('type') == 'checkbox'
                    && item.getAttribute('id').indexOf('_messageuse_') > -1)
            {
                octalAddEventListener(item, 'click', messageUseHandler);
                showItemMessage(item);
            }
        }
    }

    /* Add "occasion" change handlers and do initial showing/hiding */
    tbody = document.getElementById('orderitems_occasions');
    if (tbody && tbody.childNodes && tbody.childNodes.length) {
        var inputs = tbody.getElementsByTagName('select');
        for (var i = 0; i < inputs.length; ++i) {
            octalAddEventListener(inputs.item(i), 'change', occasionChangeHandler);
        }

        var rows = tbody.getElementsByTagName('tr');
        for (var i = 0; i < rows.length; ++i) {
            occasionShowTextBox(rows.item(i), false);
        }
    }

    /* Add "referer" change handler and set initial state */
    var elem = document.getElementById('referer');
    if (elem) {
        var select = elem.getElementsByTagName('select').item(0);
        octalAddEventListener(select, 'change', refererChangeHandler);
        refererShowTextbox(select);
    }

    /* Do initial update */
    updatePage(document, octalXmlHttpSync(ajaxbase
                + '/../jellybrations/order.xml'
                + '?list=1'));
}
