/**
 * RetroWeb Console Emulator for MarkWoodman.com
 * Mildly object oriented JavaScript.
 * Pure silliness, of course.
 *
 * (c) Copyright 2005-2006 Mark Woodman
 */

/** Reference to the textarea used as the console. */
var Console = null;

/**
 * Skynet in the early years.  No need to
 * do the prototype/instance business with this
 * because we only need one of them.
 */
var Kernel = new Object();

/** As close as you can get to constants in JS. */
Kernel.VERSION = "RetroWeb [v2006.07.05.15]";
Kernel.TAGLINE = "It's Space-Age Client-Side Technology!";
Kernel.COPYRIGHT = "(C) Copyright 2006 Mark Woodman";
Kernel.HELP_MSG = "Type 'help' for a list of commands.\n";
Kernel.DEFAULT_PROMPT = "$ ";
Kernel.MAX_ROWS = 50;
Kernel.MAX_COLS = 68;
Kernel.EMAIL_ADDR = "mark@markwoodman.com";
Kernel.LOGO = null;

/** Member variables */
Kernel.promptPostion = 0;
Kernel.promptString = Kernel.DEFAULT_PROMPT;
Kernel.commandHistory = new Array();
Kernel.commandHistoryPos = 0;
Kernel.online = false;


/**
 * Let's get this party started.
 */
Kernel.boot = function(event, initialCommand) 
{
    // Identify the textarea we'll use as the Console.
    if(!Console)
    {
	    Console = document.getElementById('console');
	    Commands.clear();
	}
	
	Console.disabled = false;
	
	// Intercept keyboard events in the Console.
	// TODO:  This is really bad form and should be smacked.
	// The event types act differently in IE and Moz, which sucks.
	if(window.event)
	{
	    Console.onkeydown = Kernel.keyEvent; //IE.
	}
    else
    {
        Console.onkeypress = Kernel.keyEvent; // Moz
    }
	
    // TEMP:  Warn Opera Users.
    if(window.opera)
    {
        alert("Opera + JavaScript isn't working well in RetroWeb.\n" +
              "I'm working on the issues, but in the meantime\n" +
              "please use a different browser here.  Sorry.\n");
    }
	
	// Define this runtime's random logo
	Kernel.LOGO = LogoLib.get();
	
	// Default prompt
	Kernel.promptString = Kernel.DEFAULT_PROMPT;
	
	// Rock and roll.
	Kernel.online = true;
	
	// If initial command passed in as arg, show rebooting message.
    if(initialCommand) Kernel.writeConsole("\nReconnecting to http://markwoodman.com ...\n\n");
	
	// Show introduction info.
	Kernel.writeConsole(Kernel.LOGO);
	Kernel.writeConsole(Kernel.VERSION + "\n");
	Kernel.writeConsole(Kernel.TAGLINE + "\n");
	Kernel.writeConsole(Kernel.COPYRIGHT + "\n\n");
	Kernel.writeConsole(Kernel.HELP_MSG);
	
	// Prompt user for command.
	Kernel.prompt();
	
	// Check for command passed in as argument, then in URL
	if(!initialCommand) initialCommand = new String(document.location).split("?")[1];
	if(initialCommand) Kernel.processCommand(initialCommand);
	
}

/**
 * Nicer than body onload.
 */
window.onload = Kernel.boot;

/**
 * Change the style without a reload.
 * Based on code in http://ppleyard.org.uk/styleswitcher.js
 */
Kernel.changeStyle = function(title)
{
    for(i=0; (a = document.getElementsByTagName("link")[i]); i++) 
    {
        if(a.getAttribute("rel").indexOf("style") != -1 && a.getAttribute("title")) 
        {
          a.disabled = true;
          if(a.getAttribute("title") == title) a.disabled = false;
        }
    }  
}

/**
 * Prompt the user for input.
 */
Kernel.prompt = function()
{
    Kernel.writeConsole(Kernel.promptString);   
    Kernel.trimBuffer();
    Kernel.promptPosition = Console.value.length;
    Kernel.moveCaret();
}

/**
 * Makes columns out of array values.
 * @param array    The array values to columnize.
 * @param cols     The number of columns to make.
 * @param prePad   String padding to use before columns.
 */
