// ==UserScript==
// @name                Printable receipt enhancer
// @version             1.0
// @date                2008-10-30
// @author              Ian Malpass ( ian AT etsyhacks DOT com )
// @namespace           etsy.com
// @description         Adds IDs and class names on the printer-friendly receipt, to make it easier to customise
// @include             http://www.etsy.com/receipt_print.php?order_id=*
// ==/UserScript==

/*
The tags on the printable receipt page on Etsy doesn't have many id or class attributes
which makes it hard to style with CSS. This script adds in attributes so that you can
apply stylesheets (or other Greasemonkey scripts) to customise the page to suit your
needs.

It includes an option to specify the URL of an external stylesheet, or some inline CSS
directives.


See also: http://www.etsyhacks.com/greasemonkey/printable_receipt_enhancer.html
*/

var dialogRef;     // location to stash a ref to the config dialog
var stylesheetRef; // location to stash a ref to the stylesheet node, if there is one
var linkRef;       // location to stash a ref to the stylesheet node, if there is one

// Set up the menu option
GM_registerMenuCommand( 'Configure printer-friendly styles', showConfigDialog );
GM_registerMenuCommand( 'Enable/disable styles', toggleStyles );

// Add the CSS rules, if any
var enabled = GM_getValue( 'cssEnabled' );
enabled = ( enabled == null || enabled == 1 ) ? 0 : 1;
GM_setValue( 'cssEnabled', enabled );
toggleStyles();

// Add the IDs and class names
annotatePage();

function initCSS ( clear ) {
    // clear the stylesheet and CSS link if they are there
    if ( stylesheetRef != null ) {
        stylesheetRef.parentNode.removeChild( stylesheetRef );
        stylesheetRef = null;
    }
    if ( linkRef != null ) {
        linkRef.parentNode.removeChild( linkRef );
        linkRef = null;
    }

    if ( clear == null || ! clear ) {
        var head = document.getElementsByTagName( 'head' )[0];

        // if we have a URL specified, create a link node
        var link = GM_getValue( 'cssURL' );
        if ( link ) {
            linkRef= document.createElement( 'link' );
            linkRef.rel  = 'stylesheet';
            linkRef.href = link;
            linkRef.type = 'text/css';
            head.appendChild( linkRef );
        }

        // if we have CSS rules specified, create a style node
        var css = GM_getValue( 'css' );
        if ( css ) {
            stylesheetRef = document.createElement( 'style' );
            stylesheetRef.type = 'text/css';
            stylesheetRef.innerHTML = css;
            head.appendChild( stylesheetRef );
        }
        GM_setValue( 'cssEnabled', 1 );
    } else {
        GM_setValue( 'cssEnabled', 0 );
    }
}    

function toggleStyles () {
    var enabled = GM_getValue( 'cssEnabled' );
    if ( enabled == null || enabled == 1 ) {
        initCSS( true );
    } else {
        initCSS();
    }
}

function showConfigDialog () {
    var dialog = makeDialog();
    dialogRef = dialog;
    document.body.insertBefore( dialog, document.body.firstChild );
    // need to user addEventListener to make sure that the events can access this script's functions
    document.getElementById( 'cancelDialog' ).addEventListener( 'click', cancelConfigDialog, true );
    document.getElementById( 'saveDialog' ).addEventListener( 'click', saveConfigDialog, true );
    window.scrollTo( 0, 0 );
}

function cancelConfigDialog () {
    // do nothing, just get rid of the dialog
    dialogRef.parentNode.removeChild( dialogRef );
}    

function saveConfigDialog () {
    var css = document.getElementById( 'cssStringValue' ).value;
    var url = document.getElementById( 'cssURLValue' ).value;
    GM_setValue( 'css', css );   // stash the values
    GM_setValue( 'cssURL', url );
    cancelConfigDialog(); // get rid of the dialog
    initCSS(); // and re-do the CSS
}    

