// Global variables for managing the execution context
var context = 0;
var program;
var input;
var output;
var canvas;
var progTimerID;
var lineToBreakAt = -1;

function init(source_code, outputarea) {
    output = new textareaOutput(outputarea);
    input = new promptInput();
    try {
        program = new basicProgram(source_code, output);

        context = new basicContext(program, input, output, output, document, canvas);
        context.reset();
        context.charbuf = '';
        output.cls();
    }
    catch (e) {
        output.print(e + "\n");
    }
}

function update_line(n) {
    var indicator = document.getElementById("LineNumberIndicator");
    if (progTimerID || !context) {
        indicator.value = '';
    }
    else {
        var lineNo = context.currentLineNumber();
        highlightLine(lineNo, document.getElementById("programtext"));
        indicator.value = lineNo;
    }
}

function setLineToBreakAt(field, code, input, outputarea) {
    var CaretPos = 0;
    if (document.selection) {
        // IE
        var range, rangeCopy;
        field.focus();
        range = document.selection.createRange();
        if (range !== null) {
            rangeCopy = range.duplicate();
            rangeCopy.moveToElementText(field);
            rangeCopy.setEndPoint('EndToStart', range);
            CaretPos = rangeCopy.text.length - range.text.length;
        } else {
            lineToBreakAt = -1;
            return;
        }
    }
    else if (field.selectionStart || field.selectionStart == '0') {
        // Chrome, FF, etc.
        CaretPos = field.selectionStart;
    }
    while (field.value.charAt(CaretPos) == "\n" && CaretPos > 0) CaretPos--;
    while (field.value.charAt(CaretPos) != "\n" && CaretPos > 0) CaretPos--;
    var remainder = field.value.substr(CaretPos, 100);
    var linePattern = /\d+/
    lineToBreakAt = linePattern.exec(remainder);

    if (context == 0)
    {
        run(code, input, outputarea);
    }
    else {
        continue_execution();
    }
}

function unHighlight(field) {
    // Highlight the line number
    if (field.createTextRange) { // IE
        var selRange = field.createTextRange();
        selRange.moveToPoint(0, 0);
        //selRange.moveStart("character", 4);
        //selRange.moveEnd("character", 7);
        selRange.select();
    }
    else if (field.setSelectionRange) { // Chrome, FF, etc.
        field.setSelectionRange(0, 0);
    }
}

function highlightLine(line, field) {
    // Find the line
    var pattern = new RegExp("^\\s*" + line.toString(), "m");
    var start = field.value.search(pattern);
    var end = start + line.toString().length;
    if (start < 0) return;

    // Position the line at the middle of the pane
    var textRemainder = field.value.slice(start);
    var text = field.value;
    field.focus();
    field.value = field.value.slice(0, start);
    field.scrollTop = 1000000;
    var scrollTopValue = field.scrollTop;
    field.value = text;
    if (context.lineOrder(line) > 10 && context.lineOrder(line) <= 30) {
        scrollTopValue += (context.lineOrder(line) - 10) * 10;
    }
    else if (context.lineOrder(line) > 30) {
        scrollTopValue += 200;
    }
    field.scrollTop = scrollTopValue;

    // Highlight the line number
    if (field.createTextRange) { // IE
        // count lines up to the current line
        var text_lines = text.split(/\s*\n+/);
        var m = 0;
        for (var n = 0; n < text_lines.length; n++) {
            if (text_lines[n].match(pattern)) break;
            m++;
        }
        var newend = end - start;
        start -= m - 1;
        if (start == 1) start = 0;
        var selRange = field.createTextRange();
        selRange.collapse(true);
        selRange.moveStart("character", start);
        selRange.moveEnd("character", newend);
        selRange.select();
    }
    else if (field.setSelectionRange) { // Chrome, FF, etc.
        field.setSelectionRange(start, end);
    }
}

function update_trace() {
    if (progTimerID || !context) {
        document.getElementById("traceOutput").value = '';
    }
    else {
        if (context) {
            var trace_expr = document.getElementById("traceInput").value;
            if (trace_expr != '') {
                document.getElementById("traceOutput").value =
                    context.evaluateBASIC(trace_expr);
            }
        }
    }
}

