﻿/* ==============================================
    Модуль для работы с графикой Canvas
   ============================================== */


// ********************************************** Обработка текстовой информации для определения команд *********************************************

/*
var CANVAS_OPEN_TAG = "<cc>";               // Открывающий тег команды Canvas
var CANVAS_CLOSE_TAG = "</cc>";             // Закрывающий тег команды Canvas
//  Формат команды
var OPEN_CANVAS_CMD = "var canvas = document.getElementById('canvas');\n" + 
    "if (canvas.getContext) {\n" + 
    "var ctx = canvas.getContext('2d');\n";
var CLOSE_CANVAS_CMD = "}";
*/

var GraphCmdBuffer = "";
var GraphCmdBufferTimer;
var waitNext = true;
var toContinueGraph = true;

// Обрабатывает строку вывода как графическую команду
function ProcessCanvasGraphCmd(cmdStr) {
    GraphCmdBuffer += cmdStr;
    //ProcessCanvasGraphCmdOwn(cmdStr);
}

function ProcessCanvasGraphCmdOwn(cmdStr){
    //alert("|->"+cmdStr.length);
//    var openTagInd = cmdStr.indexOf(CANVAS_OPEN_TAG);                           // Позиция первого открывающего тега
//    if (openTagInd == -1)
    //        return;
    
    // Текст графической команды целиком
//    var resultCmd = cmdStr.split(/<cc>|<\/cc>/).join("");

    var resultCmd = cmdStr.replace(/<cc>|<\/cc>/g, "");
    //alert(resultCmd);

/*    do{
        var cmdStartInd = openTagInd + CANVAS_OPEN_TAG.length;                  // Позиция начала команды
        var closeTagInd = cmdStr.indexOf(CANVAS_CLOSE_TAG, cmdStartInd);        // Позиция начала закрывающего тега
        var nextTextInd = closeTagInd + CANVAS_CLOSE_TAG.length;                // Позиция начала текста после закрывающего тега команды
        var cmd = cmdStr.substring(cmdStartInd, closeTagInd);                   // Текст команды
        resultCmd = resultCmd + cmd;
        openTagInd = cmdStr.indexOf(CANVAS_OPEN_TAG, nextTextInd);              // Позиция следующего открывающего тега
    } while (openTagInd != -1);
*/
    /*  l(1,1,5,5) => ctx_cmd(...);
        разбор строки resultCmd
        находим l(...)
        заменяем l(1,1,5,5) => ctx_cmd(...) */
    var sp = resultCmd.split(";");
    //alert(sp+ " ----->"+ sp.length);
    var res = "";
    var x = "";
    var y = "";
    var x1 = "";
    var y1 = "";
    var r = "";
    var ss = "";
    var fc = "";
    var bc = "";
    for (var i = 0; i < sp.length; i++)
    {
        var s = sp[i];
        var pars = s.split(/[ ,]+/);
        
        switch (pars[0]) {
            case 'l':
                x = pars[1];
                y = pars[2];
                x1 = pars[3];
                y1 = pars[4];
                x = (parseInt(x) + 0.5);
                y = (parseInt(y) + 0.5);
                x1 = (parseInt(x1) + 0.5);
                y1 = (parseInt(y1) + 0.5);
                res += "ctx.beginPath();ctx.moveTo(" + x + "," + y + ");ctx.lineTo(" + x1 + "," + y1 + ");ctx.closePath();ctx.stroke();";
                break;
            case 'i':
                res += 'ctx.fillStyle="white";ctx.strokeStyle="black";ctx.lineWidth=1;';
                break;
            case 'bc':
                res += 'ctx.fillStyle="' + pars[1] + '";';
                break;
            case 'pc':
                res += 'ctx.strokeStyle="' + pars[1] + '";';
                break;
            case 'pw':
                res += 'ctx.lineWidth="' + pars[1] + '";';
                break;
            case 'f':
                res += 'ctx.font="' + s.slice(2) + '";ctx.textBaseline="top";';
                break;
            case 'fr':
                x = pars[1];
                y = pars[2];
                x1 = pars[3];
                y1 = pars[4];
                res += 'ctx.fillRect(' + x + ',' + y + ',' + x1 + ',' + y1 + ');';
                break;
            case 'dr':
                x = pars[1];
                y = pars[2];
                x1 = pars[3];
                y1 = pars[4];
                x = (parseInt(x) + 0.5);
                y = (parseInt(y) + 0.5);
                x1 = (parseInt(x1) - 1);
                y1 = (parseInt(y1) - 1);
                res += 'ctx.strokeRect(' + x + ',' + y + ',' + x1 + ',' + y1 + ');';
                break;
            case 'fc':
                x = pars[1];
                y = pars[2];
                x = (parseInt(x) + 0.5);
                y = (parseInt(y) + 0.5);
                r = pars[3];
                res += 'ctx.beginPath(); ctx.arc(' + x + ',' + y + ',' + r + ',0,2*Math.PI,true); ctx.closePath(); ctx.fill();'
                break;
            case 'dc':
                x = pars[1];
                y = pars[2];
                x = (parseInt(x) + 0.5);
                y = (parseInt(y) + 0.5);
                r = pars[3];
                res += 'ctx.beginPath(); ctx.arc(' + x + ',' + y + ',' + r + ',0,2*Math.PI,true); ctx.closePath(); ctx.stroke();'
                break;
            case 't':
                x = pars[1];
                y = pars[2];
                fc = pars[3];
                bc = pars[4];
                ss = s.slice(s.indexOf('|') + 1);
                res += 'ctx.fillStyle="' + fc + '"; ctx.fillText("' + ss + '",' + x + ',' + y + '); ctx.fillStyle="' + bc + '";';
                break;
            case 'wc':
                res += 'ctx.clearRect(0,0,canvas.width,canvas.height);';
                break;
            case 'ww':
                res += 'canvas.width=' + pars[1] + ';canvasWindow.setSize(' + pars[1] + '+2,canvasWindow.getSize()["height"]);';
                break;
            case 'wh':
                res += 'canvas.height=' + pars[1] + ';canvasWindow.setSize(canvasWindow.getSize()["width"],' + pars[1] + '+2);';
                break;
            case 'ws':
                res += 'canvas.width = ' + pars[1] + '; canvas.height = ' + pars[2] + '; canvasWindow.setSize(' + pars[1] + ' + 2, ' + pars[2] + ' + 2);';
                break;
            case 'lw':
                res += 'canvasWindow.setLocation(' + pars[1] + ', canvasWindow.getLocation()["left"]);';
                break;
            case 'tw':
                res += 'canvasWindow.setLocation(canvasWindow.getLocation()["top"], ' + pars[1] + ');';
                break;
            case 'wp':
                res += 'canvasWindow.setLocation(' + pars[2] + ', ' + pars[1] + ');';
                break;
            case 'wt':
                res += 'canvasWindow.setTitle("' + s.slice(3) + '");';
                break;
            case 'max':
                res += 'canvasWindow.maximize();';
                break;
            case 'min':
                res += 'canvasWindow.minimize();';
                break;
            case 'cl':
                res += 'canvasWindow.closeAll();';
                break;
        }
//            alert(s.length);
    }
//    resultCmd = res; 
    // Сложим и выполним графическую команду
    //resultCmd = OPEN_CANVAS_CMD + resultCmd + CLOSE_CANVAS_CMD; // !!!
    //alert(resultCmd);
    //    eval(resultCmd);
    //alert(res);
    eval(OPEN_CANVAS_CMD + res + CLOSE_CANVAS_CMD);
}

