/*
This code may be used internally to Travelocity without limitation,
exclusion, or restriction.  If this code is used externally the
following comment must be included everywhere this code is used.
*/

/***********************************************************************
This is written by Austin Cheney on 7 May 2009.  Anybody may use this
code without permission so long as this comment exists verbatim in each
instance of its use.

http://www.travelocity.com/
http://mailmarkup.org/
***********************************************************************/

/*
This function is the heart behind the per character logic of the pretty
diff engine.  The logic from diff lib performs comparisons per lines of
code, but does not illustrate per character differences for the diffview
output.

At the time of this writing only side-by-side view receives the benefit
of this logic, although inline view excepted to receive this benefit as
a later enhancement.
------------------------------------------------------------------------    
*/
"use strict";
var charcomp = function (c, d) {
    var i, j, k = 0,
    m, n, p, r = 1,
    ax, bx, zx, em = new RegExp(/em>/g),
    entity,
    compare,
    a = c.innerHTML,
    b = d.innerHTML;

    //JavaScript evaluates double quotes to single quote
    //characters during evaluation by the JavaScript
    //interpreter.  This makes logic comparisons of a double
    //quote character to a single quote character impossible
    //unless they are escaped to something the browser does not
    //recognize and then convert them back after initial
    //comparisons are made.
    a = a.replace(/\'/g, "$#39;");
    a = a.replace(/\"/g, "$#34;");
    a = a.replace(/\&nbsp;/g, " ");
    b = b.replace(/\'/g, "$#39;");
    b = b.replace(/\"/g, "$#34;");
    b = b.replace(/\&nbsp;/g, " ");

    //If the input lines are identical then an exhaustive
    //comparison is a wasted exercise.
    if (a === b) {
        return;
    } else {
        ax = a.split('');
        bx = b.split('');
        if (ax.length >= bx.length) {
            zx = ax.length;
        } else if (bx.length > ax.length) {
            zx = bx.length;
        }

        //This is a massive amount of code for a very simple
        //task. Entities that have been split per character
        //along with their containing data must be reconstituted
        //so that they can be accurately interpreted.
        entity = function (z) {
            for (n = k; n < zx; n += 1) {
                if (z[n] === "&" && z[n + 1] === "g" && z[n + 2] === "t" && z[n + 3] === ";") {
                    z[n] = '&gt;';
                    z.splice(n + 1, 3);
                } else if (z[n] === "&" && z[n + 1] === "l" && z[n + 2] === "t" && z[n + 3] === ";") {
                    z[n] = '&lt;';
                    z.splice(n + 1, 3);
                } else if (z[n] === "$" && z[n + 1] === "#" && z[n + 2] === "3" && z[n + 3] === "9" && z[n + 4] === ";") {
                    z[n] = "'";
                    z.splice(n + 1, 4);
                } else if (z[n] === "$" && z[n + 1] === "#" && z[n + 2] === "3" && z[n + 3] === "4" && z[n + 4] === ";") {
                    z[n] = '"';
                    z.splice(n + 1, 4);
                } else if (z[n] === "$" && z[n + 1] === "#" && z[n + 2] === "4" && z[n + 3] === "7" && z[n + 4] === ";") {
                    z[n] = '/';
                    z[n + 1] = '/';
                    z.splice(n + 2, 3);
                } else if (z[n] === "&" && z[n + 1] === "n" && z[n + 2] === "b" && z[n + 3] === "s" && z[n + 4] === "p" && z[n + 5] === ";") {
                    z[n] = ' ';
                    z.splice(n + 1, 5);
                }
            }
        };
        entity(ax);
        entity(bx);

        //This function actually determines if the same
        //character positions in two compared arrays match.  If
        //not an <em> tag is opened.  If a match is then
        //detected, or if a space is being compared to an
        //undefined character the <em> tag is closed.  This
        //logic occurs for the duraction of the character length
        //of given lines of code so that many separate matches
        //can be specified perline.
        compare = function () {
            for (i = k; i < zx; i += 1) {
                if (ax[i] === bx[i]) {
                    r = i;
                } else {
                    if (ax[i] === undefined && (bx[i] === '' || bx[i] === ' ')) {
                        ax[i] = ' ';
                    } else if (bx[i] === undefined && (ax[i] === '' || ax[i] === ' ')) {
                        bx[i] = ' ';
                    } else if (ax[i] !== bx[i] && em.test(ax[i]) === false && em.test(bx[i]) === false && em.test(ax[i - 1]) === false && em.test(bx[i - 1]) === false) {
                        if (ax[i] !== undefined && bx[i] !== undefined) {
                            ax[i] = "<em>" + ax[i];
                            bx[i] = "<em>" + bx[i];
                        } else if (ax[i] === undefined && bx[i] !== undefined) {
                            ax[i] = "<em> ";
                            bx[i] = "<em>" + bx[i];
                        } else if (ax[i] !== undefined && bx[i] === undefined) {
                            ax[i] = "<em>" + ax[i];
                            bx[i] = "<em> ";
                        }
                    }
                    break;
                }
            }
            for (j = i; j < zx; j += 1) {
                if (ax[j] !== undefined && bx[j] === undefined) {
                    bx[j] = " ";
                } else if (ax[j] === undefined && bx[j] !== undefined) {
                    ax[j] = " ";
                } else if (ax[j] === bx[j]) {
                    ax[j - 1] = ax[j - 1] + "</em>";
                    bx[j - 1] = bx[j - 1] + "</em>";
                    k = j;
                    break;
                }
            }
        };

        //This logic determines if the entire line of code has
        //has not been evaluated that the compare function must
        //fire again.  This logic is what allows multiple
        //comparisons per line of code.
        for (p = 0; p < zx; p += 1) {
            if (r + 1 !== zx) {
                compare();
            }
        }
        //This is where the charcomp output is created.
        c.innerHTML = ax.join('');
        d.innerHTML = bx.join('');
    }
};