function clear_trace() {
    document.getElementById("traceOutput").value = '';
    document.getElementById("LineNumberIndicator").value = '';
    unHighlight(document.getElementById("programtext"));
}

function cycle() {
    if (context) {
        var r; // delay returned by leap()
        context.setLevel(level);
        if (lineToBreakAt > 0) {
            if ((r = context.step())) {
                if (lineToBreakAt != context.currentLineNumber()) {
                    progTimerID = setTimeout(cycle, r);
                }
                else {
                    stop_execution()
                }
            }
        }
        else if ((r = context.leap(20))) { // leap 20 BASIC lines
            progTimerID = setTimeout(cycle, r);
        }
        else {
            progTimerID = 0;
            context = 0;
        }
    }
}

function run(code, input, outputarea) {
    _gaq.push(['_trackEvent', 'ProgramExecution', 'Run', document.forms[0].title.value]);
    if (context != 0) {
        continue_execution()
    }
    else {
        init(code, outputarea);
        context.setLevel(level);
        clearTimeout(progTimerID);
        progTimerID = -1; // non-null to indicate we are about to cycle
        update_line();
        clear_trace();
        cycle();
    }
}

function reset_context(code, input, outputarea) {
    lineToBreakAt = -1;
    context = 0;
    clearTimeout(progTimerID);
    progTimerID = 0;
    init(code, outputarea);
    context.setLevel(level);
    canvas.cls();
    update_line();
    update_trace();
}

function continue_execution() {
    context.setLevel(level);
    clear_trace();
    if (progTimerID == 0) cycle();
}

function step_line(code, input, outputarea) {
    clearTimeout(progTimerID);
    progTimerID = 0;
    if (!context) {
        reset_context(code, input, outputarea);
    }
    else {
        context.setLevel(level);
        if (!context.step()) {
            context = 0;
            //alert('step failed');
        }
    }
    update_line();
    update_trace();
}

function stop_execution() {
    lineToBreakAt = -1;
    clearTimeout(progTimerID);
    progTimerID = 0;
    update_trace();
    update_line();
    context.setLevel(level);
}

// Global variables for managing the canvas

var canvas10x10 = 0;
var canvas3x3 = 0;
var canvas8x8 = 0;
var canvas25x25 = 0;
var canvas50x50 = 0;
var canvas100x100 = 0;
var canvas75x75 = 0;
var canvas50x10 = 0;
var canvas10x50 = 0;
var canvas_string;

function setUpCanvas(canvas_type) {
    var canvasDiv = document.getElementById("canvas");
    canvasDiv.align = 'left';
    canvasDiv.background = '#ffffff';
    canvas_string = canvas_type;
    document.forms[0].canvas.value = canvas_type;

    if (canvas) canvas.element.style.visibility = 'hidden';

    switch (canvas_type) {
        case '10x10':
            if (canvas10x10) canvas = canvas10x10;
            else canvas = canvas10x10 = new tableCanvas(10, 10, { 'grid': 2, 'height': 28, 'width': 28 });
            break;
        case '3x3':
            if (canvas3x3) canvas = canvas3x3;
            else canvas = canvas3x3 = new tableCanvas(3, 3, { 'grid': 5, 'height': 95, 'width': 95 });
            break;
        case '8x8':
            if (canvas8x8) canvas = canvas8x8;
            else canvas = canvas8x8 = new tableCanvas(8, 8, { 'grid': 2, 'height': 36, 'width': 36 });
            break;
        case '25x25':
            if (canvas25x25) canvas = canvas25x25;
            else canvas = canvas25x25 = new tableCanvas(25, 25, { 'grid': 1, 'height': 11, 'width': 11 });
            break;
        case '50x50':
            if (canvas50x50) canvas = canvas50x50;
            else canvas = canvas50x50 = new tableCanvas(50, 50, { 'grid': 1, 'height': 5, 'width': 5 });
            break;
        case '75x75':
            if (canvas75x75) canvas = canvas75x75;
            else canvas = canvas75x75 = new tableCanvas(75, 75, { 'grid': 0, 'height': 4, 'width': 4 });
            break;
        case '100x100':
            if (canvas100x100) canvas = canvas100x100;
            else canvas = canvas100x100 = new tableCanvas(100, 100, { 'grid': 0, 'height': 3, 'width': 3 });
            break;
        default:
            alert('Bad canvas type:' + canvas_type);
            return;
    }

    canvas.attachTo(canvasDiv);
    canvas.element.style.position = 'absolute';
    canvas.element.style.visibility = 'visible';
    canvas.element.style.zIndex = 1;
}