function ProcessCanvasGraphCmdFromBuffer(cmdBuffer){
    waitNext = false;
    if (!toContinueGraph){
        GraphCmdBuffer = "";
        return;
    }
    var openPauseTagInd = cmdBuffer.indexOf(JS_SLEEP_O);
    if (openPauseTagInd == -1){
        waitNext = true;
        ProcessCanvasGraphCmdOwn(cmdBuffer);
    }
    else {
        var sleepIntStartInd = openPauseTagInd + JS_SLEEP_O.length;
        var closePauseTagInd = cmdBuffer.indexOf(JS_SLEEP_C, sleepIntStartInd);
        var sleepIntStr = cmdBuffer.substring(sleepIntStartInd, closePauseTagInd);
        var sleepInt = parseInt(sleepIntStr);
        ProcessCanvasGraphCmdOwn(cmdBuffer.substring(0, openPauseTagInd));
        setTimeout(
            function() { ProcessCanvasGraphCmdFromBuffer(
                cmdBuffer.substring(closePauseTagInd + JS_SLEEP_C.length, cmdBuffer.length)); }, 
            sleepInt);
    }    
}

/*function GraphCmdBufferTimerHandler() {
    if (GraphCmdBuffer.length == 0)
        return;
    if (!waitNext)
        return;
    var newBuffer = GraphCmdBuffer; 
    GraphCmdBuffer = "";          
    ProcessCanvasGraphCmdFromBuffer(newBuffer);
}*/

