﻿/* ==============================================
    Модуль для работы с функциями компилятора
        (компиляция,
         выполнение,
         ввод-вывод,
         завершение программы)
   ============================================== */


// *************************************************************** Глобальные константы *************************************************************

var interv;
var in_enter = false;

// Надо ли обрабатывать содержимое вывода, как графическую команду
var outputAsCanvasGraphCmd = false;



// Позиция — строка и столбец
function Position(line, column) {
    this.line = line;
    this.column = column;
}

// Выхватывает из строки ошибки компиляции номер
// строки, в которой произошла ошибка
function GetPositionOfCompilerError(errorStr) {
    var firstLineInd = errorStr.indexOf("(") + 1;
    var delimInd = errorStr.indexOf(",");
    var lastColumnInd = errorStr.indexOf(")");
    
    var line = errorStr.slice(firstLineInd, delimInd);
    var column = errorStr.slice(delimInd + 1, lastColumnInd);
    var result = new Position(line, column);
    return result;
}

// Выхватывает из строки ошибки выполнения номер
// строки, в которой произошла ошибка
function GetLineOfExecutionError(errorStr) {
    var firstInd = errorStr.indexOf("строка ") + 7;
    var lastInd = errorStr.indexOf("\n");
    
    var result = errorStr.slice(firstInd, lastInd-1);
    return result;
}

// Выхватывает имя файла, в котором произошла ошибка
function GetErrorFileName(errorStr){
    var firstInd = errorStr.lastIndexOf("\\") + 1;
    var lastInd = errorStr.lastIndexOf(":");
    
    var result = errorStr.slice(firstInd, lastInd);
    return result;
}

// Выхватывает имя файла, в котором произошла ошибка компиляции
function GetFileNameOfCompilerError(errorStr){
    var endNameInd = errorStr.indexOf("(");
    return errorStr.substr(0, endNameInd);
}

// ************************************************************ Управление вводом-выводом ***********************************************************

function GetProcessOutput() {
    //alert(PageMethods.prototype.GetMessageOfTheDay);
    if (compId != null)
        PageMethods.GetProcessOutput(compId,GetProcessOutput_CallBack);   
}

function SendReadString(s) {
    //StopReadOutput();
    if (compId != null)
        PageMethods.SendReadString(compId,s, SendReadString_CallBack);
}

function SendReadString_CallBack(responce) {
    //GetProcessOutput();
    //StartReadOutput();
}

// Ввод данных в поле ввода
function enter_data() {
    el3 = $get("EnterEdit");
    var data = el3.value
    
    WriteTextToOutputBox(data + "\n", "output");
    $get("StatusImage").src = "images/isRunning.gif";
    
    SendReadString(data);
    
    HideEnterString();
    return false;
}

function HideEnterString() {
    enterBlockOn = false;   // блок ввода спрятан
    ResizeErrorsAndEditsTextBoxHeight();
    
    statusEl = $get("StatusLabel");
    statusEl.innerHTML = isRunning;
    //el1.style.visibility = "hidden";
    el2 = $get("EnterLabel");
    el2.style.display = "none";
    el4 = $get("EnterEdit");
    el4.style.display = "none";
    el3 = $get("EnterButton");
    el3.style.display = "none";
    el4.value = "";
    el5 = $get("StopButton");
    el5.style.display = "none";
}

function check_for_enter(evt) {
    evt = evt || window.event
    if (evt.keyCode == 13) {
        enter_data();
        return false;
    }
    
    in_enter = true;
    return true;
}

function CutOneGraphCommandFrom(text) {
    var grCh = '@'; // символ ограничивающий графкоманду
    var R = [];
    R[0] = text;
    R[1] = '';
    var txt = '';
    var grtxt = '';
    var t1 = '';
    var t2 = text;
    var p1;
    if (t2.indexOf(grCh) != -1) {
        p1 = t2.indexOf(grCh);
        // разделяем строку по p1
        t1 = text.substring(0, p1);
        t2 = text.substring(p1 + 1);
        p2 = t2.indexOf(grCh);
        grtxt = grtxt + t2.substring(0, p2);
        t2 = t2.substring(p2 + 1);
        txt = txt + t1 + t2;
        R[0] = txt; R[1] = grtxt;
    }
    return R;
}

