/**
 * CodeRamble.js
 *
 * @Author: Walter Higgins walter.higgins@gmail.com
 *
 * This source file contains _all_ of the javascript logic for communicating with the coderamble server.
 * The same logic is used by both controller and viewer/s.
 *
 */

/*
 * Define the CODERAMBLE namespace. All functions and variables belong to this namespace.
 */
var CODERAMBLE =
{
    sessionIndex: 0,    // index into the list of commands for current session

    broadcasts: 0,      // number of broadcasts made to the server

    sessionHistory: [], // list of commands for current session

    responses: {}       // a hashmap of GET URLs to responses
};

/**
 * Setup automatic synchronization between controller and viewers
 */
CODERAMBLE.autosync = function()
{
    setInterval(CODERAMBLE.synchronize,250);
};

/**
 * Create a XMLHttpRequest Object
 */
CODERAMBLE.request = function()
{
    if (typeof XMLHttpRequest != 'undefined') {
        return new XMLHttpRequest();
    }
    try  {
        return new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
            return new ActiveXObject("Microsoft.XMLHTTP");
        } catch (e) { }
    }
    return false;
};


/**
 * update the server so that all viewers can be synchronized
 */
CODERAMBLE.synchronize = function()
{
    var i = CODERAMBLE.sessionIndex;
    for (; i < CODERAMBLE.sessionHistory.length; i++){
         CODERAMBLE.broadcast(CODERAMBLE.sessionHistory[i]);
    }
    CODERAMBLE.sessionIndex = i;
};

CODERAMBLE.onDone = function(request,callback)
{
     request.onreadystatechange = function()
     {
         if (request.readyState == 4)
         {
             if (request.status == 200){
                 callback(request.responseText);
             }else{
                 alert("Status: " + request.status + " " + request.responseText);
             }

         }
     };
};

/**
 * Send a command to the server. The command will be put on the command queue for all viewers to process.
 */
CODERAMBLE.broadcast = function(command)
{
    var req = CODERAMBLE.request();

    CODERAMBLE.onDone(req,function(response)
    {
        if (CODERAMBLE.broadcasts == 0)
        {
            var t = document.getElementById("send_participants_here");
            var l = window.location.href;
            var p = l.substring(0,l.lastIndexOf('/') + 1);
            p = p + "view.html?" + CODERAMBLE.sessionId;
            t.innerHTML = "Send participants to this link... <a style='text-decoration: none;' href='" + p + "'>" + p + "</a>";
        }
        CODERAMBLE.broadcasts = CODERAMBLE.broadcasts + 1;

    });

    req.open("POST","./cgi/broadcast.pl",true);
    req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    req.send("sessionid=" + CODERAMBLE.sessionId + "&command=" + escape(command));
};

CODERAMBLE.gotoLine = function(lineNumber)
{
    CODERAMBLE.sessionHistory.push("CODERAMBLE.gotoLine(" + lineNumber + ");\n");
    document.location = "#line_" + lineNumber;
};

/**
 * Update the view to reflect current controller .
 */
CODERAMBLE.onResponse = function(url,extension,original,response)
{

    var pane = document.getElementById("source-view");
    pane.innerHTML = "";

    var src = response.replace(/\r/g,"");
    src = src.replace(/</g, "&lt;");

    pane.innerHTML = src;

    // if extension is not recognized by dp.SyntaxHighlighter - use XML as default

    var exts = ['c#','c-sharp','csharp','cpp','c','c++','css',
                'delphi','pascal','js','jscript','javascript','java', 'php','rb','ruby','sql','vb','bas'
                ,'xml','xhtml','xslt','html','htm','xhtml'];

    var i = exts.length;
    var found = false;

    while (i--){
        if (exts[i] == extension){
            found = true;
            break;
        }
    }

    if (found)    {
        pane.className = extension;
    }
    else    {
        pane.className = "xml";
    }

    CODERAMBLE.responses[url] = response;

    document.getElementById("source-filename").innerHTML = original;

    //
    // must clear all existing dp-highlighter divs
    //
    var divs = document.body.getElementsByTagName("div");
    var highlighters = [];

    i = divs.length;
    while (i--){
        if (divs[i].className == "dp-highlighter"){
            highlighters.push(divs[i]);
        }
    }
    i = highlighters.length;
    while (i--){
        document.body.removeChild(highlighters[i]);
    }

    dp.SyntaxHighlighter.ClipboardSwf = "./dpSyntaxHighlighter/Scripts/clipboard.swf";
    dp.SyntaxHighlighter.HighlightAll("source-view");

};

/**
 * Show the source code for the file the user just clicked on in the controller.
 */
CODERAMBLE.showSource = function(url, extension, original)
{
    CODERAMBLE.sessionHistory.push("CODERAMBLE.showSource(\"" +  url + "\",\"" + extension + "\",\"" + original + "\");\n");

    if (CODERAMBLE.responses[url] != null){
        CODERAMBLE.onResponse(url,extension,original,CODERAMBLE.responses[url]);
        return;
    }

    var req = CODERAMBLE.request();
    CODERAMBLE.onDone(req,function(response)
    {
        CODERAMBLE.onResponse(url,extension,original,response);
    });

    req.open("GET",url,true);
    req.send(null);
};

/**
 * Invoked from the View page to listen to a particular code walk-thru session
 */
CODERAMBLE.listen = function(sessionId)
{
    setTimeout(function()
    {
        CODERAMBLE._listen(sessionId);
    },1000);
};

CODERAMBLE._listen = function(sessionId)
{
    var req = CODERAMBLE.request();

    CODERAMBLE.onDone(req,function(response)
    {
        try{

            // don't do anything we've already done.
            var r = response.replace(/\r/g, "");

            var commands = r.split("\n");
            var i = CODERAMBLE.sessionIndex;
            for (; i < commands.length-1; i++){
                eval(commands[i]);
            }
            CODERAMBLE.sessionIndex = i;

            CODERAMBLE.listen(sessionId);

        }catch(e){
            alert("Error: " + e + "\nresponse: " + response);
        }

    });
    req.open("GET","./temp/sessions/" + sessionId  + ".txt",true);
    req.send(null);
};
/**
 * Convert a number to base 36 [0-1, a-z] - (shortens the session ID)
 */
CODERAMBLE.base36 = function(number)
{
    var digits = ['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
    var result = '';
    if (number >= 36){
        result = result + CODERAMBLE.base36(  parseInt(number / 36 ) );
        result = result + digits[ number % 36];
    }else{
        result = digits[number];
    }
    return result;
};
/*
 * Set the sessionId - Need to fix this so it's guaranteed to be unique for any install
 */
CODERAMBLE.sessionId = CODERAMBLE.base36((new Date()).getTime());