/*function GraphCmdBufferTimerHandler() {//alert(GraphCmdBuffer.length);
    if (GraphCmdBuffer.length == 0)
        return;
    if (!waitNext)
        return;
    var lastCloseInd = GraphCmdBuffer.lastIndexOf(CANVAS_CLOSE_TAG);
    var newBuffer = GraphCmdBuffer.substring(0, lastCloseInd + CANVAS_CLOSE_TAG.length + 1);
    GraphCmdBuffer = GraphCmdBuffer.slice(lastCloseInd + CANVAS_CLOSE_TAG.length);      //alert(newBuffer.length);    
    ProcessCanvasGraphCmdFromBuffer(newBuffer);
}*/

/*function GraphCmdBufferTimerHandler() {//alert(GraphCmdBuffer.length);
    if (GraphCmdBuffer.length == 0)
        return;
    if (!waitNext)
        return;
    var lastCloseInd = GraphCmdBuffer.lastIndexOf(CANVAS_CLOSE_TAG);
    var newBuffer = GraphCmdBuffer.substring(0, lastCloseInd + CANVAS_CLOSE_TAG.length);
    GraphCmdBuffer = GraphCmdBuffer.slice(lastCloseInd + CANVAS_CLOSE_TAG.length);      
    alert(newBuffer.length);    
    ProcessCanvasGraphCmdFromBuffer(newBuffer);
}*/

function GraphCmdBufferTimerHandler() {//alert(GraphCmdBuffer.length);
    if (GraphCmdBuffer.length == 0)
        return;
    if (!waitNext)
        return;
    var lastCloseInd = GraphCmdBuffer.lastIndexOf(CANVAS_CLOSE_TAG);
    if (lastCloseInd == -1)
        return;
    var newBuffer = GraphCmdBuffer.substring(0, lastCloseInd + CANVAS_CLOSE_TAG.length);
    GraphCmdBuffer = GraphCmdBuffer.slice(lastCloseInd + CANVAS_CLOSE_TAG.length);
    //alert(newBuffer.length);    alert(newBuffer); 
    ProcessCanvasGraphCmdFromBuffer(newBuffer);
}

// *********************************************************** Обработка событий в canvas ***********************************************************

