<!DOCTYPE html>
<html lang=de">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>LED Board</title>
    <style>
      body {background-color: #ccc; margin: 0; padding: 0; text-align: center;}
      input {background-color: #ccc; border-radius: 2px;}
      .menu { background-color: rgb(4, 0, 59); color: #ccc; padding: 1.2em; width: 100%; box-sizing: border-box; margin-bottom: 1em;}
      .btn { background-color: #005; border-radius: 2px; color:#ccc; box-shadow: 5px, 5px, 5px, #000; padding: 5px;}
    </style>
  </head>
  <body>
    <div class="menu">
      IP: <input type="text" id="ip" value="10.23.42.24">
      <div style="width: 2em; display: inline-block;" ></div>
      Port: <input type="text" id="port" value="81" style="width: 2.5em;">
      <div style="width: 2em; display: inline-block;" ></div>
      Panel width: <input type="text" id="width" value="32" style="width: 2.5em;" onchange="creatGUI()">
      height: <input type="text" id="height" value="40" style="width: 2.5em;" onchange="creatGUI()">
      <div style="width: 1em; display: inline-block;" ></div>
      Connection state: <div id="connectionState" onclick="toggleConnection()" style="background-color: red; display: inline-block; width: 1em; height: 1em; border-radius: 0.5em;"></div>
      
    </div>

    <input class="btn" type="button" value="clear" onclick="clearCanvas()">
    <input type="file" id="fileupload" value="upload file" style="display: none;" />
    <label class="btn" for="fileupload">upload a file</label>
    <br />
    <canvas id="can" style="background-color:#000; margin: 1em;"></canvas> <br />
    <textarea id="textInput"></textarea><br />
    <input type="button" value="print" onclick="textInputChanged()" />

    <script type="text/javascript">
      var socket;
      document.onload = openWebSocket();
      var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));

      var canvas, ctx = false,
        prevX = 0,
        currX = 0,
        prevY = 0,
        currY = 0,
        dragMode = false;

      var onColor = "#fd0";
      var offColor = "#310";
      
      var pixelBuffer = new Array(0);
      var scaling;
      var xMax, yMax;
      var changeFlag = false;
      var frameRate = 3;    //frames per second

      creatGUI();
      setTimeout(frameRefresh, 1000 / frameRate);

      
      function openWebSocket()
      {
        ip = document.getElementById('ip').value;
        port = document.getElementById('port').value;
        panelWidthElement = document.getElementById('width');
        panelHeightElement = document.getElementById('height');

        displayView = document.getElementById("can");
        console.log("connect to " + ip + ":" + port);

        socket = new WebSocket('ws://' + ip + ':'+port+'', ['arduino']);
        socket.onopen = function () 
        {
          console.log('connected');
          document.getElementById('connectionState').style.backgroundColor = "#3d3";
        };
        
        socket.onerror = function (error) 
        {
          console.log('WebSocket Error ', error);
          document.getElementById('connectionState').style.backgroundColor = "#dd3";
        };
        
        socket.onclose = function () 
        {
          console.log('WebSocket connection closed');
          document.getElementById('connectionState').style.backgroundColor = "#d33";
        };
      }

      function frameRefresh()
      {
        if(changeFlag==true && socket.readyState === WebSocket.OPEN)
        {
          changeFlag = false;
          sendPixelBuffer();
          console.log("refreshed");
        }

        setTimeout(frameRefresh, 1000 / frameRate);
      }

      function toggleConnection()
      {
        if(socket.readyState === WebSocket.CLOSED)
        {
          openWebSocket();
        }
        else
        {
          socket.close();
        }

      }

      function sendPixelBuffer()
      {
        header = new Uint8Array(6);
        header[0] = Math.floor(xMax / 255);
        header[1] = xMax % 255;
        header[2] = Math.floor(yMax / 255);
        header[3] = yMax % 255;
        header[4] = 0;
        header[5] = 0;

        socket.send(header);
        socket.send(pixelBuffer);
      }

      function creatGUI()
      {
        scaling = 10;//(document.width / 2) / panelWidthElement.value;

        xMax = panelWidthElement.value;
        yMax = panelHeightElement.value;
        displayView.width = panelWidthElement.value*scaling;// + "px";
        displayView.height = panelHeightElement.value*scaling;// + "px";
        
        pixelBuffer = new Uint8Array(xMax*yMax);

        initCanvas();
      }

      function clearCanvas()
      {
        ctx = canvas.getContext("2d");
        ctx.clearRect(0, 0, displayView.width, displayView.height);

        for(x = 0; x < xMax; x++)
        {

          for(y = 0; y < yMax; y++)
          {
            pixelBuffer[x, xMax*y] = 0;
            drawDot(x*scaling+1, y*scaling +1, true);
          }
        }
      }

      function initCanvas() {
        canvas = document.getElementById('can');
        ctx = canvas.getContext("2d");
        w = canvas.width;
        h = canvas.height;
    
        canvas.addEventListener("mousemove", function (e) {
            findxy('move', e)
        }, false);
        canvas.addEventListener("mousedown", function (e) {
            findxy('down', e)
        }, false);
        canvas.addEventListener("mouseup", function (e) {
            findxy('up', e)
        }, false);
        canvas.addEventListener("mouseout", function (e) {
            findxy('out', e)
        }, false);

        clearCanvas();
      }

    function findxy(res, e) {
        if (res == 'down') {
            prevX = currX;
            prevY = currY;
            currX = e.clientX - canvas.offsetLeft;
            currY = e.clientY - canvas.offsetTop;
    
            drawDot(currX, currY);
            dragMode = true;
        }
        if (res == 'up' || res == "out") {
            dragMode = false;
        }
        if (res == 'move') {
            if (dragMode) {
                prevX = currX;
                prevY = currY;
                currX = e.clientX - canvas.offsetLeft;
                currY = e.clientY - canvas.offsetTop;
                drawDot(currX, currY);
            }
        }
    }

    function drawDot(x, y, forceOff=false)
    {
      x =  Math.floor(x / scaling);
      y =  Math.floor(y / scaling);

      if((pixelBuffer[x+xMax*y] == 0 || dragMode==true) && forceOff==false)
      {
        ctx.fillStyle = onColor;
        if(pixelBuffer[x+xMax*y] != 1)
        {
          changeFlag = true;
        }
        pixelBuffer[x+xMax*y] = 1;
      }
      else
      {
        ctx.fillStyle = offColor;

        if(pixelBuffer[x+xMax*y] != 0)
        {
          changeFlag = true;
        }
        pixelBuffer[x+xMax*y] = 0;
      }

      ctx.beginPath();
      ctx.arc(x * scaling + scaling/2, y * scaling + scaling/2, scaling/2, 0, 2 * Math.PI);
      
      ctx.fill();
      ctx.stroke();
    }

    function displayBufferContent()
    {
      dragMode = true;
      for(x = 0; x < xMax; x++)
      {
        for(y = 0; y < yMax; y++)
        {
          if(pixelBuffer[x + xMax*y] != 0)
          {
            drawDot(x*scaling+1, y*scaling +1);
          }
          else
          {
            drawDot(x*scaling+1, y*scaling +1, true);
          }
        }
      }
      dragMode = false;
      changeFlag = true;
    }

    //====================================================================
    //========= image upload functione... ==========
    //====================================================================

    document.getElementById("fileupload").addEventListener('change', imageChanged, false);
    hiddenCanvas = document.createElement("canvas");
    hiddenCtx = hiddenCanvas.getContext('2d');

    function imageChanged(evt)
    {
      
      var file = evt.target.files[0];
      if (!file.type.match('image.*')) 
      {
        alert("wrong file format");
        return;
      }

      var reader = new FileReader();
      reader.onload = function (event)
      {
        var img = new Image();
        img.src = event.target.result;
        img.onload = function()
        {
          width = img.width;
          height = img.height;
          if (width > height) 
          {
            if (width > xMax) 
            {
              height *= xMax / width;
              width = xMax;
            }
          } 
          else 
          {
            if (height > yMax) 
            {
              width *= yMax / height;
              height = yMax;
            }
          }
          hiddenCanvas.width = width;
          hiddenCanvas.height = height;
          hiddenCtx.drawImage(img, 0, 0, width, height);
          
          showHiddenCanvas();

        }
        img.src = event.target.result;
      };
      reader.readAsDataURL(file);
    }

    function showHiddenCanvas()
    {
      var threasholdRGB = 200;
      var threasholdAlpha = 100;

      for(var y = 0; y < yMax; y++)
      {
        for(var x = 0; x < xMax; x++)
        {
          var p = hiddenCtx.getImageData(x, y, 1, 1).data;
          if((p[0] < threasholdRGB || p[1] < threasholdRGB || p[2] < threasholdRGB) && p[3] > threasholdAlpha)
          {
            pixelBuffer[x+xMax*y] = 1;
          }
          else
          {
            pixelBuffer[x+xMax*y] = 0;
          }
        }
      }

      displayBufferContent();
    }

    function printText(texttodraw)
    {
      hiddenCanvas.width = xMax;
      hiddenCanvas.height = yMax;

      var lines = texttodraw.split('\n');

      hiddenCtx.clearRect(0, 0, hiddenCanvas.width, hiddenCanvas.height);

      hiddenCtx.font = '10px Verdana';
      hiddenCtx.textBaseline="top"; 
      var lineheight = 10;

      for (var j = 0; j<lines.length; j++)
      {
        hiddenCtx.fillText(lines[j], 0, 0 + (j*lineheight));
      }

      showHiddenCanvas();
    }


    function textInputChanged()
    {
      var text = document.getElementById("textInput").value;
      printText(text);
    }

    </script>
  </body>
</html>