/*
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,
    n, p, r = 0,
    ax, bx, zx, em = new RegExp(/<em>/g),
    entity,
    compare,
    a = c.innerHTML.replace(/\&nbsp;/g, " "),
    b = d.innerHTML.replace(/\&nbsp;/g, " ");

    //Some older versions of browsers were having trouble comparing
    //between single and double quotes as string literals.  To speed
    //processing for newer browsers remove these lines.
    a = a.replace(/\'/g, "$#39;").replace(/\"/g, "$#34;");
    b = b.replace(/\'/g, "$#39;").replace(/\"/g, "$#34;");

    //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] + z[n + 2] + z[n + 3] === "&gt;") {
                    z[n] = '&gt;';
                    z.splice(n + 1, 3);
                } else if (z[n] + z[n + 1] + z[n + 2] + z[n + 3] === "&lt;") {
                    z[n] = '&lt;';
                    z.splice(n + 1, 3);
                } else if (z[n] + z[n + 1] + z[n + 2] + z[n + 3] + z[n + 4] + z[n + 5] === "&nbsp;") {
                    z[n] = ' ';
                    z.splice(n + 1, 5);
                }
                //If the two lines for replacing quote characters
                //with entities from appoximately 30 lines above
                //were removed then these last two if conditions can
                //also be removed to increase processing speed.
                else if (z[n] + z[n + 1] + z[n + 2] + z[n + 3] + z[n + 4] === "$#34;") {
                    z[n] = "&#34;";
                    z.splice(n + 1, 4);
                } else if (z[n] + z[n + 1] + z[n + 2] + z[n + 3] + z[n + 4] === "$#39;") {
                    z[n] = "&#39;";
                    z.splice(n + 1, 4);
                }
                //Do not remove below this line.
            }
        };
        entity(ax);
        entity(bx);
        for (i = 0; i < zx; i += 1) {
            if (ax[i] === "&" && bx[i] !== "&") {
                bx.splice(i, 0, "", "", "", "");
            } else if (bx[i] === "&" && ax[i] !== "&") {
                ax.splice(i, 0, "", "", "", "");
            }
        }

        //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] !== 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> ";
                        }
                        n = 1;
                    } else if (ax[i] === undefined && (bx[i] === '' || bx[i] === ' ')) {
                        ax[i] = ' ';
                    } else if (bx[i] === undefined && (ax[i] === '' || ax[i] === ' ')) {
                        bx[i] = ' ';
                    }
                    break;
                }
            }
            for (j = i + 1; j < zx; j += 1) {
                if (ax[j] === bx[j]) {
                    ax[j - 1] = ax[j - 1] + "</em>";
                    bx[j - 1] = bx[j - 1] + "</em>";
                    k = j;
                    n = 0;
                    break;
                } else if (ax[j] !== undefined && bx[j] === undefined) {
                    bx[j] = " ";
                } else if (ax[j] === undefined && bx[j] !== undefined) {
                    ax[j] = " ";
                }
            }
            if (j === zx && n === 1) {
                if (ax[j - 1].indexOf("</em>") === -1) {
                    ax[ax.length - 1] = ax[ax.length - 1] + "</em>";
                }
                if (bx[j - 1].indexOf("</em>") === -1) {
                    bx[bx.length - 1] = bx[bx.length - 1] + "</em>";
                }
            }
        };

        //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('');
    }
};