/*
 * PHP Formatter javascript
 *
 * Copyright, Gerben <www.gerbenvv.nl>
 */

/*
 *
 * GLOBALS
 *
 */

var xmlrequest = false;

var newlines     = 0;
var visiblelines = 18;
var lineheight   = 20;
var errorline    = 0;

var ie = (navigator.appName.indexOf('Microsoft') != -1);
var ff = (navigator.userAgent.indexOf('Firefox') != -1);

var begin;

var active_tab = 'input';

var files      = new Object();
var fileamount = 0;

var formatting = false;

var plainoutput = '';

/*
 *
 * GLOBAL FUNCTIONS
 *
 */

//inits formatter
function Init() {
    //Do we have HTTP Request?
    if (window.XMLHttpRequest) {
        xmlrequest = new XMLHttpRequest();
    }

    //IE has an ActiveX Object
    else {
        try {
            xmlrequest = new ActiveXObject('Msxml2.XMLHTTP');
        } catch (e) {
            try {
                xmlrequest = new ActiveXObject('Microsoft.XMLHTTP');
            } catch (e) {
                return false;
            }
        }
    }

    //get nodes
    var nodes = [
                  'loginform', //NOTE: IE gives an error!
                  'formatform',
                  'statusbar',
                  'input', 'outerinput', 'inputcode', 'innerlines', 'outerlines',
                  'upload', 'selectedfiles', 'selectedfilesheader', 'noselectedfiles',
                  'style',
                  'output', 'outputlines', 'outputcode'
                ];
    for (id in nodes) {
        try {
            this[nodes[id]] = document.getElementById(nodes[id]);
        } catch (e) { }
    }

    //get upload mc
    uploadmc = document.getElementById(ie ? 'uploadmcie' : 'uploadmc');
    
    //disable wrapping
    inputcode.wrap = "off";

    //setup lines
    if (ff || ie) {
        inputcode.onscroll  = OnScroll;
        inputcode.onkeydown = OnKeyUp;
        inputcode.onkeyup   = OnKeyUp;
        
        outerlines.style.display = "";
        outerinput.style.marginLeft = '40px';
        if (ie) {
            inputcode.style.marginLeft = "-40px";
        }

        OnKeyUp();
    }

    //give textarea focus
    inputcode.focus();

    //set image hovers
    if (document.images) {
        var buttons = [
                        'home', 'features', 'stylem', 'contact', 'about',
                        'inputtab', 'uploadtab', 'styletab', 'outputtab',
                        'format', 'formatfiles', 'downloadfiles', 'download'
                      ];
        for (id in buttons) {
            var loadimg = new Image();
            loadimg.src = 'images/' + buttons[id] + '_hvr.png';

            var img = document.getElementById(buttons[id]);
            if (img && (img.src != loadimg.src)) {
                img.onmouseover = function () { this.src = 'global/images/' + this.id + '_hvr.png'; };
                img.onmouseout  = function () { this.src = 'global/images/' + this.id + '.png';     };
            }
        }
    }
    
    ActivateButton('inputtab');
}

function GetMicroTime() {
    //create date class
    var datec = new Date();

    return datec.getTime();
}

function ActivateButton(which) {
    var img = document.getElementById(which);

    img.src = 'global/images/' + which + '_hvr.png';

    img.onmouseover = null;
    img.onmouseout  = null;
}

function DeactivateButton(which) {
    var img = document.getElementById(which);

    img.src = 'global/images/' + which + '.png';

    img.onmouseover = function () { this.src = 'global/images/' + this.id + '_hvr.png'; };
    img.onmouseout  = function () { this.src = 'global/images/' + this.id + '.png';     };
}

function SubmitForm(form, vars, async, handler) {
    for (i = form.elements.length - 1; i >= 0; i--) {
        var element = form.elements[i];

        if (!element.name) {
            continue;
        }

        if (element.type == 'checkbox' && !element.checked) {
            continue;
        }

        vars += vars.length ? '&' : '';
        vars += element.name + '=' + encodeURIComponent(element.value);
    }

    if (form.method.toUpperCase() == 'POST') {
        xmlrequest.open('POST', form.action, async);
        xmlrequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    } else {
        xmlrequest.open('GET', form.action, async);
    }

    xmlrequest.onreadystatechange = handler;
    xmlrequest.send(vars);

    // login: user, pass, login
    // fieldset
    // flash object
}

function GotoTab(tab) {
    document.getElementById(active_tab).style.display = 'none';
    document.getElementById(       tab).style.display = 'block';

    document.getElementById(active_tab + 'buttons').style.display = 'none';
    document.getElementById(       tab + 'buttons').style.display = '';

    DeactivateButton(active_tab + 'tab');
    ActivateButton(tab + 'tab');
    active_tab = tab;

    if (active_tab == 'input') {
        OnScroll();
    }

    SetStatusMessage('');
}