// извлекает графкоманды из text 
// Result[0] оставшийся текст
// Result[1] графкоманды
function extractGraphCommands(text) {
    var result = [];
    var r;
    r = CutOneGraphCommandFrom(text);
    var grcmds = r[1]; // графкоманды
    var txt = r[0];    // остальной текст
    while (r[1] != '') {
        r = CutOneGraphCommandFrom(txt);
        grcmds = grcmds + r[1];
        txt = r[0];
    }
    result[0] = txt; result[1] = grcmds;
    return result;
}


var grWin;
var grCmdBuff = '';
function processText(txt){
   // извлекаем графкоманды из txt
    var resExtract=extractGraphCommands(txt);
    var text=resExtract[0];
    
    var grCommands=resExtract[1];
    // если графокно не создано, то открыть его
    if (grCommands !='' && !grWin) {grWin= open("grClientCode.htm");}
    
    // пишем графкоманду
    //if (grCommands !='') {addCmd(grCommands); alert('to grWin->'+grCommands+' read:'+readCmd());}
    if (grCommands != '') {
        // добавляем графкоманду во временный буфер
        grCmdBuff = grCmdBuff + grCommands;
    }
 // возвращаем оставшийся текст   
 return text;   
}

function sendCmdFromBuffer() {
    //alert('sendCmd');
    // переписываем часть буфера в cookie, если оно свободно
    var cookieTxt = readCmd();
    var cookieLen = cookieTxt.length;

    // если cookie свободна  
    if (cookieLen == 0) {
        // берем из буфера порцию
        var p1 = 2000;
        //if (p1>grCmdBuff.length-1) p1=grCmdBuff.length-1;
        var s3 = grCmdBuff.substring(p1);
        var p3 = s3.indexOf('/');
        var pos = p1 + p3;
        if (p3 == -1) pos = grCmdBuff.length;
        var s1 = grCmdBuff.substring(0, pos); // прорция
        var s2 = grCmdBuff.substring(pos);
        //if (grCmdBuff != '')  alert('s1='+s1+' \n\n s2='+s2);
        addCmd(s1);
        grCmdBuff = s2;
    }
}

// Вывод данных text содержания content (ошибки компиляции или данные для вывода)
function WriteTextToOutputBox(text, content) {
    var resultTab = $find("ResultTabContainer");
        
    if (content == "errors") {
        el = $get("ResultTabContainer_ErrorsTabPanel_ErrorsTextBox");
        resultTab.set_activeTabIndex(1);
    }
    else {  // это данные для вывода
        el = $get("ResultTabContainer_OutputTabPanel_ResultTextBox");
        resultTab.set_activeTabIndex(0);
    }            
    
    el.value = el.value + text;
}

function ShowReadString() {
    statusEl = $get("StatusLabel");
    el1 = $get("EnterLabel");
    el3 = $get("EnterButton");
    el2 = $get("EnterEdit");
    el4 = $get("StopButton");

    $get("StatusImage").src = "images/enterWaiting.gif";    // смена статус-картинки на ожидание
    
    enterBlockOn = true;        // блок ввода открыт
    ResizeErrorsAndEditsTextBoxHeight();

    statusEl.innerHTML += enterWaiting;
    el1.style.display = "inline";
    el2.style.display = "inline";
    el3.style.display = "inline";
    el4.style.display = "inline";
    el2.focus();
}

function GetProcessOutput_CallBack(response) {
    //sendCmdFromBuffer();

    if (response == null) {
        StopReadOutput();
        OnStopProgramm();
        //InformAboutWarning(processExpiredError);
        //return;
    }

    isExecutionError = false;
    var obj = response; //eval("(" + response + ")");

    // выхватываем графкоманды   
    //obj.output = processText(obj.output);

    if (obj.output != "" && obj.output != null) {
        if (!ProcessExecutionError(obj.output))
            if (!outputAsCanvasGraphCmd)
                WriteTextToOutputBox(obj.output, "output");
            else        // Обрабатываем данные вывода как графические команды Canvas
                ProcessCanvasGraphCmd(obj.output);          // В файле canvasUse.js
    }
    if (obj.exited == "1") {
        StopReadOutput();
        if (isExecutionError)
            OnStopProgramm("executionError");
        else
            OnStopProgramm();
    }
    if (obj.readrequest == "1") {
        ShowReadString();
    }
}
    
    // Обрабатывает возможную ошибку выполнения