function open_aux(url, name) {
    window.open(url, name, 'width=600,height=600,scrollbars=yes,toolbar=yes,menubar=yes').focus();
    return false;
}

function FbStatus() {
    this.loggedIn = true;

    this.saveSlots = 3;
    this.projects = new Array('project1', 'hello world', '---unused---');
    this.achieved = new Array(1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0);
    this.user = 'nikkostrom';
}

function FbLogin(status) {
    if (!status.loggedIn) {
        return '<div class="fblogin">-FBLOGIN-</div>';
    }
}

function XMLHttp() {
    return (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
}

function PostProject() {
    var xmlHttp = XMLHttp();
    if (xmlHttp) {
        var projData = document.getElemenyById('ProjectForm').serialize();
        xmlHttp.open('POST', '/submit/', true);
        xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xmlHttp.setRequestHeader("Content-length", projData.length);
        xmlHttp.setRequestHeader("Connection", "close");
        xmlHttp.onreadystatechange = function () {
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                alert(xmlHttp.responseText);
            }
            xmlHttp.send(projData);
        };
    }
}

function Publish() {
    var content = '';
    var status = new FbStatus();

    if (status.loggedIn) {
        content += '<p>You currently have ' + status.saveSlots + ' slots available for publishing projects.</p>';
        if (status.saveSlots < 10) {
            content += '<p>When you earn enough trophies and increase your rank you\'ll be awarded more slots.</p>'
            content += '<p>Beware, the old save will be overwritten and disapear if you publish this project in an occupied slot.</p>';
        }
        for (var i = 0; i < status.saveSlots; i++) {
            content += '<p class="saveurl">' + (i + 1) + '. http://quitebasic.com/user/' + status.user + '/' + (i + 1) + '</p>';
            content += '<p class="savebutton"><button>Save here!</button></p> ' + status.projects[i] + '</div>';
        }
    }
    else {
        content += '<p>To save projects you must be logged in using facebook</p>';
        content += '<p>No worries, it is free and we respect your <a href="">privacy</a>.</p>';
        content += FbLogin(status);
    }
    OpenDialog('Publish Project', content);
}

function SetProjectProperties() {
    document.forms[0].title.value = document.forms[0].newTitle.value;
    document.forms[0].description.value = document.forms[0].newDescription.value;

    for (var i = 0; i < document.forms[0].newCanvas.length; i++) {
        if (document.forms[0].newCanvas[i].checked) {
            setUpCanvas(document.forms[0].newCanvas[i].value);
        }
    }
    CloseDialog();
    document.forms[0].action = '/user/';
    document.forms[0].target = '';
    document.forms[0].submit();
}

function NewProject() {
    document.forms[0].title.value = 'Project Title (edit me!)';
    document.forms[0].description.value = 'Project Description (edit me!)';
    document.forms[0].program.value = '';
    ProjectProperties();
}