function makeDialog () {
    var css    = GM_getValue( 'css' ) || "";
    var cssURL = GM_getValue( 'cssURL' ) || "";
    var configDialog = document.createElement( 'div' );
    var configHTML  = '<div style="position: absolute; background: #ffffff; border: 1px solid rgb(234, 233, 228); text-align: left; margin: 10px; width: 50em;">';
    configHTML     += '<div style="background: rgb(234, 233, 228); font-weight: bold; padding: 2px 6px; ">printer-friendly receipt style settings</div>';
    configHTML     += '<div style="padding: 5px">';
    configHTML     += '<table width="100%"><tr><td style="padding: 4px; text-align: right" width="17%">Stylesheet URL</td><td style="padding: 2px;"><input type="text" id="cssURLValue" style="border: 1px solid #999999; width: 100%" value="' + cssURL + '" /></td></tr>';
    configHTML     += '<tr><td style="padding: 4px; text-align: right" valign="top">CSS</td><td style="padding: 2px;"><textarea id="cssStringValue" style="border: 1px solid #999999; width: 100%; height: 10em;">' + css + '</textarea></td></tr>';
    configHTML     += '<tr><td colspan="2" style="padding: 4px; text-align: right"><div onmouseover="this.style.background = \'#999999\'" onmouseout="this.style.background = \'#ffffff\'" id="cancelDialog" style="cursor: pointer; border: 1px solid #999999; width: 4em; text-align: center; padding: 2px 4px; float: right;">cancel</div><div onmouseover="this.style.background = \'#999999\'" onmouseout="this.style.background = \'#ffffff\'" id="saveDialog" style="cursor: pointer; border: 1px solid #999999; width: 4em; text-align: center; padding: 2px 4px; float: right; margin-right: 5px">save</div></td></tr>';
    configHTML     += '</table>';
    configHTML     += '</div></div>';
    configDialog.innerHTML  = configHTML;
    return configDialog;
}