function ProcessExecutionError(output) {
    var errorInd = output.indexOf(executionErrorBegining);
    if (errorInd == -1)                                     // ошибки нет
        return false;

    InformAboutWarning(executionError);
    isExecutionError = true;

    var textBeforError = output.slice(0, errorInd);         // если есть текст, который нужно вывести до ошибки,
    if (textBeforError != "")                               // выводим его
        WriteTextToOutputBox(textBeforError, "output");

    var errorText = output.slice(errorInd);                 // текст всей ошибки

    var newLine = "\n";
    var newLineInd = errorText.indexOf(newLine);
    var errorNameText = output.slice(errorInd, newLineInd); // строка, содержащая название ошибки

    WriteTextToOutputBox(errorNameText, "output");          // выводим название ошибки
    
    var newLineSecondInd = errorText.indexOf(newLine, newLineInd + 1);
    /*  Ищем строку, содержащую имя файла пользователя, в котором
    произошла эта ошибка (для некоторых ошибок первой строкой
    стека идет системный модуль).Поэтому ищем строку, которая
    не содержит "PABCSystem". */
    var strWithLineNumber = errorText.slice(newLineInd + 1, newLineSecondInd + 1);      // строка, содержащая номер
    // строки с ошибкой
    if (strWithLineNumber.indexOf("PABCSystem") != -1) {
        var newLineThirdInd = errorText.indexOf(newLine, newLineSecondInd + 1);
        strWithLineNumber = errorText.slice(newLineSecondInd + 1, newLineThirdInd + 1);
    }
    var errorStr = GetLineOfExecutionError(strWithLineNumber);
    executionErrorLineNumber = errorStr;
    
    if (!restrictedMode){
        var errorFileName = GetErrorFileName(strWithLineNumber);
        if (isUser){        // если мы в режиме пользователя, значит есть подкаталоги
            errorFileName = far.currentDir + ( (far.currentDir!="") ? "/" : "") + errorFileName;
        }
        // чтобы отследить процесс, передаем третий параметр
        OnFileNameLink_Click(errorFileName, userFileNameLinkType, true);
    }
    editAreaLoader.goToPosition("SourceCodeTextBox", errorStr, "0");
    return true;
}

function StartReadOutput() {
    //alert(document.mainForm.onsubmit);
    //document.mainForm.onsubmit = "return enter_data()";
    interv = setInterval(GetProcessOutput, 300);
    //timer = setInterval( sendCmdFromBuffer,300);
}

function StopReadOutput() {
    someProcessIsRunning = false;
    //document.mainForm.onsubmit = function(evt) { return true; }
    clearInterval(interv);
    //if (grCmdBuff=='') clearInterval(timer);
}


// Очищает табы
function ClearTabs() {
    $get("ResultTabContainer_OutputTabPanel_ResultTextBox").value = ""; // очищение полей вывода
    $get("ResultTabContainer_ErrorsTabPanel_ErrorsTextBox").value = ""; // и вывода ошибок
}


// ****************************************************************** Silverlight *******************************************************************
// Определяет, подключается ли соответствующий модуль
/*function SilverlightIsUsed() {
    var sourceCode = editAreaLoader.getValue(EDIT_AREA_SOURCE_ID);      // текст файла
    var a = "4654";
    var silverlightUnitInd = indexOf(SILVERLIGHT_UNIT);
    if (silverlightUnitInd == -1)                                       // в коде даже не используется имя модуля
        return false;
    
}*/

// ******************************************************************* Компиляция *******************************************************************

var compId;
var goToDownloading = false;            // нужно ли после компиляции переходить к скачиванию файла