Kernel.makeColumns = function(array, cols, prePad)
{
    // Determine the widest column
    var width=5;
    for(i=0;i<array.length;i++)
    {
        if(array[i].length>width) width=array[i].length;
    }
    width+=1;
    
    // Create columns
    var output = "";
    var colNum = 0;
    for(i=0;i<array.length;i++)
    {
        if(colNum==0) output+=prePad;
        output+=array[i];
        if(colNum<cols-1)
        {
            var midPad = "";
            while(array[i].length + midPad.length < width) midPad+=" ";
            output+=midPad;
            colNum++;
        }
        else
        {
            output+="\n";
            colNum = 0;   
        }
    }
    
    return output;    
}

/**
 * Open a new browser window.
 */
Kernel.openWindow = function(theUrl, sameWin)
{
    if(sameWin)
    {
        // Use current window
        document.location = theUrl;
    }
    else
    {
        // Open new window
        var win = window.open(theUrl,Kernel.POPUP_NAME,'');
    }
}

/**
 * Move the caret to the prompt.
 */
Kernel.moveCaret = function()
{
    if(Kernel.online)
    {
        // Move the caret
        var length = Console.value.length;
        if( Console.setSelectionRange ) 
        {
            // Moz
            Console.setSelectionRange(length,length);
            Console.focus();
        } 
        else if( Console.createTextRange ) 
        {
            // IE
            var range = Console.createTextRange();
            range.collapse(true);
            range.moveStart('character',length-1);
            range.moveEnd('character',length-1);
            range.select();
         }
         
         // Move the scroll (Only needed in Mozilla)
         Console.scrollTop=Console.scrollHeight-Console.clientHeight;
    }
}

/**
 * Remove lines to keep with MAX_ROWS.
 */
Kernel.trimBuffer = function()
{
    var lines = Console.value.split("\n");
    while(lines.length>Kernel.MAX_ROWS)
    {
        lines.shift();   
    }
    Console.value = lines.join("\n");
}

/**
 * Handle a keystroke event.
 */
Kernel.keyEvent = function(event)
{
    // Identify the keypress event
    if (!event) event = window.event;  // IE
    
    // Identify the key pressed
    var key = event.keyCode; // IE
    if (!key) key = event.which;  // Moz

    // Certain keystrokes need to be intercepted.
    var continueEvent = true;
    if(key==13)
    {
        // User pressed Enter, so we'll process the command.
        Kernel.processCommand();
        continueEvent = false;
    }
    else if(key==8)
    {
        // User pressed backspace. Only allowed if it won't go behind the prompt.
        continueEvent = (Console.value.length>Kernel.promptPosition);
    }
    else if(key>=37 && key<=40)
    {
        // User pressed an arrow key.
        
        // Up = Previous command
        if(key==38) Kernel.writeConsole(Kernel.getPreviousCommand(), true);
        
        // Down = Next command
        if(key==40) Kernel.writeConsole(Kernel.getNextCommand(), true);
        
        Kernel.moveCaret();
        continueEvent = false;
    }
    
    // Do we override normal event propagation?
    if(continueEvent==false)
    {
        if (event.stopPropagation) event.stopPropagation();
        if (event.preventDefault) event.preventDefault();
        if (event.cancelBubble) event.cancelBubble = true;
        if (event.returnValue) event.returnValue = false;
        return false;
    }
    else
    {
        // Typing only allowed at the end.
        Kernel.moveCaret();
        
        // Allow keystroke to be entered in textarea.
        return true;
    }
}

/**
 * Write to the console.
 * @param replace  if true, will replace everything after prompt
 */
Kernel.writeConsole = function(msg, replace)
{
    if(replace)
    {
        Console.value = Console.value.substring(0,Kernel.promptPosition);
        Console.value += msg;
    }
    else
    {    
        Console.value += msg; 
    }
    if(Kernel.online) Console.focus();
}

/**
 * Get the user's command, which is everything
 * after Kernel.promptPosition.  This is a vast
 * improvement over the old method which won't
 * be mentioned ever again, do you hear me?
 */
Kernel.getCommand = function()
{
    return Console.value.substring(Kernel.promptPosition).toLowerCase();
}

/**
 * Add a user's line to the command history.
 */
Kernel.addToHistory = function(line)
{
    if(line.length>0)
    {
        Kernel.commandHistory.push(line);
        Kernel.commandHistoryPos = Kernel.commandHistory.length;
    }
}