// Just a long list of lines finding elements and adding ID and class attributes
// More of these could/should be done in a loop, really
function annotatePage () {
    var tables = document.getElementsByTagName( 'table' );
    tables[ 0 ].id = 'rootTable1';
    tables[ 1 ].id = 'rootTable2';
    tables[ 2 ].id = 'rootTable3';
    var rowIds = [
        'bannerRow',
        'titleRow',
        'spacerRow1',
        'sellerBuyerRow',
        'spacerRow2',
        'orderSectionHeaderRow',
        'spacerRow3',
        'orderDetailsRow',
        'spacerRow4',
        'paymentSectionHeaderRow',
        'spacerRow5',
        'paymentDetailsRow',
        'spacerRow6',
        'shipToSectionHeaderRow',
        'spacerRow7',
        'shipToDetailsRow',
        'spacerRow8',
        'notesSectionHeaderRow',
        'spacerRow9',
        'notesDetailsRow'
    ];
    var tbody = tables[ 2 ].getElementsByTagName( 'tbody' )[0];
    var idCounter = 0;
    for ( var r = 0; r < tables[ 2 ].rows.length; r++ ) {
        var row = tables[ 2 ].rows[ r ];
        row.id = rowIds[ r ];
        if ( row.id.indexOf( 'spacerRow' ) == 0 ) {
            row.className = 'spacerRow';
        } else if ( row.id.indexOf( 'HeaderRow' ) > -1 ) {
            row.className = 'headerRow';
        } else if ( row.id.indexOf( 'DetailsRow' ) > -1 ) {
            row.className = 'detailsRow';
        }
    }

    var cells = document.getElementById( 'titleRow' ).getElementsByTagName( 'td' );
    cells[ 1 ].id = "orderNumberCell";
    cells[ 2 ].id = "viewOriginalCell";

    var sellerBuyerTables = document.getElementById( 'sellerBuyerRow' ).getElementsByTagName( 'table' );
    var rows = sellerBuyerTables[ 0 ].rows;
    rows[ 0 ].id = 'sellerBuyerSectionHeaderRow';
    rows[ 0 ].className = 'headerRow';
    rows[ 1 ].id = 'spacerRow10';
    rows[ 1 ].className = 'spacerRow';
    rows[ 2 ].id = 'sellerBuyerDetailsRow';
    rows[ 2 ].className = 'detailsRow';
    var headerCells = rows[ 0 ].cells;
    headerCells[ 0 ].id = 'sellerHeaderCell';
    headerCells[ 1 ].id = 'buyerHeaderCell';

    sellerBuyerTables[ 1 ].id = 'sellerTable';
    sellerBuyerTables[ 1 ].className = 'greyBorder'; 
    sellerBuyerTables[ 1 ].rows[ 0 ].cells[ 0 ].id = 'sellerIconCell';
    var img = sellerBuyerTables[ 1 ].rows[ 0 ].cells[ 0 ].getElementsByTagName( 'img' )[ 0 ];
    img.className = 'userIcon';
    img.id = 'sellerIcon';
    sellerBuyerTables[ 1 ].rows[ 0 ].cells[ 0 ].className = 'userIconCell';
    sellerBuyerTables[ 1 ].rows[ 0 ].cells[ 1 ].id = 'sellerDetailsCell';
    sellerBuyerTables[ 1 ].rows[ 0 ].cells[ 1 ].className = 'userDetailsCell';
    var table = sellerBuyerTables[ 1 ].rows[ 0 ].cells[ 1 ].getElementsByTagName( 'table' )[ 0 ];
    table.id = 'sellerDetailsTable';
    table.className = 'detailsTable';
    table.rows[ 0 ].className = 'userProfileRow';
    table.rows[ 0 ].id        = 'sellerProfileRow';
    table.rows[ 1 ].className = 'userRatingRow';
    table.rows[ 1 ].id        = 'sellerRatingRow';
    table.rows[ 2 ].className = 'userLocationRow';
    table.rows[ 2 ].id        = 'sellerLocationRow';
    table.rows[ 3 ].className = 'userEmailRow';
    table.rows[ 3 ].id        = 'sellerEmailRow';

    sellerBuyerTables[ 3 ].id = 'buyerTable';
    sellerBuyerTables[ 3 ].className = 'greyBorder'; 
    sellerBuyerTables[ 3 ].rows[ 0 ].cells[ 0 ].id = 'buyerIconCell';
    var img = sellerBuyerTables[ 3 ].rows[ 0 ].cells[ 0 ].getElementsByTagName( 'img' )[ 0 ];
    img.className = 'userIcon';
    img.id = 'buyerIcon';
    sellerBuyerTables[ 3 ].rows[ 0 ].cells[ 0 ].className = 'userIconCell';
    sellerBuyerTables[ 3 ].rows[ 0 ].cells[ 1 ].id = 'buyerDetailsCell';
    sellerBuyerTables[ 3 ].rows[ 0 ].cells[ 1 ].className = 'userDetailsCell';
    var table = sellerBuyerTables[ 3 ].rows[ 0 ].cells[ 1 ].getElementsByTagName( 'table' )[ 0 ];
    table.rows[ 0 ].className = 'userProfileRow';
    table.rows[ 0 ].id        = 'buyerProfileRow';
    table.rows[ 1 ].className = 'userRatingRow';
    table.rows[ 1 ].id        = 'buyerRatingRow';
    table.rows[ 2 ].className = 'userLocationRow';
    table.rows[ 2 ].id        = 'buyerLocationRow';
    table.rows[ 3 ].className = 'userEmailRow';
    table.rows[ 3 ].id        = 'buyerEmailRow';

    var cells = document.getElementById( 'orderSectionHeaderRow' ).getElementsByTagName( 'td' );
    cells[ 1 ].id = 'orderHeaderCell';
    cells[ 2 ].id = 'currencyCell';

    var itemTables = document.getElementById( 'orderDetailsRow' ).getElementsByTagName( 'table' );
    for ( var t = 1; t < itemTables.length - 1; t++ ) {
        table = itemTables[ t ];
        table.id = 'itemTable_' + t;
        table.className = 'itemTable';
        var row = table.rows[ 0 ];
        row.cells[ 0 ].className = 'itemImageCell';
        row.cells[ 1 ].className = 'itemLinkCell';
        row.cells[ 2 ].className = 'itemSpacerCell1';
        row.cells[ 3 ].className = 'itemPriceCell';
        row = table.rows[ 1 ];
        row.cells[ 0 ].className = 'itemTransactionCell';
        row.cells[ 1 ].className = 'itemQuantityLabelCell';
        row.cells[ 2 ].className = 'itemQuantityCell';
        row = table.rows[ 2 ];
        row.cells[ 0 ].className = 'itemSpacerCell2';
        row.cells[ 1 ].className = 'itemShippingLabelCell';
        row.cells[ 2 ].className = 'itemShippingCell';
    }
    itemTables[ 0 ].className = 'greyBorder';
    itemTables[ 0 ].rows[ itemTables[ 0 ].rows.length -1 ].id = 'itemsTotalRow';
    itemTables[ itemTables.length - 1 ].rows[ 0 ].cells[ 0 ].id = 'itemsTotalLabel';
    itemTables[ itemTables.length - 1 ].rows[ 0 ].cells[ 1 ].id = 'itemsTotalValue';

    var paymentTables = document.getElementById( 'paymentDetailsRow' ).getElementsByTagName( 'table' );
    paymentTables[ 0 ].className = 'greyBorder';
    if ( paymentTables[ 1 ].rows[ 0 ].cells.length > 2 ) {
    } else {
        paymentTables[ 1 ].rows[ 0 ].cells[ 0 ].id = 'paymentCell';
        paymentTables[ 1 ].rows[ 0 ].cells[ 1 ].id = 'paymentNotesCell';
        if ( paymentTables[ 2 ] ) {
            paymentTables[ 2 ].rows[ 0 ].cells[ 0 ].id = 'paymentStatusIconCell';
            paymentTables[ 2 ].rows[ 0 ].cells[ 1 ].id = 'paymentMethodCell';
            paymentTables[ 2 ].rows[ 1 ].cells[ 0 ].id = 'paymentAmountCell';
        } else {
        }
    }

    var shippingTables = document.getElementById( 'shipToDetailsRow' ).getElementsByTagName( 'table' );
    shippingTables[ 0 ].className = 'greyBorder';
    var address = shippingTables[ 1 ].rows[ 0 ].cells[ 0 ];
    address.id = 'addressCell';
    var fragment = document.createDocumentFragment();
    var spans = address.getElementsByTagName( 'span' );
    if ( spans.length > 0 ) {
        var span = spans[ 0 ];
        span.id = 'crossReferenceWarning';
        fragment.appendChild( span );
        address.innerHTML = '<span id="address">' + address.innerHTML + '</span>';
        address.appendChild( fragment );
    } else {
        address.innerHTML = '<span id="address">' + address.innerHTML + '</span>';
    }

    var notesTables = document.getElementById( 'notesDetailsRow' ).getElementsByTagName( 'table' );
    notesTables[ 0 ].className = 'greyBorder';
    notesTables[ 1 ].rows[ 0 ].id = 'sellerMessageHeaderRow';
    notesTables[ 1 ].rows[ 1 ].id = 'sellerMessageRow';
    notesTables[ 1 ].rows[ 2 ].id = 'spacerRow11';
    notesTables[ 1 ].rows[ 2 ].className = 'spacerRow';
    notesTables[ 1 ].rows[ 3 ].id = 'buyerMessageHeaderRow';
    notesTables[ 1 ].rows[ 4 ].id = 'buyerMessageRow';
}