function SetStatusMessage(msg) {
    statusbar.innerHTML = msg;
}

function WriteFlashObject(code) {
    document.write(code);
}

function FormatSize(size) {
    //check for MiB
    if (size > (1024 * 1024)) {
        return Math.round(size / (1024 * 1024) * 10) / 10 + ' MiB';
    }

    //and KiB
    if (size > 1024) {
        return Math.round(size / 1024 * 10) / 10 + ' KiB';
    }

    //or bytes
    return size + ' B';
}

function FormatTime(time) {
    //check for Mb
    if (time > (1000 * 60)) {
        var sec;
        return Math.floor(time / (1000 * 60)) + ' min'
        + ((sec = Math.round(time / 1000) % 60) ? ', ' + sec + ' sec' : '');
    }

    //and Kb
    if (time > 1000) {
        return Math.round(time / 1000 * 10) / 10 + ' s';
    }

    //or bytes
    return time + ' ms';
}

/*
 *
 * FORMAT MULTIPLE FILES FUNCTIONS
 *
 */

function FormatFiles() {
    try {
        begin = GetMicroTime();

        SetStatusMessage(
          '<img src="global/images/loading.gif" alt="Loading..." id="loading" /> ' +
          'Formatting...'
        );

        for (name in files) {
            files[name].formatted = false;
        }

        SubmitForm(formatform, 'setstyle=1&reset=1&time=' + begin, false, null); //uploads input!

        formatting = true;

        FormatFile();
    } catch(e) {
        SetStatusMessage('Formatting failed. ' + e);
    }
}

function FormatFile() {
    for (name in files) {
        if (files[name].formatted) {
            continue;
        }

        selectedfiles.rows[ files[name].row ].cells[3].innerHTML = 'formatting...';
        
        setTimeout(function() {
            uploadmc.UploadFile(name, path + '/Upload/?' + sid, 'file');
        }, 20);

        return;
    }

    //we are done now
    var time = GetMicroTime() - begin;

    SetStatusMessage('Formatting took: ' + FormatTime(time));

    formatting = false;
}

function AddSelectedFile(name, size) {
    var rows = selectedfiles.rows.length;
    var row = selectedfiles.insertRow(rows);
    row.insertCell(0);
    row.insertCell(1).appendChild(document.createTextNode(name));
    row.insertCell(2).appendChild(document.createTextNode(FormatSize(size)));
    row.insertCell(3).innerHTML = '<a href="#" onclick="RemoveSelectedFile(\''
                                + name
                                + '\'); return false;" title="Delete file">delete</a';
    row.insertCell(4);

    noselectedfiles.style.display = 'none';
    selectedfilesheader.style.display = '';
    fileamount++;

    files[name].row = rows;
}

function RemoveSelectedFile(name) {
    selectedfiles.deleteRow(files[name].row);

    delete files[name];

    fileamount--;
    if (!fileamount) {
        noselectedfiles.style.display = '';
        selectedfilesheader.style.display = 'none';
    }
}

function TryAgain(name) {
    files[name].formatted = false;
    if (!formatting) {
        FormatFiles();
    }
}

function OnFileSelected(name, type, size) {
    if (files[name]) {
        RemoveSelectedFile(name);
    }

    files[name] = {'size': size, 'formatted': false};

    AddSelectedFile(name, size);
}

function OnFileUploaded(name) {
    files[name].formatted = true;

    selectedfiles.rows[ files[name].row ].cells[3].innerHTML = //childNodes
        '<a href="' + path + '/Download/?file=' + name + '" title="Download file">download</a>';

    //dont do work in a flash event
    setTimeout(FormatFile, 20);
}

function OnFileUploadError(name) {
    files[name].formatted = true;

    selectedfiles.rows[ files[name].row ].cells[3].innerHTML =
        'failed, <a href="#" onclick="TryAgain(\'' + name +
        '\'); return false;" title="Try again">try again</a>';

    //dont do work in a flash event
    setTimeout(FormatFile, 20);
}

function OnFileUploadHttpError(name, error) {
    files[name].formatted = true;

    alert(error + "\n" + path + '/Upload/?' + sid);

    selectedfiles.rows[ files[name].row ].cells[3].innerHTML = 'parse error';

    //dont do work in a flash event
    setTimeout(FormatFile, 20);
}

/*
 *
 * FORMAT INPUT FUNCTIONS
 *
 */