Kernel.getPreviousCommand = function()
{
    if(Kernel.commandHistory.length==0) return "";
    
    if(Kernel.commandHistoryPos>0)
    {
        Kernel.commandHistoryPos--;
    }
    return Kernel.commandHistory[Kernel.commandHistoryPos];
}

Kernel.getNextCommand = function()
{
    if(Kernel.commandHistoryPos==Kernel.commandHistory.length) return "";
    if(Kernel.commandHistoryPos<(Kernel.commandHistory.length-1))
    {
        Kernel.commandHistoryPos++;
    }
    return Kernel.commandHistory[Kernel.commandHistoryPos];
}

/**
 * Process the user's command line using
 * the magic of javascript associative arrays.
 */
Kernel.processCommand = function(line)
{
    if(Kernel.online)
    {
        // If passed as argument, append to console
        if(line) 
        {
            Kernel.writeConsole(line, true);
        }
        else
        {
            // Or just get line from console
            line = Kernel.getCommand();
            
            // Add to command history;
            Kernel.addToHistory(line);        
        }
        
        // Now add line feed for display purposes.
        Kernel.writeConsole("\n");
        
        // Check for command
        if(line.length>0)
        {
            // Split into arguments
            var args = line.split(" ");
        
            // Execute command
            Kernel.execute(args); 
        }
        
        // New prompt
        Kernel.prompt();
    }
    else
    {
        Kernel.boot(null, line);
    }
}

/**
 * Execute a command and its arguments
 */
Kernel.execute = function(args)
{
    // Lookup command
    var command = Commands[args[0]];
    
    // Shhh!
    if(!command) command = HiddenCommands[args[0]];
    
    // Execute the match, if any
    if(command)
    {
        // Pass in the arguments without the command name
        args.shift();
        result = command(args);
        
        // If something comes out the other end, show it.
        if(result) Kernel.writeConsole(result);
    }
    // Error out
    else
    {
        Kernel.writeConsole(Kernel.getUnknownSynonym() + " command: " + args[0] + "\n");
        Kernel.writeConsole(Kernel.HELP_MSG);
    }
}

/** Because just saying "unknown" is soooo boring. */
Kernel.unknownSynonyms = new Array("Bad", "Blighted", "Botched",
                                   "Crappy", 
                                   "Dullard",
                                   "Evil",
                                   "Frivolous",
                                   "Inane",
                                   "Ludicrous",
                                   "Preposterous",
                                   "Unknown", "Unfathomable",
                                   "Please never again type this");
/**
 * Creative commands get creative rejection.
 */
Kernel.getUnknownSynonym = function()
{
    var index = Math.round(Math.random()*(Kernel.unknownSynonyms.length-1));
    return Kernel.unknownSynonyms[index];
}

/**
 * Object holding available commands. No need to
 * do the prototype/instance business with this
 * because we only need one of them.
 */
var Commands = new Object();

/**
 * What I've managed to get done lately.
 */
Commands.news = function()
{
    var msg = "The latest advances in RetroWeb technology...\n";
    msg += "02/09/2006 Various tweaks, added bio and rss commands\n";
    msg += "09/06/2005 Fixed bug in command history.  Opera users warned of bugs.\n";
    msg += "           QOTD command added with ~200 quotes, just because.\n";
    msg += "09/04/2005 Prompt-spoofing bug fixed, tidy up html/css.\n";
    msg += "           Vastly improved key event handling.\n";
    msg += "           Added command history with up/down arrows.\n";
    msg += "           Fixed scrolling problem in Moz, sort of.\n";
    msg += "           Response to unknown commands spiced up a bit.\n";
    msg += "09/02/2005 Palm skin added, Plain (No style) skin added.\n";
    msg += "09/01/2005 Commands can have arguments. Help beefed up. News added.\n";
    msg += "           Commands can be passed in url. Ex: markwoodman.com/?news.\n";
    msg += "           Off-site URLs now opened in new window.  Random logo.\n";
    msg += "08/29/2005 DOS and Lappy skins added.\n";
    msg += "08/26/2005 RetroWeb is born.\n";
    return msg;
}

/**
 * Load the blog.  TODO:  Prompt for new window/same window.
 */