// Запуск компиляции программы
// <forDownloading> нужно перейти к процессу скачивания файла после компиляции
function compile_programm(forDownloading) {
    if (someProcessIsRunning){
        alert(fullProcessMessage);
        return;
    }
    /*if (ProgramIsRunned)
        return;
    if (ProgramIsCompiled)
        return;*/
    
    if (forDownloading == true)
        goToDownloading = true;
    else
        goToDownloading = false;
    
    ClearTabs();
    
    var sourceFileName;
    if (!restrictedMode){
        var currTitle = editAreaLoader.getCurrFileTitle(EDIT_AREA_SOURCE_ID);
        if (currTitle == "") {
            InformAboutWarning(noOpenedFile);
            return;
        }
        else {
            var currTabID = editAreaLoader.getCurrentFile(EDIT_AREA_SOURCE_ID).id;
            var currentFile = File_GetFileByTabID(currTabID);
            currentWorkFile = currentFile;
            sourceFileName = currentFile.fullName;
        }
    }
    else{
        sourceFileName = "";       // в обрезанном режиме работаем без имени файла
    }
    var sourceCode = editAreaLoader.getValue(EDIT_AREA_SOURCE_ID);
    
    InformAboutCompilation();
    ProgramIsCompiled = true;
    someProcessIsRunning = true;
    fullProcessMessage = inProcess + ofCompiling;
    
    var userDir = (isUser) ? userName : currSessionID;
    if (!userActivityIsFixed) {
        userActivityIsFixed = true;
        setActivityCookie();
        PageMethods.CompileProgrammWithUserFixing(sourceCode, sourceFileName, isUser, userDir, userIP, CompileProgramm_CallBack);
    }
    else
        PageMethods.CompileProgramm(sourceCode, sourceFileName, isUser, userDir, CompileProgramm_CallBack);
}

// Выводит список ошибок компиляции, если таковые имеются,
// или сообщает, что компиляция прошла успешно
function CompileProgramm_CallBack(response) {
    someProcessIsRunning = false;
    
    compId = response.comp_id;
    var errors = response.errors;
    var fileType = response.fileType;
    
    if (errors != null && errors != "") {
        ProcessCompilerError(errors);
        
        OnStopCompileProgramm("incorrect");
    }
    else {
        currentWorkFile.typeIsKnown = true;
        currentWorkFile.type = ((fileType == "ConsoleApplicaton") || (fileType == "WindowsApplicaton")) ? EXE_FILE : 
            (fileType == "ClassLibrary" ? DLL_FILE : PCU_FILE);
        OnStopCompileProgramm("correct");
        if (goToDownloading)
            DownloadCompiledFile();
    }
}

    // Обработка ошибки компиляции
function ProcessCompilerError(errors) {
    if (errors == SERVER_COMPILE_ERROR){
        WriteTextToOutputBox(errors, "errors");
        return;
    }
    var newLinePos = errors.indexOf("\n");
    errors = errors.slice(0, newLinePos - 1);
    var errorPos = GetPositionOfCompilerError(errors);
    if (!restrictedMode){                                   // переход к ошибкам только для полного режима
        var errorFileName = GetFileNameOfCompilerError(errors);
        if (isUser){        // если мы в режиме пользователя, значит есть подкаталоги
            errorFileName = far.currentDir + ( (far.currentDir!="") ? "/" : "") + errorFileName;
        }
        // чтобы отследить процесс, передаем третий параметр
        OnFileNameLink_Click(errorFileName, userFileNameLinkType, true);
    }
    else{
        errors = errors.slice(errors.indexOf(":") + 2);
    }
    editAreaLoader.goToPosition("SourceCodeTextBox", errorPos.line, errorPos.column - 1);
    
    WriteTextToOutputBox(errors, "errors");
}

// Окончание компиляции, статус-сообщение об итогах компиляции
function OnStopCompileProgramm(status) {
    ProgramIsCompiled = false;
    compId = null;

    if (status == "correct") {
        SetStatusLineHidden();
    }
    else {
        InformAboutError(compilationErrors);
    }
}

// ******************************************************************* Выполнение *******************************************************************