function ProjectProperties() {
    var content = '';
    var t = document.forms[0].title.value;
    var d = document.forms[0].description.value;
    content += '<h2>Title</h2><p><input value="' + t + '" type="text" size="40" name="newTitle"/></p>';
    content += '<h2>Description</h2><p><textarea style="background:white;" cols="40" rows="5" name="newDescription">' + d + '</textarea></p>';

    content += '<h2>Canvas</h2><p>';
    content += '<table cellpadding="5" style="color: #FFFFFF;">';
    content += '<tr>';
    var resolutions = new Array('25x25', '50x50', '75x75', '100x100', '3x3', '8x8', '10x10');
    for (var i = 0; i < resolutions.length; i++) {
        var selected = (document.forms[0].canvas.value == resolutions[i]) ? 'checked="checked"' : '';
        var res = resolutions[i];
        content += '<td><input type="radio" name="newCanvas" value="' + res + '" ' + selected + '/>' + res + '</td>';
        if (i == 3) {
            content += '</tr><tr>';
        }
    }
    content += '</tr>';
    content += '</table></p>';
    content += '<input type="button" onclick="SetProjectProperties()" value="OK" style="font-size:20px; margin-left:250px; margin-top:25px;"/>';

    OpenDialog('Project Properties', content);
}

function Trophies() {
    var content = '';
    var status = new FbStatus();

    var trophies = new Array(
    'Hello World!', 0, 'Wrote a hello world program', 25,
    'Mr. Nice Guy', 1, 'Liked someone else\'s project', 15,
    'Explorer', 2, 'Tried sample projects from all categories', 25,
    'Spagetti Chef', 6, 'Used lots of nested GOTOs in a program', 30,
    'Social', 0, 'A friend signed in', 50,
    'Control Freak', 6, 'Used four different flow control commands', 50,
    'Bug Swatter', 5, 'Tried the debug console', 15,
    'Hooked', 3, 'Logged in five days in a row', 100,
    'Gamer', 4, 'Tried all game samples', 20,
    'Plotter', 7, 'Used a canvas command in a program', 15,
    'Designer', 7, 'Used three different canvas commands', 25,
    'Popular', 1, 'Another signed in user liked your project', 30,
    'Rising Star', 1, 'At least 5 users liked your project', 100,
    'Rock Star', 1, 'At least 25 users liked your project', 250,
    'Respect', 8, 'A whale liked your project', 100,
    'Social Hub', 0, 'Five friends signed in', 150,
    'Whale', 8, 'Ranked over 500 points', 0
    );

    var rank = 0;
    for (var i = 0; i < trophies.length / 4; i++) {
        if (status.achieved[i]) {
            rank += trophies[i * 4 + 3];
        }
    }
    content += '<h2 id="rank">' + status.user + ' &mdash; rank: ' + rank + '</h2>';

    for (var i = 0; i < trophies.length / 4; i++) {
        var c = status.achieved[i] ? 'achieved' : 'unachieved';
        var yoff = status.achieved[i] ? 0 : -32;
        content += '<div class="trophy"><img src="/dummy.png" style="width:32px; height:32px; background:url(/trophies.png) -' + (trophies[i * 4 + 1] * 32) + 'px ' + yoff + ';"/></br><h2 class="' + c + '">' + trophies[i * 4] + '</h2><p>' + trophies[i * 4 + 2] + ' (' + trophies[i * 4 + 3] + ')<p></div>';
    }

    if (!status.loggedIn) {
        content += '<p>To see your trophies you must be logged in using facebook</p>';
        content += '<p>No worries, it is free and we respect your <a href="">privacy</a>.</p>';
        content += FbLogin(status);
    }

    OpenDialog('Trophies', content);
}

function CloseLoggedInDialog() {
    document.getElementById('modalScreen').style.visibility = 'hidden';
    document.getElementById('loggedInDialogBox').style.visibility = 'hidden';
    document.getElementById('loggedInDialogTitle').innerHTML = '';
    document.getElementById('loggedInDialogContent').innerHTML = '';
}

function OpenLoggedInDialog(title, content) {
    document.getElementById('loggedInDialogTitle').innerHTML = title;
    document.getElementById('loggedInDialogContent').innerHTML = content;
    document.getElementById('modalScreen').style.visibility = 'visible';
    document.getElementById('loggedInDialogBox').style.visibility = 'visible';
}

function CloseDialog() {
    document.getElementById('modalScreen').style.visibility = 'hidden';
    document.getElementById('dialogBox').style.visibility = 'hidden';
    document.getElementById('dialogTitle').innerHTML = '';
    document.getElementById('dialogContent').innerHTML = '';
}

