var is = new Is;

var g_got_letter = false;
var g_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var g_letter_expr = /^[A-Z?]$/;
var g_answer = "";

var g_phrases = new Array ();
var g_difficulties = new Array ();
var g_analysis = null;
var g_max_phrase = 0;


/**************************************
/ Load the initial display on startup /
/ and set other event handler calls   /
**************************************/

window.onload = init_cryptogram;
window.onerror = errorTrap;

document.onclick = f_click;
document.onkeypress = f_keypress;


/******************************
/ Text manipulation functions /
******************************/

function f_letter (l_letter)
{
        var l_text = null;

        l_letter = l_letter.toUpperCase();
        if (g_letter_expr.test (l_letter) )
        {
                if (g_got_letter)
                {
                        if ((letter1.innerText == "?") || (l_letter == "?"))
                                l_text = cryptotext.innerText;
                        else
                        {
                                f_display_text (letter2, l_letter);
                                l_text = f_swap (cryptotext.innerText, letter1.innerText, l_letter);
                        }

                        f_update_analysis (letter1.innerText, l_letter);
                        f_display_text (cryptotext, l_text);
                        f_display_text (letter1, "_");
                        f_display_text (letter2, "_");
                        g_got_letter = false;

                        if (cryptotext.innerText == g_answer)
                                reward.style.visibility = "visible";
                        else
                                reward.style.visibility = "hidden";
                }
                else
                {
                        f_display_text (letter1, l_letter);
                        g_got_letter = true;
                }
        }
}


function f_swap (l_text, l_letter1, l_letter2)
{
        var l_char = "#";
        var l_expr;
        var l_temp1;
        var l_temp2;

        l_letter1 = l_letter1.toUpperCase ();  // First do capital letters
        l_letter2 = l_letter2.toUpperCase ();

        l_expr = new RegExp (l_letter1, "g");  // Replace letter 1 with temp char
        l_text = l_text.replace (l_expr, l_char);

        l_expr = new RegExp (l_letter2, "g");  // Replace letter 2 with letter 1
        l_text = l_text.replace (l_expr, l_letter1);

        l_expr = new RegExp (l_char, "g");     // Replace temp char with letter 2
        l_text = l_text.replace (l_expr, l_letter2);

        l_letter1 = l_letter1.toLowerCase ();  // Next do lowercase letters
        l_letter2 = l_letter2.toLowerCase ();

        l_expr = new RegExp (l_letter1, "g");  // Replace letter 1 with temp char
        l_text = l_text.replace (l_expr, l_char);

        l_expr = new RegExp (l_letter2, "g");  // Replace letter 2 with letter 1
        l_text = l_text.replace (l_expr, l_letter1);

        l_expr = new RegExp (l_char, "g");     // Replace temp char with letter 2
        l_text = l_text.replace (l_expr, l_letter2);

        return l_text;
}


function f_update_analysis (l_letter1, l_letter2)
{
        var c;
        var a;
        var celli = 1;

        if (g_analysis)
        {
                if (l_letter1 != l_letter2 && g_analysis.Exists (l_letter1) &&
                        g_analysis.Exists (l_letter2))
                {
                        g_analysis.Key (l_letter1) = "TEMP";
                        g_analysis.Key (l_letter2) = l_letter1;
                        g_analysis.Key ("TEMP") = l_letter2;

                        a = (new VBArray (g_analysis.Keys())).toArray ();
                        for (c in a)
                                document.all("cell" + celli++).innerText = a[c] + " " + g_analysis (a[c]);
                }
        }
}


function f_scramble (l_text) {
        var c1 = "";
        var c2 = "";
        var i;
        var l_alphabet;
        var l_expr = null;

        for (i = 1; i <= 3; i++) {
                l_alphabet = g_alphabet;
                while (l_alphabet.length > 0) {
                        if (c1 == "")
                        {
                                c1 = f_random_letter (l_alphabet);
                                l_expr = new RegExp (c1);
                                l_alphabet = l_alphabet.replace (l_expr, "");   // remove letter
                        }
                        else
                        {
                                c2 = f_random_letter (l_alphabet);
                                l_expr = new RegExp (c2);
                                l_alphabet = l_alphabet.replace (l_expr, "");   // remove letter

                                l_text = f_swap (l_text, c1, c2);
                                c1 = "";
                                c2 = "";
                        }
                }
        }
        return l_text
}