Commands.inkblots = function(args)
{
    var theUrl = "http://inkblots.markwoodman.com";
    Kernel.openWindow(theUrl);
    return "Loading " + theUrl + "...\n";
}

/**
 * Load the game LAN Panic!
 */
Commands.panic = function(args)
{
    var theUrl = "http://lanpanic.markwoodman.com";
    Kernel.openWindow(theUrl);
    return "Have fun playing LAN Panic! ...\n";
}

/**
 * Load the resume.
 */
Commands.resume = function()
{
    var theUrl = "http://markwoodman.com/woodman.pdf";
    Kernel.openWindow(theUrl);
    return "Loading " + theUrl + "...\n";   
}

/**
 * Display contact information.
 */
Commands.contact = function()
{
    var msg = "Contact Information:\n";
    msg+= "  Mark Woodman\n";
    msg+= "  Colorado Springs, CO USA\n";
    msg+= "  mark@markwoodman.com\n";
    return msg; 
}

/**
 * Open email program with proper address.
 */
Commands.email = function(args)
{
    var theUrl = "mailto:" + Kernel.EMAIL_ADDR + "?subject=";
    if(args[0]) 
    {
        theUrl += args.join(" ");
    }
    else
    {
        theUrl += Kernel.VERSION;
    }
    Kernel.openWindow(theUrl);
    return "Emailing " + Kernel.EMAIL_ADDR + " ...\n";
}

/**
 * Clear the screen.
 */
Commands.clear = function()
{
    Console.value = "";
    Console.focus();
    return;
}

/**
 * Show the about message.
 */
Commands.about = function()
{
    var msg = Kernel.LOGO;
    msg    += Kernel.VERSION + "\n";
    msg    += Kernel.COPYRIGHT + "\n";
    msg    += "  \"RetroWeb.  You don't need no stinkin' GUI.\"           \n";
    msg    += "   Graphical websites made by programmers are usually painful. \n";
    msg    += "   You get to be spared from the usual rollovers, buttons, and \n";
    msg    += "   all that incessant clicking.  Settle back and enjoy old school\n";
    msg    += "   functionality at its finest:  RetroWeb.   Now in monochrome!\n\n";
    msg    += "   Note: This is all client-side... No server scripts whatsoever.\n";
    Kernel.writeConsole(msg);
}

/**
 * Show the available commands.
 */
Commands.help = function(args)
{
    // Find man page 
    var manPage = ManPages[args[0]];
    if(manPage)
    {
        return manPage + "\n";
    }
    else
    {
        // This is way too expensive to do every time.  Shame on me.
        // Alphebetize the command names
        var commandNames = new Array();
        var i = 0;
        for (prop in Commands)
        {
            commandNames[i++] = prop;
        }
        commandNames.sort();
        
        // Show the command names in columnds
        var output = "Available commands:\n";
        output += Kernel.makeColumns(commandNames, 3, "  ");
        output += "\nFor help on a specific command, try 'help <command_name>'.\n";
        return output;
    }
}

/**
 * Quote of the Day
 */
Commands.qotd = function()
{
    return Qotd.random();
}

/**
 * Bio on XML.com
 */
Commands.bio = function()
{
    var theUrl = "http://www.xml.com/pub/au/274";
    Kernel.openWindow(theUrl);
    return "Opening bio on XML.com...\n";
}

/**
 * inkBlots RSS
 */
Commands.rss = function()
{
    var theUrl = "http://feeds.feedburner.com/woodman/inkblots";
    Kernel.openWindow(theUrl);
    return "Opening inkBlots RSS feed...\n";
}

/**
 * I suppose we might as well document some of this junk, eh?
 */
var ManPages = new Object();

ManPages.about = "Usage:  'about'.  Tells you about RetroWeb.";
ManPages.clear = "Usage:  'clear'.  Clears the screen.";
ManPages.contact = "Usage:  'contact'.  Contact information for MW.";
ManPages.email = "Usage:  'email <subject>'.  Addresses email with optional subject to MW.";
ManPages.help = "That's getting a bit redundant, eh?";
ManPages.inkblots = "Usage:  'inkblots'.  Opens window to MW's tech blog on RSS and Atom.";
ManPages.news = "Usage:  'news'.  Lists new features and changes to RetroWeb.";
ManPages.resume = "Usage:  'resume'.  Opens window to resume.";
ManPages.qotd = "Usage:  'qotd'.  Displays random Quote of the Day.";
ManPages.bio = "Usage:  'bio'.  Displays author bio on XML.com";
ManPages.rss = "Usage:  'rss'.  Opens the inkBlots RSS feed in new window.";
ManPages.command_name = "Very funny.";

