"use strict";

var UrsLCDDisplay = function (canvas, parameters) {
   parameters = parameters || {};
   var context = (undefined === parameters.context ? null : parameters.context),
       width = (undefined === parameters.width ? 0 : parameters.width),
       height = (undefined === parameters.height ? 0 : parameters.height),
       value = (undefined === parameters.value ? 0 : parameters.value),
       top = (undefined === parameters.top ? 0 : parameters.top),
       left = (undefined === parameters.left ? 0 : parameters.left),
       align = (undefined === parameters.align ? 'right' : parameters.align);

   var lcdFontName = 'LCDMono2Ultra,Arial,Verdana,sans-serif';
   var ctx;
   var textColor = 'rgb(35, 42, 52)';
   var gradientStartColor = 'rgb(131, 133, 119)';
   var gradientFraction1Color = 'rgb(176, 183, 167)';
   var gradientFraction2Color = 'rgb(165, 174, 153)';
   var gradientFraction3Color = 'rgb(166, 175, 156)';
   var gradientStopColor = 'rgb(175, 184, 165)';

   // Get the canvas context and clear it
   if (context) {
      ctx = context;
   } else {
      ctx = getCanvasContext(canvas);
   }

   // Has a size been specified?
   if (width === 0) {
      width = ctx.canvas.width;
   }
   if (height === 0) {
      height = ctx.canvas.height;
   }

   var fontHeight = Math.floor(height / 1.5);
   var lcdFont = fontHeight + 'px ' + lcdFontName;

   var initialized = false;

   // **************   Buffer creation  ********************
   // Buffer for the lcd
   var lcdBuffer; // Background


   // **************   Image creation  ********************
   var drawLcdText = function (value, color) {
      ctx.save();
      ctx.textAlign =  align;
      ctx.strokeStyle = color;
      ctx.fillStyle = color;

      ctx.beginPath();
      ctx.rect(left+2, top+0, width - 4, height);
      ctx.closePath();
      ctx.clip();

      ctx.shadowColor = 'gray';
      ctx.shadowOffsetX = height * 0.035;
      ctx.shadowOffsetY = height * 0.035;
      ctx.shadowBlur = height * 0.055;

      ctx.font = lcdFont;

      // Text value
      switch (align.toLowerCase()) {
         case "left":
            ctx.fillText(value, left + 2, top + height * 0.5 + fontHeight * 0.38);
            break;
         case "center":
            ctx.fillText(value, left + width/2, top + height * 0.5 + fontHeight * 0.38);
            break;
         default:
            ctx.fillText(value, left + width - 2, top + height * 0.5 + fontHeight * 0.38);
      }
      ctx.restore();
   };

   function createBuffer(width, height) {
      var buffer = document.createElement('canvas');
      buffer.width = width;
      buffer.height = height;
      return buffer;
   }

   function roundedRectangle(ctx, x, y, w, h, radius) {
      var r = x + w,
          b = y + h;
      ctx.beginPath();
      ctx.moveTo(x + radius, y);
      ctx.lineTo(r - radius, y);
      ctx.quadraticCurveTo(r, y, r, y + radius);
      ctx.lineTo(r, y + h - radius);
      ctx.quadraticCurveTo(r, b, r - radius, b);
      ctx.lineTo(x + radius, b);
      ctx.quadraticCurveTo(x, b, x, b - radius);
      ctx.lineTo(x, y + radius);
      ctx.quadraticCurveTo(x, y, x + radius, y);
      ctx.closePath();
      //        ctx.stroke();
   }


   function getCanvasContext(elementOrId) {
      var element = (typeof elementOrId === 'string' || elementOrId instanceof String) ?
          document.getElementById(elementOrId) : elementOrId;
      return element.getContext('2d');
   }

   var createLcdBackgroundImage = function (width, height) {
      var lcdBuffer, lcdCtx,
          xB = 0,
          yB = 0,
          wB = width,
          hB = height,
          rB = Math.min(width, height) * 0.095,
          grad,
          xF = 1,
          yF = 1,
          wF = width - 2,
          hF = height - 2,
          rF = rB - 1,
          cacheKey = width.toString() + height;

      // check if we have already created and cached this buffer, if not create it
      lcdBuffer = createBuffer(width, height);
      lcdCtx = lcdBuffer.getContext('2d');
      // background
      grad = lcdCtx.createLinearGradient(0, yB, 0, yB + hB);
      grad.addColorStop(0, '#4c4c4c');
      grad.addColorStop(0.08, '#666666');
      grad.addColorStop(0.92, '#666666');
      grad.addColorStop(1, '#e6e6e6');
      lcdCtx.fillStyle = grad;
      roundedRectangle(lcdCtx, xB, yB, wB, hB, rB);
      lcdCtx.fill();

      // foreground
      grad = lcdCtx.createLinearGradient(0, yF, 0, yF + hF);
      grad.addColorStop(0, gradientStartColor);
      grad.addColorStop(0.03, gradientFraction1Color);
      grad.addColorStop(0.49, gradientFraction2Color);
      grad.addColorStop(0.5, gradientFraction3Color);
      grad.addColorStop(1, gradientStopColor);
      lcdCtx.fillStyle = grad;
      roundedRectangle(lcdCtx, xF, yF, wF, hF, rF);
      lcdCtx.fill();

      return lcdBuffer;
   };

   // **************   Initialization  ********************
   var init = function () {
      initialized = true;

      // Create lcd background if selected in background buffer (backgroundBuffer)
      lcdBuffer = createLcdBackgroundImage(width, height);
   };

   // **************   Public methods  ********************
   this.setValue = function (newValue) {
      if (value !== newValue) {
         value = newValue;
         this.repaint();
      }
      return this;
   };

   this.setAlign = function (newAlign) {
      if (align !== newAlign) {
         align = newAlign;
         this.repaint();
      }
      return this;
   };

   this.repaint = function () {
      if (!initialized) {
         init();
      }

      ctx.clearRect(left + 2, top + 2, width - 4, height - 4);
      var lcdBackgroundBuffer = lcdBuffer;

      // Draw lcd background
      ctx.drawImage(lcdBackgroundBuffer, left, top);

      // Draw lcd text
      drawLcdText(value, textColor);
   };

   // Visualize the component
   this.repaint();

   return this;
};