/*********************************************************************
/ Set up the initial values in the analysis object and table.
/ On systems that don't support ActiveX objects (Macs, for instance),
/ the 'new ActiveXObject' call will fail.  errorTrap will catch the
/ error, preventing a message from reaching the user, and g_analysis
/ will still be set to null.  Before using g_analysis elsewhere,
/ check to make sure it has a value.
*********************************************************************/

function f_initial_analysis ()
{
        var c;
        var i;
        var a;
        var celli = 1;
        var maxc = " ";
        var maxvalue = 0;
        var s = cryptotext.innerText;
        var l_temp = null;

        l_temp = new ActiveXObject ("Scripting.Dictionary");  // fails on
                                                         // systems without
        g_analysis = new ActiveXObject ("Scripting.Dictionary");    // ActiveX

        for (i = 0; i <= 25; i++)                       // set up the dictionary
                l_temp.Add (g_alphabet.substr (i, 1), 0);

        for (i = 0; i <= s.length; i++)                 // load it
        {
                c = (s.substr (i, 1)).toUpperCase ();

                if (l_temp.Exists (c))
                        l_temp.Item (c) += 1;
        }

        for (i = 0; i <= 25; i++)                       // sort it
        {
                maxc = "";
                maxvalue = -1;
                a = (new VBArray (l_temp.Keys())).toArray ();
                for (c in a)
                        if (l_temp (a[c]) > maxvalue)
                        {
                                maxc = a[c];
                                maxvalue = l_temp (a[c]);
                        }
                g_analysis.Add (maxc, maxvalue);
                l_temp.Remove (maxc);
        }

        a = (new VBArray (g_analysis.Keys())).toArray ();
        for (c in a)
                document.all("cell" + celli++).innerText = a[c] + " " + g_analysis (a[c]);

        analysisHeader.style.visibility = "visible";
}


/********************
/ Startup functions /
********************/

function init_cryptogram ()
{
        var l_text = "";
        var l_phraseID = null;
        var params = location.search;
        var phrase_expr = /PHRASE=(\d+)/i;

        if (params)
        {
                params.match (phrase_expr);
                l_phraseID = RegExp.$1;
        }

        f_load_phrases ();
        g_answer = f_get_phrase (l_phraseID);
        l_text = f_scramble (g_answer);
        f_display_text (cryptotext, l_text);
        f_initial_analysis ();
}


function f_get_phrase (l_int) {
        var l_text = "";
        var l_title_tag;

        if (l_int == null || l_int == "")
                l_int = f_random (g_max_phrase) + 1;    // necessary to add one?

        if (l_int < 0)
        {
                g_answer = "";
                l_text = showModalDialog ("enterPhrase.html", is.mac,
                        "dialogWidth: 720px; dialogHeight: 300px; center: yes" );
                f_display_text (title, "User-entered phrase" );
                f_display_text (cryptotext, l_text);
                f_initial_analysis ();
        }       
        else
        {
                --l_int;
                l_text = g_phrases[l_int];
                f_display_text (title, "Phrase " + (l_int + 1) + " of " + g_max_phrase +
                        " (" + g_difficulties[l_int] + ") ..." );
        }

        return l_text;
}


/*********************************************************************
/ Enter some phrases into the phrase list.
/ Be careful with special characters.  In particular, don't enter
/ phrases with multiple spaces.  They get condensed to a single space
/ on IE for Mac, so the user's entry and the correct string will
/ never match and the reward picture doesn't appear.  ("two  spaces"
/ is different from "two spaces").  Presumably, this applies to other
/ special browser characters like angle brackets, etc.
*********************************************************************/