/**
 * Yeah, you found it.  So much for the magic of computers.
 * No need to do the prototype/instance business with this
 * because we only need one of them.
 */
var HiddenCommands = new Object();


/**
 * Because?
 */
HiddenCommands.hidden = function()
{
    
}

/**
 * Who are you, indeed?
 */
HiddenCommands.whoami = function()
{
    var msg = "Somebody running " + navigator.appCodeName + " " + navigator.appVersion ;
    msg += " on " + navigator.platform + ".\n";
    return msg;
}

/**
 * Because?
 */
HiddenCommands.why = function()
{
    return "I was bored.  Next thing ya know:  RetroWeb!\n";
}

/**
 * Revenge of Zork.
 */
HiddenCommands.north = function()
{
    var msg = "You walk north and enter a strange forest.\n";
        msg+= "It is dark here.  You are likely to be eaten\n";
        msg+= "by a Grue.  You really should leave this place.\n";
        msg+= Kernel.promptString + "sleep\n";
        msg+= "Sleep?  If you insist.  Your pleasant nap in the\n";
        msg+= "strange forest is interrupted by terrible screaming.\n";
        msg+= "Unfortunately, the screaming is yours.  You have\n";
        msg+= "been eaten by a Grue.  (Score: -4)\n";
    return msg;
}

/**
 * The Oregon Trail fate awaits you.
 */
HiddenCommands.south = function()
{
    var msg = "You walk south, and get lost in a desert.  After several\n";
    msg    += "days of blinding thirst you come upon a small, muddy creek.\n";
    msg    += "Desperate, you decide to drink it.   Within hours you know this\n";
    msg    += "was the worst, and last, mistake of your life.\n";
    msg    += "You have died from dysentery.   (Score: -2)\n";
    return msg;
}

/**
 * Side of fava beans not included.
 */
HiddenCommands.west = function()
{
    var msg = "You travel west and get stranded in the mountains.\n";
        msg+= "You have died and are eaten by the Donner Party.  (Score: -3)\n";
    return msg;
}

/**
 * Reality sets in.
 */
HiddenCommands.east = function()
{
    var msg = "You can't go that way.\n";
    return msg;
}

/**
 * Ground zero.
 */
HiddenCommands.hello = function()
{
    var msg = "Hello world!\n(That was easy.)\n";
    return msg;
}

/**
 * Everybody tries this one.
 */
HiddenCommands.hi = function()
{
    var msg = "Sorry, no chat client functionality yet.\n";
    return msg;
}

/**
 * War games tribute.
 */
HiddenCommands.play = function(args)
{
    var msg;
    if(args[0])
    {
        var game = args.join(" ");
        if(game.toLowerCase()=='chess')
        {
            Kernel.openWindow("http://chess.delorie.com/c.cgi?fromform=yes&computer=black&time=1&pieces=lfc");
        }
        if(game.toLowerCase()=='tic tac toe')
        {
            Kernel.openWindow("http://www.billsgames.com/tic-tac-web/ttw.cgi"); 
        }
        if(game.toLowerCase()=='global thermonuclear war')
        {
            Kernel.openWindow("http://www.imdb.com/title/tt0086567/quotes");
        }
        return "I don't know the game '" + game + "'.\n";
    }
    else
    {
        return "Greetings Professor Falken.\nUsage: play [tic tac toe / chess / global thermonuclear war]\n";
    }
}

/**
 * One that works.
 */
HiddenCommands.time = function()
{
    var msg = new Date() +"\n";
    return msg;
}

/**
 * One that doesn't.
 */
HiddenCommands.date = function()
{
    var msg = "Sorry, I'm married.\n";
    return msg;
}

/**
 * For the unix folks out there.
 */
HiddenCommands.ls = function()
{
    return " .\n ..\n inkblots\n hidden\n resume\n";
}

/**
 * For the redmond folks out there.
 */