// Запуск программы на выполнение
function run_programm() {
    if (someProcessIsRunning){
        alert(fullProcessMessage);
        return;
    }
    /*if (ProgramIsCompiled) {
        //alert("is compiling");
        return;
    }
    if (ProgramIsRunned) return;*/
    
    ClearTabs();
    isExecutionError = false;
    outputAsCanvasGraphCmd = false;             // Изначально, файл не считается графическим
    
    var sourceFileName;
    if (!restrictedMode){
        var currTitle = editAreaLoader.getCurrFileTitle("SourceCodeTextBox");
        if (currTitle == "") {
            InformAboutWarning(noOpenedFile);
            return;
        }
        else {
            var currTabID = editAreaLoader.getCurrentFile(EDIT_AREA_SOURCE_ID).id;
            var currentFile = File_GetFileByTabID(currTabID);
            currentWorkFile = currentFile;
            sourceFileName = currentFile.fullName;
        }
    }
    else{
        sourceFileName = "";
    }
    ProgramIsRunned = true;
    InformAboutExecution();
    $get("EnterEdit").value = "";
    
    var sourceCode = editAreaLoader.getValue("SourceCodeTextBox");
    someProcessIsRunning = true;
    fullProcessMessage = inProcess + ofExecuting;
    var userDir = (isUser) ? userName : currSessionID;
    if (!userActivityIsFixed) {
        userActivityIsFixed = true;
        setActivityCookie();
        PageMethods.RunProgrammWithUserFixing(sourceCode, sourceFileName, isUser, userDir, userIP, RunProgramm_CallBack);
    }
    else {
        PageMethods.RunProgramm(sourceCode, sourceFileName, isUser, userDir, RunProgramm_CallBack);
    }
}

function RunProgramm_CallBack(response) {
    compId = response.comp_id;
    var errors = response.errors;
    var fileType = response.fileType;
    var graphFileType = response.graphType;
    
    if (errors != null && errors != "") {
        ProcessCompilerError(errors);

        OnStopProgramm("incorrect");
        StopReadOutput();
    }
    else {
        // Модуль невозможно выполнить
        if (fileType == pascalCompiledUnit) {
            OnStopProgramm("correct");
            alert("Невозможно запустить откомпилированный модуль");
            StopReadOutput();
        }
        else if (fileType == classLibrary) {
            OnStopProgramm("correct");
            alert("Невозможно запустить динамическую библиотеку");
            StopReadOutput();
        }
        else if (graphFileType == SILVERLIGHT_TYPE){
            // Действия для работы с графики Silverlight
            $get("silverlightControlHost").style.visibility = "visible";
            sendGuidToSL(compId); alert("Ура! Я - клиент!");
            
            var currTitle = editAreaLoader.getCurrFileTitle("SourceCodeTextBox");
            var currTabID = editAreaLoader.getCurrentFile(EDIT_AREA_SOURCE_ID).id;
            var currentFile = File_GetFileByTabID(currTabID);
            currentWorkFile = currentFile;
            sourceFileName = currentFile.fullName;
            someProcessIsRunning = true;
            fullProcessMessage = inProcess + ofExecuting;
            var userDir = (isUser) ? userName : currSessionID;
            PageMethods.ContinueRunGraphProgramm(compId, sourceFileName, isUser, userDir, ContinueRunGraphProgramm_CallBack);
        }
        else if (graphFileType == CANVAS_TYPE){
            // Действия для работы с графикой Canvas
            canvasWindow.setTitle(CANVAS_WINDOW_TITLE);
            canvasWindow.show();                        // Открываем графическое окно
            outputAsCanvasGraphCmd = true;              // Теперь будем обрабатывать данные для вывода, как граф. команды
            ClearCanvas();                              // Очищаем окно (В файле canvasUse.js) 
            //draw();             // Проверка работы
            
            if (!restrictedMode){
                var currTitle = editAreaLoader.getCurrFileTitle("SourceCodeTextBox");
                var currTabID = editAreaLoader.getCurrentFile(EDIT_AREA_SOURCE_ID).id;
                var currentFile = File_GetFileByTabID(currTabID);
                currentWorkFile = currentFile;
                sourceFileName = currentFile.fullName;
            }
            else{
                sourceFileName = "PasFileFromRestrictedMode.pas";
            }
            someProcessIsRunning = true;
            fullProcessMessage = inProcess + ofExecuting;
            var userDir = (isUser) ? userName : currSessionID;
            PageMethods.ContinueRunGraphProgramm(compId, sourceFileName, isUser, userDir, ContinueRunGraphProgramm_CallBack);
        }
        else {
            var sourceCode = editAreaLoader.getValue("SourceCodeTextBox");
            StartReadOutput();
        }
    }
}