/*  АЛГОРИТМ отправки событий на сервер с накапливанием 
  ------------------------------------------------------- 
    
    I. НАКАПЛИВАНИЕ
    Если открыто текущее_событие
        добавить разделитель блока параметров ( | )
    Иначе
        если блок_событий не открыт
            открыть блок_событий ( Код<evtb> )
        иначе (открыто другое_событие)
            закрыть другое_событие ( </ev> )
        открыть текущее_событие ( <ev><en>EventName</en> )
    добавить параметры события ( x;y;b )
    если буфер событий заполнен
        закрыть текущее_событие ( </ev> )
        закрыть блок_событий ( </evtb> )
        отправить
        
    II. ОТПРАВКА ПО ТАЙМЕРУ
    Если блок_событий пуст
        ничего не делать
    Иначе
        закрыть текущее_событие ( </ev> )
        закрыть блок_событий ( </evtb> )
        отправить   
*/

/*  КОДЫ СОБЫТИЙ

    все события закрыты             0
    OnMouseDown                     1
    OnMouseUp                       2
    OnMouseMove                     3
*/

var CanvasEventCmdsTimer;

var eventsBuffer = "";                      // буфер событий
var currentEventsBufferSize = 0;
var currentEventCode = 0;                   // код текущего события

// Обработчик событий (пока только мыши) по алгоритму накапливания
function CanvasEventHandler(eventCode, eventName, x, y, mousebutton){
    if (eventCode == currentEventCode)              // открыто текущее событие
        eventsBuffer += JS_PAR_BLOCK_DELIM;
    else {
        if (currentEventCode == 0)                  // все события закрыты
            eventsBuffer += SECRETLY + JS_EVT_BLOCK_O;
        else
            eventsBuffer += JS_EVT_C + JS_EVT_DELIM;
        currentEventCode = eventCode;
        eventsBuffer += JS_EVT_O + JS_EVT_NAME_O + eventName + JS_EVT_NAME_C;
    }
    eventsBuffer += x + JS_PAR_DELIM + y + JS_PAR_DELIM + mousebutton;
    currentEventsBufferSize = eventsBuffer.length;
    /*if (eventsBuffer.length > BUFF_MAX_SIZE){
        eventsBuffer += JS_EVT_C + JS_EVT_BLOCK_C;
        currentEventsBufferSize = eventsBuffer.length;
        SendGraphCmd(eventsBuffer);         // В compilerFunctions.js
    }*/
}

// Обработчик таймера отправки событий на сервер
function CanvasEventCmdsTimerHandler(){
    if (currentEventsBufferSize == 0)
        return;
    var newBuffer = eventsBuffer.substring(0, currentEventsBufferSize);   // Чтобы не возникло конфликтов с буфером событий
    newBuffer += JS_EVT_C + JS_EVT_BLOCK_C;
    SendGraphCmd(newBuffer);                                  // В compilerFunctions.js
}

// номер нажатой кнопки мыши по паскалю
var clickedMouseButton = 0;

// Обработка нажатия мыши
function canvasMouseDownHandler(e){
    var x, y, button;                               // необходимые параметры события             
    var browser = navigator.appCodeName;            // понадобится для корректной обработки событий
    //if (browser = "Mozilla"){                     // Firefox, GoogleChrome, Safari точно
    if ((browser == "Opera") || (navigator.appName == "Opera")){                        // Opera    
        x = e.offsetX;
        y = e.offsetY;
    }
    else {                                          // Будем считать, что все остальное по модели мозиллы
        x = e.layerX;
        y = e.layerY;
    }
    /*  В Паскале:  левая_кнопка = 1
                    правая_кнопка = 2   */
    button = 1;
    if (e.button == 2)
        button = 2;
    clickedMouseButton = button;
    CanvasEventHandler(1, "OnMouseDown", x, y, button);
}

// Обработка нажатия мыши
function canvasMouseUpHandler(e){
    var x, y, button;                               // необходимые параметры события   
    button = clickedMouseButton;    
    clickedMouseButton = 0;     
    var browser = navigator.appCodeName;            // понадобится для корректной обработки событий
    //if (browser = "Mozilla"){                     // Firefox, GoogleChrome, Safari точно
    if ((browser == "Opera") || (navigator.appName == "Opera")){                        // Opera    
        x = e.offsetX;
        y = e.offsetY;
    }
    else {                                          // Будем считать, что все остальное по модели мозиллы
        x = e.layerX;
        y = e.layerY;
    }
    /*  В Паскале:  левая_кнопка = 1
                    правая_кнопка = 2   */
    CanvasEventHandler(2, "OnMouseUp", x, y, button);
}