//formats PHP input code
function FormatInput() {
    try {
        SetStatusMessage(
          '<img src="global/images/loading.gif" alt="Loading..." id="loading" /> ' +
          'Formatting...'
        );

        begin = GetMicroTime();

        SubmitForm(formatform, 'time=' + begin, true, OnInputFormatted);
    } catch(e) {
        SetStatusMessage('Formatting failed. ' + e);
    }
}

//handles XML request ready event
function OnInputFormatted() {
    //check state
    if (xmlrequest.readyState == 4) {
        if (xmlrequest.status == 200) {
            var result = null;

            try {
                eval("result=" + xmlrequest.responseText);
            } catch (e) {
                throw 'Response was no JSON!';
            }

            if (result.error) {
                line = result.line;
                text = result.text;

                GotoTab('input');
                GotoErrorLine(line);

                SetStatusMessage('<a id="errors" href="#" onclick="GotoErrorLine('
                                 + line
                                 + '); return false;">Error on line '
                                 + line
                                 + ': '
                                 + text
                                 + '!</a>');
            } else {
                plainoutput = result.plainoutput;

                var outputstr = result.output;
                var lines     = result.lines;

                outputstr = outputstr.replace(/\<\</g, '</span><span style="color: #DD0000;">');
                outputstr = outputstr.replace(/\<\>/g, '</span><span style="color: #007700;">');
                outputstr = outputstr.replace(/\<\&/g, '</span><span style="color: #0000BB;">');
                outputstr = outputstr.replace(/\<\"/g, '</span><span style="color: #FF8000;">');

                outputcode.innerHTML = outputstr;

                lines = parseInt(lines);

                outputlines.innerHTML = '';
                for (i = 1; i < lines + 1; i++) {
                    var element = document.createElement('div');
                    element.id = 'line_' + i;

                    if (ie) {
                        element.innerText = i;
                    } else {
                        element.textContent = i;
                    }

                    outputlines.appendChild(element);
                }

                GotoTab('output');
                CleanError();

                var time = GetMicroTime() - begin;

                SetStatusMessage('Formatting took: ' + FormatTime(time));
            }
        } else {
            throw 'Status code was ' + xmlrequest.status;
        }
    }
}

function GetClipboardContent() {
    return plainoutput;
}

/*
 *
 * INPUT AREA FUNCTIONS
 *
 */

function OnKeyUp() {
    if (!ff && !ie) return;

    var _newlines = inputcode.value.split("\n").length;
    if (_newlines > newlines) {
        for (i = newlines + 1; i < _newlines + 1; i++) {
            var element = document.createElement("div");
            element.id = 'line_' + i;

            if (ie) {
                element.innerText = i;
            } else {
                element.textContent = i;
            }

            innerlines.appendChild(element);
        }

        newlines = _newlines;
    } else if (_newlines < newlines) {
        for (i = _newlines; i < newlines; i++) {
            innerlines.removeChild(innerlines.lastChild);
        }

        newlines = _newlines;
    }

    //IE does not throw a scroll event
    OnScroll();
}

function OnScroll() {
    innerlines.style.top    = '-' + inputcode.scrollTop + 'px';
    outerlines.style.height = inputcode.clientHeight + 'px';
}

function GotoErrorLine(linenum) {
    if (!ie && !ff) {
        SelectLine(inputcode, linenum);
        inputcode.scrollTop = Math.round((linenum - 0.5 - visiblelines / 2) * lineheight);
        return;
    }
    
    inputcode.scrollTop = Math.round((linenum - 0.5 - visiblelines / 2) * lineheight);

    OnScroll();

    if (errorline) {
        document.getElementById('line_' + errorline).className = '';
    }

    var line = document.getElementById('line_' + linenum);
    line.className = 'errorline';

    errorline = linenum;
}

function SelectLine(textarea, linenum) {
    var text = textarea.value;
    linenum = Number(linenum);

    var linePattern = /.*(\r\n|\r|\n)/g;
    linePattern.lastIndex = 0;

    var lineStart = 0;
    var lineEnd = 0;
    var lineMatch;
    var lineFound = 0;

    var found = false;
    while ((lineMatch = linePattern.exec(text))) {
        lineFound++;
        lineStart = lineMatch.index;
        lineEnd = lineStart + lineMatch[0].length;
        if (lineFound == linenum) {
            found = true;
            break;
        }
    }

    if (found) {
        if (textarea.setSelectionRange) {
            textarea.scrollTop = Math.floor(textarea.scrollHeight / textarea.value.split("\n").length * (linenum - 1));
            textarea.setSelectionRange(lineStart, lineEnd);
            textarea.focus();
        }
    }
}

function CleanError() {
    if (errorline) {
        document.getElementById('line_' + errorline).className = '';
        errorline = 0;
    }
}