function OpenDialog(title, content) {
    document.getElementById('dialogTitle').innerHTML = title;
    document.getElementById('dialogContent').innerHTML = content;
    document.getElementById('modalScreen').style.visibility = 'visible';
    document.getElementById('dialogBox').style.visibility = 'visible';
}

function CloseNotice() {
    document.getElementById('modalScreen').style.visibility = 'hidden';
    document.getElementById('noticeBox').style.visibility = 'hidden';
    document.getElementById('noticeTitle').innerHTML = '';
    document.getElementById('noticeContent').innerHTML = '';
}

function OpenNotice(title, content) {
    document.getElementById('noticeTitle').innerHTML = title;
    document.getElementById('noticeContent').innerHTML = content;
    document.getElementById('modalScreen').style.visibility = 'visible';
    document.getElementById('noticeBox').style.visibility = 'visible';
}

// Initialize Menus
var listMenu = new FSMenu('listMenu', true, 'display', 'block', 'none');
listMenu.animations[listMenu.animations.length] = FSMenu.animFade;

var canvasMenu = new FSMenu('canvasMenu', true, 'display', 'block', 'none');
canvasMenu.animations[canvasMenu.animations.length] = FSMenu.animFade;

var arrow = null;
if (document.createElement && document.documentElement) {
    arrow = document.createElement('span');
    arrow.appendChild(document.createTextNode('>'));
    arrow.className = 'subind';
}

var level;
function setLevel(val) { document.forms[0].elements['level'].value = val; level = val }

var capB;
function BlinkCapB() {
    var tmp = capB.style.color;
    capB.style.color = capB.style.backgroundColor;
    capB.style.backgroundColor = tmp;
}

// Get fb username
//FB.api('/me', function (response) {
//  var user = /[^\/]+$/g.exec(response.link);
//  if (!user) user = 'fbid' + response.id;
//});

function SignOutCallback(response) {
    if (response.session && response.status == 'connected') {
        FB.logout(function (response) { CloseNotice(); });
    }
    CloseNotice();
}

function SignOut(response) {
    document.getElementById('noticeContent').innerHTML = 'Signing out...';
    FB.getLoginStatus(SignOutCallback);
}

function SignOutConfirmation() {
    OpenNotice('Sign Out',
             '<p>Sign out from Facebook?<p><input type="button" onclick="SignOut()" value="Yes"/>&nbsp;<input type="button" onclick="CloseNotice()" value="Cancel"/>')
}

function TrackLikes(response) {
    _gaq.push(['_trackEvent', 'Social', 'Like', response.id + ':' + document.forms[0].title.value]);
}

function ManageFBSession(response) {
    if (response.session) {
        document.getElementById("FBLogin").style.display = 'none';
        document.getElementById("loggedInDialogContent").style.display = 'block';
    } else {
        document.getElementById("FBLogin").style.display = 'block';
        document.getElementById("loggedInDialogContent").style.display = 'none';
    }
}

function initFB() {
    window.fbAsyncInit = function () {
        FB.init({ appId: '147146985181', status: true, cookie: true, xfbml: true });
        FB.getLoginStatus(ManageFBSession);
        FB.Event.subscribe('auth.sessionChange', ManageFBSession);
        FB.Event.subscribe('edge.create', TrackLikes);
    };
    (function () {
        var e = document.createElement('script'); e.async = true;
        e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
        document.getElementById('fb-root').appendChild(e);
    } ());
}

// Initializer
window.onload = function () {
    // Activate the FS menus
    listMenu.activateMenu("listMenuRoot", arrow);
    canvasMenu.activateMenu("canvasMenuRoot", arrow);

    // Initialize level and canvas
    var radioArray = document.getElementsByName("projectLevel");
    for (i = 0; i < radioArray.length; i++) {
        if (radioArray[i].checked) setLevel(radioArray[i].value);
    }
    setUpCanvas(document.forms[0].elements['canvas'].value);

    // Setup blinking 'B'
    capB = document.getElementById("capB");
    capB.style.color = 'green';
    capB.style.backgroundColor = 'black';
    setInterval(BlinkCapB, 1500);

    initFB();
};
 