HiddenCommands.dir = function()
{
    var msg = "";
    msg += "Volume in drive C has no label.    \n";
    msg += "Volume Serial Number is A4CA-BE36  \n";
    msg += "\n";
    msg += "Directory of C:\\markwoodman.com\\   \n";
    msg += "\n";
    msg += "08/26/2005  14:23    <DIR>      .\n";
    msg += "08/26/2005  14:23    <DIR>      ..\n";
    msg += "09/06/2005  09:29    <DIR>      inkblots\n";
    msg += "09/06/2005  09:29    <DIR>      hidden\n";
    msg += "07/02/2005  09:29    <DIR>      resume\n";
    return msg;
}

/**
 * Esoteric.
 */
HiddenCommands.wmd = function()
{
    var msg = "WMD not found.  Try Syria? (y/n)\n";
    return msg;
}

/**
 * P.S., I love you.
 */
HiddenCommands.ps = function(args)
{
    var msg="";
    msg+="UID    ID     PPID  STIME    TTY    COMD    \n";           
    msg+="guest  792    779   2:52:24  pts/2  ps " + args.join(" ") + "\n";
    msg+="root   24621  560   Jul 02   ttyp2  kick 792\n";
    return msg;
}

/**
 * Da boot.
 */
HiddenCommands.kick = function(args)
{
    var msg;
    if(args[0])
    {
        msg = args[0] + " cries bitter tears as they are disconnected.";
    }
    else
    {
        msg = "Usage: kick [session_id]";
    }
    return msg;
}

/**
 * As if I had time to write man pages.
 */
HiddenCommands.man = function(args)
{
    var msg;
    if(args[0])
    {
        var manPage = ManPages[args[0]];
        if(manPage)
        {
            msg = manPage + "\n";
        }
        else
        {
            msg = args[0] + " should be avoided at all costs.\n";
        }
        
    }
    else
    {
        msg = "Woman is much nicer.\n";
    }
    return msg;
}

/**
 * Changing Directories?  Nah.
 */
HiddenCommands.cd = function(args)
{
    if(args[0])
    {
        if(args[0]==".") return "That was productive.\n";
        if(args[0]=="..") return "Permission denied.\n";
        Kernel.execute(args);
        return;
    }
    else
    {
        var msg = "Yes, but cd to WHERE?  Since you don't really know...\n";
        msg += "Permission denied.\n";
        return msg;
    }
}

/**
 * The copymeister.
 */
HiddenCommands.cp = function()
{
    var msg = "Permission denied. There can be only one.\n";
    return msg;
}

/**
 * Movin' on up.
 */
HiddenCommands.mv = function()
{
    var msg = "Permission denied.  You want to move, try UHaul.\n";
    return msg;
}

/**
 * Where's StrongBad when you need him?
 */
HiddenCommands.rm = function()
{
    var msg = "Baleeted.\n";
    return msg;
}

/**
 * Did you honestly think this would work?
 */
HiddenCommands.chmod = function()
{
    var msg = "You now own markwoodman.com.  Please send a check for 10 years of late registrar and hosting fees.\n";
    return msg;
}

/**
 * Because clear wasn't enough.
 */
HiddenCommands.cls = function()
{
    Commands.clear();
}

/**
 * Honesty is our best policy.
 */
HiddenCommands.pwd = function()
{
    var msg = "/you/bin/waste/ng/time";
    return msg;
}

/**
 * That's just spiteful.  Shame on you.
 */
HiddenCommands.kill = function()
{
    Kernel.writeConsole("Now you've done it.\nConnection to host lost.\n");
    Console.disabled = true;
    Kernel.online = false;
    Kernel.promptString = "";
}

/**
 * Redmond would be proud.
 */
HiddenCommands.dos = function()
{
   Kernel.changeStyle("dos");
   Kernel.promptString = "C:\\> ";
   return;  
}

/**
 * So you like Unix better?
 */
HiddenCommands.xterm = function()
{
   Kernel.changeStyle("xterm");
   Kernel.promptString = "$ ";
   return;
}

/**
 * Will the Brothers Chaps sue?
 */
HiddenCommands.lappy = function()
{
   Kernel.changeStyle("lappy");
   Kernel.promptString = "]";
   return;  
}

/**
 * This might assuage them.
 */