// Обработка движения мыши
function canvasMouseMoveHandler(e){
    var x, y, button;                               // необходимые параметры события             
    var browser = navigator.appCodeName;            // понадобится для корректной обработки событий
    //if (browser = "Mozilla"){                     // Firefox, GoogleChrome, Safari точно
    if ((browser == "Opera") || (navigator.appName == "Opera")){                        // Opera    
        x = e.offsetX;
        y = e.offsetY;
    }
    else {                                          // Будем считать, что все остальное по модели мозиллы
        x = e.layerX;
        y = e.layerY;
    }
    /*  В Паскале:  левая_кнопка = 1
                    правая_кнопка = 2   */
    button = clickedMouseButton;
    CanvasEventHandler(3, "OnMouseMove", x, y, button);
}

// *************************************************************** Работа с окном Canvas ************************************************************

// Проверочный метод рисования в canvas
function draw(){
    if (canvas.getContext) {
        var ctx = canvas.getContext("2d");
        ctx.beginPath();  
        ctx.moveTo(75,50);  
        ctx.lineTo(100,75);  
        //ctx.lineTo(100,25);  
        ctx.closePath(); 
        ctx.stroke();   
        ctx.fillRect (10, 10, 55, 50);
    }
}

// Очищает окно Canvas для работы заново
function ClearCanvas(){
    if (canvas.getContext) {
        var ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, canvas.width, canvas.height); 
    }
}

// Вызывается при изменении размеров окна, содержащего Canvas
function CanvasWindowOnResize(){
    canvas.width = canvasWindow.getSize()["width"] - 2;
    canvas.height = canvasWindow.getSize()["height"] - 2;
}

/* ----------------------------------------
    Было нужно раньше
   ----------------------------------------
// Перемещаемость окна Canvas
var in_drag = false;
function SetCanvasMovable(){
   var div = $get( "divGraphCanvas" );
   div.onmousedown = function( evnt ){
       evnt = evnt || event;
       in_drag = [ this, evnt.offsetX || evnt.layerX, evnt.offsetY || evnt.layerY ];
   }
   document.onmouseup = function(){
       in_drag = false;
   }
   document.onmousemove = function( evnt ){
       if( ! in_drag ){
           return false;
       }
       evnt = evnt || event;
       in_drag[ 0 ].style.left = ( document.body.scrollLeft + ( evnt.x || evnt.clientX ) - in_drag[ 1 ] ) + "px";
       in_drag[ 0 ].style.top  = ( document.body.scrollTop  + ( evnt.y || evnt.clientY ) - in_drag[ 2 ] ) + "px";
   }
}*/
// Второй вариант
/*var xshift = 200;
var yshift = 200;
function Move_DivGraphCanvas(e) {
    //Отлавливаем координаты в момент onmousedown
    if (!e) e = window.event;
    x = e.pageX || e.x;
    y = e.pageY || e.y;
    elem = $get('divGraphCanvas'); //Указываем на наш элемент
    xshift = x-elem.style.left.substring(0, elem.style.left.length - 2);
    yshift = y-elem.style.top.substring(0, elem.style.top.length - 2);
    //Вешаем на документ правила для передвижения курсора
    document.onmousemove = function(e) {
        //Отлавливаем координаты
        if (!e) e = window.event;
        var x2 = e.pageX || e.x;
        var y2 = e.pageY || e.y;
        y2 = y2 - yshift;
        x2 = x2 - xshift;
        //Задаем эти координаты элементу
        elem.style.top = y2 + 'px';
        elem.style.left = x2 + 'px';
    }
    document.onmouseup = function() {  document.onmousemove = null; };
}*/