// После продолжения выполнения графической программы, использующей Silverlight
function ContinueRunGraphProgramm_CallBack(response){
    compId = response.comp_id;
    var errors = response.errors;
    
    if (errors != null && errors != "") {
        ProcessCompilerError(errors);

        OnStopProgramm("incorrect");
        StopReadOutput();
    }
    else{
        var sourceCode = editAreaLoader.getValue("SourceCodeTextBox");
        StartReadOutput();
    }
}

function OnStopProgramm(status) {
    someProcessIsRunning = false;
    
    ProgramIsRunned = false;
    HideEnterString();
    compId = null;
    
    if (status == "incorrect") {
        InformAboutError(compilationErrors);
    }
    else if (status == "executionError") {
        InformAboutWarning(executionError);
    }
    else  {
        $get("StatusImage").style.visibility = "hidden";
        if (status == "broken") {
            $get("StatusLabel").innerHTML = hasBroken;
        }
        else {
            $get("StatusLabel").innerHTML = hasFinished;
        }
    }          
}


// ******************************************************************* Завершение *******************************************************************

function StopProgramm_CallBack(responce) {
    OnStopProgramm("broken");
}

// Завершение выполнения программы
function stop_programm() {
    someProcessIsRunning = false;
    
    if (!ProgramIsRunned) 
        return;
    ProgramIsRunned = false;
    if (compId != null)
        PageMethods.StopProgramm(compId,StopProgramm_CallBack);
    StopReadOutput();
}

// Флаг "программа компилируется"
var ProgramIsCompiled = false;
// Флаг "программа выполняется"
var ProgramIsRunned = false;


//setTimeout("_SessionExpired()", 1 * 60 * 1000);

function _SessionExpired() {
    //alert("Сессия истекла. Страница будет обновлена.");
    //location.href = location.href; //"http://pascalabc.net/WDE/";
}


// **************************************************************** Загрузка примеров ***************************************************************

/*// Текущий номер примера
var currSampleNum;

function getSampleCallback(responce) {
    var fileName = sampleLabel + responce.FileName;     // имя файла с пометкой "не сохранен"
    var Source = responce.Source;                       // содержимое файла

    var newFile = {id: newID, title: fileName, text: Source};
    
    parFileName = "\"" + fileName + "\"";
    tabsIDHash[parFileName] = newID;      

    NextFileParams();
    
    // запомнили номер примера
    var parFileName = "\"" + fileName + "\"";
    samplesNumsHashByName[parFileName] = currSampleNum;  
    // запомнили имя примера
    var strI = "\"" + currSampleNum.toString() + "\"";
    samplesNamesHashByNum[strI] = fileName;
    
    editAreaLoader.openFile("SourceCodeTextBox", newFile);
    
    $get("StatusLabel").innerHTML = "";
    $get("StatusImage").style.visibility = "hidden";
}

function ex1(i) {
    var strI = "\"" + i.toString() + "\"";
    if (samplesHashByNum[strI]) {
        var parFileName = "\"" + samplesNamesHashByNum[strI] + "\"";
        var specFileID = tabsIDHash[parFileName];
        editAreaLoader.switchToFile("SourceCodeTextBox", specFileID);
        return;
    }
    
    samplesHashByNum[strI] = true;   // запомнили, что пример открыт
    currSampleNum = i;
    
    var statusImg = $get("StatusImage");  
    var statusLabel = $get("StatusLabel");
    
    statusLabel.style.color = "#555555";
    statusLabel.innerHTML = sampleIsLoading;
    statusImg.src = "images/waiting.gif";
    statusImg.style.visibility = "visible";
    PageMethods.getSample(i, getSampleCallback);
}*/