HiddenCommands.sbemail = function()
{
    var theUrl = "http://homestarrunner.com/sbemail.html";
    Kernel.openWindow(theUrl);
    return "strongbad_email.exe\n";
}

/**
 * Handy.
 */
HiddenCommands.palm = function()
{
   Kernel.changeStyle("palm");
   Kernel.promptString = "~";
   return;  
}

/**
 * WTIIWYS:  What there is is what you see.
 */
HiddenCommands.plain = function()
{
   Kernel.changeStyle("plain");
   return "The magic is gone.\n";  
}

/**
 * Nifty.
 */
HiddenCommands.monkey = function()
{
    Kernel.promptString = ":(|) ";
    return;
}

/**
 * v++, in Roman!
 */
HiddenCommands.vi = function()
{
    var msg = "~\n";
        msg+= "~\n";
        msg+= "~\n";
        msg+= "~\n";
        msg+= "~\n";
        msg+= "\"index.html\", 5 lines, 0 characters\n\n";
        msg+= "Seriously, emacs is so much better.\n";
    return msg;
}

/**
 * Seriously.
 */
HiddenCommands.emacs = function()
{
    return "I prefer iMacs.\n";
}

/**
 * Bye.
 */
HiddenCommands.exit = function()
{
    HiddenCommands.kill();
}


/**
 * Show all the hidden commands.  Cheater.
 */
HiddenCommands.hidden = function()
{
    // This is way too expensive to do every time.  Shame on me.
    // Alphebetize the command names
    var commandNames = new Array();
    var i = 0;
    for (prop in HiddenCommands)
    {
        commandNames[i++] = prop;
    }
    commandNames.sort();
    
    // Show the command names
    var output = "These aren't the commands you're looking for.  Move along.\n";
    output += Kernel.makeColumns(commandNames, 6, "  ");
    output += "\n";
    return output;
}

/**
 * Logo repository.  Renderings courtesy of 
 * http://www.network-science.de/ascii/
 */
 
var LogoLib = new Array();

/**
 * Returns an indexed logo.
 * @param index   If omitted, a random logo is returned.
 */
LogoLib.get = function(index)
{
    if(!index) index = Math.round(Math.random()*(LogoLib.length-1));
    return LogoLib[index];   
}

// All backslashes need to be escaped.
LogoLib[0] = " _                         \n";
LogoLib[0] +="|_) _ _|_ ._ _ \\    / _ |_ \n";
LogoLib[0] +="| \\(/_ |_ | (_) \\/\\/ (/_|_)\n";

LogoLib[1] = " __   ___  _|_   __   __           ___  |__ \n";
LogoLib[1] +="|  ' (__/_  |_, |  ' (__) (__(__( (__/_ |__)\n";

LogoLib[2] = "____ ____ ___ ____ ____ _  _ ____ ___ \n";
LogoLib[2] +="|--< |===  |  |--< [__] |/\\| |=== |==] \n";

LogoLib[3] = "  __                          \n";
LogoLib[3] +=" /__)  _ _/  _    (   /  _  / \n";
LogoLib[3] +="/ (   (- /  /  () |/|/  (- () \n";

LogoLib[4] ="01010010 01100101 01110100 01110010 01101111 01010111 01100101 01100010\n";

LogoLib[5] = "  _   _   _   _   _   _   _   _          \n";
LogoLib[5] +=" / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ \n";
LogoLib[5] +="( R | e | t | r | o | W | e | b )        \n";
LogoLib[5] +=" \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \n";

LogoLib[6] = "____ ____ ___ ____ ____ _ _ _ ____ ___  \n";
LogoLib[6] +="|__/ |___  |  |__/ |  | | | | |___ |__] \n";
LogoLib[6] +="|  \\ |___  |  |  \\ |__| |_|_| |___ |__] \n";
                                        
LogoLib[7] = "+-+-+-+-+-+-+-+-+\n";
LogoLib[7] +="|R|e|t|r|o|W|e|b|\n";
LogoLib[7] +="+-+-+-+-+-+-+-+-+\n";

LogoLib[8] = " _ \\     |        \\ \\      /    |      \n";
LogoLib[8] +="   / -_)  _|  _| _ \\ \\ \\  / -_)  _ \\  \n";
LogoLib[8] +="_|_\\___|\\__|_| \\___/\\_/\\_/\\___|_.__/\n"; 