function f_load_phrases ()
{
        f_add_phrase ("Better to remain silent and have people think you a " +
                "fool than to open your mouth and prove them right. - Mark Twain",
                "Easy");

        f_add_phrase ("Early to bed and early to rise, till you make enough " +
                "money to do otherwise. - not Ben Franklin", "Easy");

        f_add_phrase ("Defeat of deduct went over defense before detail.",
                "Difficult");

        f_add_phrase ("When things seem bad and life's a curse, cheer up! " +
                "Tomorrow could be worse!", "Easy");

        f_add_phrase ("Portuguese proverb: Chairs sink, but stools float.",
                "Difficult");

        f_add_phrase ("Persons residing in crystalline domiciles should not " +
                "indulge in the ancient and primeval pastime of hurling bits of " +
                "geological formation through the atmosphere with considerable " +
                "velocity.", "Medium");

        f_add_phrase ("There was a young lady named Bright / " +
                "Who could travel much faster than light. / " +
                "She set out one day / In a relative way / " +
                "And returned the previous night.", "Easy");

        f_add_phrase ("\"Ubi non accusator, ibi non judex\" - roughly, \"Where " +
                "there is no patrol car, there is no speed limit.\"", "Killer");

        f_add_phrase ("'Twas brillig, and the slithy toves / Did gyre and gimbol " +
                "in the wabe. / All mimsy were the borogoves, / and the mome raths " +
                "outgrabe.", "Difficult");

        f_add_phrase ("We the people of the United States, in order to form a " +
                "more perfect union, establish justice, ensure domestic tranquility, " +
                "provide for the common defense, promote the general welfare, and " +
                "ensure the blessings of liberty to ourselves and our posterity do " +
                "ordain and establish this Constitution of the United States of " +
                "America.", "Easy");

        f_add_phrase ("Through three cheese trees three free fleas flew. While " +
                "these fleas flew, freezy breeze blew. Freezy breeze made these " +
                "three trees freeze. Freezy trees made these trees' cheese freeze. " +
                "That's what made these three free fleas sneeze. - Dr. Seuss",
                "Medium");

        f_add_phrase ("I've got this terrible pain in all the diodes down my " +
                "left side, I mean I've asked for them to be replaced but no one " +
                "ever listens. - Marvin, the paranoid android (Douglas Adams)", "Easy");

        f_add_phrase ("Now we are forced to recognize our inhumanity. Our " +
                "reason coexists with our insanity. And though we choose between " +
                "reality and madness, it's either sadness or euphoria. - Billy Joel",
                "Medium");

        f_add_phrase ("Christmas time is here, by golly. Disapproval would be " +
                "folly / Deck the halls with hunks of holly, fill the cup and don't " +
                "say 'when' / Kill the turkeys, ducks and chickens, mix the punch, " +
                "drag out the Dickens / Even though the prospect sickens, brother, " +
                "here we go again. - Tom Lehrer", "Easy");

        f_add_phrase ("... twenty centuries of stony sleep / Were vexed to " +
                "nightmare by a rocking cradle / And what rough beast, its hour come " +
                "round at last / Slouches towards Bethlehem to be born? - Yeats",
                "Medium");

        f_add_phrase ("So we beat on, boats against the current, borne back " +
                "ceaselessly into the past. - Fitzgerald", "Hard");
}


function f_add_phrase (l_phrase, l_difficulty)
{
        g_phrases [g_max_phrase] = l_phrase;
        g_difficulties [g_max_phrase++] = l_difficulty;
}


/************
* Utilities /
************/

function f_display_text (pobjDest, pstrText)
{
        pobjDest.innerText = pstrText;
}


function f_random_letter (l_alphabet) {
        var i = f_random (l_alphabet.length);

        return l_alphabet.charAt (i);
}


function f_random (l_max)
{
        return (Math.floor (l_max * Math.random () ) );
}


/*****************
* Event handlers /
*****************/

function f_click ()
{
        var l_obj = window.event.srcElement;

        if (l_obj.className == "aletter")
        {
                f_letter (l_obj.innerText);
                event.returnValue = false;
                event.cancelBubble = true;
        }

        if (l_obj.className == "hint")
        {
                f_letter ("?")
                event.returnValue = false;
                event.cancelBubble = true;
        }
}


function f_keypress ()
{
        var l_keycode = event.keyCode;
        if (l_keycode >= 97 && l_keycode <= 122)
                l_keycode -= 32

        if (l_keycode == 63)
        {
                f_letter ("?");
                event.returnValue = false;
                event.cancelBubble = true;
        }

        if (l_keycode >= 65 && l_keycode <= 90)
        {
                f_letter (g_alphabet.substr (l_keycode - 65, 1) );
                event.returnValue = false;
                event.cancelBubble = true;
        }
}


function f_analysis_click ()
{
        if (analysisHeader.className == "anHidden")
        {
                analysisHeader.className = "anVisible";
                analysisHeader.children(0).src = "Arrow down.gif";
                analysisDetail.style.visibility = "visible";
        }
        else
        {
                analysisHeader.className = "anHidden";
                analysisHeader.children(0).src = "Arrow right.gif";
                analysisDetail.style.visibility = "hidden";
        }
}
