'use strict';
define(function() {
  var fontdisplayer = function(
      PortalsFactory
  ) {
    return {
      templateUrl: 'js/XG/widgets/mapapp/style/views/fontdisplayer.html',
      restrict: 'E',
      scope: {
        ttf: '=',
        picked: '=',
        fontdata: '=',
      },
      link: function(scope, elt, attrs, ctrl) {
        if (!angular.isDefined(scope.picked)) scope.picked = {};

        var cellCount = 100,
          cellWidth = 44,
          cellHeight = 40,
          cellMarginTop = 1,
          cellMarginBottom = 8,
          cellMarginLeftRight = 1,
          glyphMargin = 5,
          pixelRatio = window.devicePixelRatio || 1;

        var paginationClasses = 'btn btn-xs btn-default fontdisplayer_page';

        var pageSelected,
          font,
          fontScale,
          fontSize,
          fontBaseline,
          glyphScale,
          glyphSize,
          glyphBaseline;

        function initGlyphDisplay() {
          var glyphCanvas = document.getElementById('glyph'),
            w = glyphCanvas.width / pixelRatio,
            h = glyphCanvas.height / pixelRatio,
            glyphW = w - glyphMargin * 2,
            glyphH = h - glyphMargin * 2,
            head = scope.font.tables.head,
            maxHeight = head.yMax - head.yMin,
            ctx = glyphCanvas.getContext('2d');

          glyphScale = Math.min(
            glyphW / (head.xMax - head.xMin),
            glyphH / maxHeight
          );
          glyphSize = glyphScale * scope.font.unitsPerEm;
          glyphBaseline = glyphMargin + (glyphH * head.yMax) / maxHeight;
          ctx.clearRect(0, 0, w, h);
          ctx.fillStyle = '#a0a0a0';
        }

        function renderGlyphItem(canvas, glyphIndex) {
          var cellMarkSize = 4;
          var ctx = canvas.getContext('2d');
          ctx.clearRect(0, 0, cellWidth, cellHeight);
          if (glyphIndex >= scope.font.numGlyphs) return;

          var glyph = scope.font.glyphs.get(glyphIndex),
            glyphWidth = glyph.advanceWidth * fontScale,
            xmin = (cellWidth - glyphWidth) / 2;

          glyph.draw(ctx, xmin, fontBaseline, fontSize);
        }

        function displayGlyphPage(pageNum) {
          pageSelected = pageNum;
          document.getElementById('fontdisplayer_page' + pageNum).className =
            paginationClasses + ' btn-primary page-selected';
          var firstGlyph = pageNum * cellCount;
          for (var i = 0; i < cellCount; i++) {
            renderGlyphItem(
              document.getElementById('fontdisplayer_glyph' + i),
              firstGlyph + i
            );
          }
        }

        function displayGlyph(glyphIndex) {
          var canvas = document.getElementById('glyph'),
            ctx = canvas.getContext('2d'),
            width = canvas.width / pixelRatio,
            height = canvas.height / pixelRatio;

          ctx.clearRect(0, 0, width, height);
          if (glyphIndex < 0) return;
          var glyph = scope.font.glyphs.get(glyphIndex),
            glyphWidth = glyph.advanceWidth * glyphScale,
            xmin = (width - glyphWidth) / 2,
            xmax = (width + glyphWidth) / 2,
            x0 = xmin,
            markSize = 10;

          var path = glyph.getPath(x0, glyphBaseline, glyphSize);
          path.fill = '#dddddd';
          path.stroke = '#000000';
          path.strokeWidth = 1.5;
          drawPathWithArrows(ctx, path);
          // glyph.drawPoints(ctx, x0, glyphBaseline, glyphSize);
        }

        function drawPathWithArrows(ctx, path) {
          var i, cmd, x1, y1, x2, y2;
          var arrows = [];
          ctx.beginPath();
          for (i = 0; i < path.commands.length; i += 1) {
            cmd = path.commands[i];
            if (cmd.type === 'M') {
              if (x1 !== undefined) {
                arrows.push([ctx, x1, y1, x2, y2]);
              }
              ctx.moveTo(cmd.x, cmd.y);
            } else if (cmd.type === 'L') {
              ctx.lineTo(cmd.x, cmd.y);
              x1 = x2;
              y1 = y2;
            } else if (cmd.type === 'C') {
              ctx.bezierCurveTo(cmd.x1, cmd.y1, cmd.x2, cmd.y2, cmd.x, cmd.y);
              x1 = cmd.x2;
              y1 = cmd.y2;
            } else if (cmd.type === 'Q') {
              ctx.quadraticCurveTo(cmd.x1, cmd.y1, cmd.x, cmd.y);
              x1 = cmd.x1;
              y1 = cmd.y1;
            } else if (cmd.type === 'Z') {
              arrows.push([ctx, x1, y1, x2, y2]);
              ctx.closePath();
            }
            x2 = cmd.x;
            y2 = cmd.y;
          }
          if (path.fill) {
            ctx.fillStyle = path.fill;
            ctx.fill();
          }
          if (path.stroke) {
            ctx.strokeStyle = path.stroke;
            ctx.lineWidth = path.strokeWidth;
            ctx.stroke();
          }
          ctx.fillStyle = '#000000';
        }

        /*function contourToString(contour) {
                    return '<pre class="contour">' + contour.map(function(point) {
                            return '<span class="' + (point.onCurve ? 'on' : 'off') + 'curve">x=' + point.x + ' y=' + point.y + '</span>';
                        }).join('\n') + '</pre>';
                }*/
        function formatUnicode(unicode) {
          console.log(unicode);
          unicode = unicode.toString(16);
          console.log(unicode);
          if (unicode.length > 4) {
            return ('000000' + unicode.toUpperCase()).substr(-6);
          } else {
            return ('0000' + unicode.toUpperCase()).substr(-4);
          }
        }

        function pageSelect(event) {
          document.getElementsByClassName(
            'fontdisplayer_page page-selected'
          )[0].className = paginationClasses;
          displayGlyphPage(+event.target.id.replace('fontdisplayer_page', ''));
        }

        function displayGlyphData(glyphIndex) {
          var glyph = scope.font.glyphs.get(glyphIndex);
          console.log(glyph);
          if (glyph && glyph.unicodes.length > 0) {
            try {
              scope.$apply(function() {
                var value = glyph.unicodes
                  .map(formatUnicode)
                  .join(', ')
                  .replace('F', '0x0');
                console.log(value);
                // specific rules
                if (scope.ttf == 'CartajourASS') {
                }
                scope.picked.value = value;
              });
            } catch(err) {}
          }

          /* var container = document.getElementById('glyph-data');
                    if (glyphIndex < 0) {
                        container.innerHTML = '';
                        return;
                    }
                    var glyph = scope.font.glyphs.get(glyphIndex),
                        html;
                    html = '<dt>name</dt><dd>'+glyph.name+'</dd>';

                    if (glyph.unicodes.length > 0) {
                        html += '<dt>unicode</dt><dd>'+ glyph.unicodes.map(formatUnicode).join(', ') +'</dd>';
                    }
                    html += '<dl><dt>index</dt><dd>'+glyph.index+'</dd>';

                    if (glyph.xMin !== 0 || glyph.xMax !== 0 || glyph.yMin !== 0 || glyph.yMax !== 0) {
                        html += '<dt>xMin</dt><dd>'+glyph.xMin+'</dd>' +
                        '<dt>xMax</dt><dd>'+glyph.xMax+'</dd>' +
                        '<dt>yMin</dt><dd>'+glyph.yMin+'</dd>' +
                        '<dt>yMax</dt><dd>'+glyph.yMax+'</dd>';
                    }
                    html += '<dt>advanceWidth</dt><dd>'+glyph.advanceWidth+'</dd>';
                    if(glyph.leftSideBearing !== undefined) {
                        html += '<dt>leftSideBearing</dt><dd>'+glyph.leftSideBearing+'</dd>';
                    }
                    html += '</dl>';
                    if (glyph.numberOfContours > 0) {
                        var contours = glyph.getContours();
                        html += 'contours:<br>' + contours.map(contourToString).join('\n');
                    } else if (glyph.isComposite) {
                        html += '<br>This composite glyph is a combination of :<ul><li>' +
                        glyph.components.map(function(component) {
                            return 'glyph '+component.glyphIndex+' at dx='+component.dx+', dy='+component.dy;
                        }).join('</li><li>') + '</li></ul>';
                    } else if (glyph.path) {
                        html += 'path:<br><pre>  ' + glyph.path.commands.map(pathCommandToString).join('\n  ') + '\n</pre>';
                    }
                    container.innerHTML = html;*/
        }

        function onFontLoaded(font) {
          scope.font = font;

          var w = cellWidth - cellMarginLeftRight * 2,
            h = cellHeight - cellMarginTop - cellMarginBottom,
            head = scope.font.tables.head,
            maxHeight = head.yMax - head.yMin;
          fontScale = Math.min(w / (head.xMax - head.xMin), h / maxHeight);
          fontSize = fontScale * scope.font.unitsPerEm;
          fontBaseline = cellMarginTop + (h * head.yMax) / maxHeight;

          var pagination = document.getElementById('fontdisplayer_pagination');
          if (pagination) {
            pagination.innerHTML = '';
            var fragment = document.createDocumentFragment();
            var numPages = Math.ceil(scope.font.numGlyphs / cellCount);

            for (var i = 0; i < numPages; i++) {
              var link = document.createElement('div');
              var lastIndex = Math.min(
                  scope.font.numGlyphs - 1,
                  (i + 1) * cellCount - 1
              );
              link.textContent = i * cellCount + '-' + lastIndex;
              link.id = 'fontdisplayer_page' + i;
              link.className = paginationClasses;
              link.addEventListener('click', pageSelect, false);
              fragment.appendChild(link);
              // A white space allows to break very long lines into multiple lines.
              // This is needed for fonts with thousands of glyphs.
              fragment.appendChild(document.createTextNode(' '));
            }
            pagination.appendChild(fragment);
          }

          initGlyphDisplay();
          displayGlyphPage(0);
          displayGlyph(-1);
          displayGlyphData(-1);
        }

        function cellSelect(event) {
          if (!scope.font) return;
          var firstGlyphIndex = pageSelected * cellCount,
            cellIndex = +event.target.id.replace('fontdisplayer_glyph', ''),
            glyphIndex = firstGlyphIndex + cellIndex;
          if (glyphIndex < scope.font.numGlyphs) {
            displayGlyph(glyphIndex);
            displayGlyphData(glyphIndex);
          }
        }

        function prepareGlyphList() {
          var marker = document.getElementById('glyph-list-end'),
            parent = marker.parentElement;
          for (var i = 0; i < cellCount; i++) {
            var canvas = document.createElement('canvas');
            canvas.width = cellWidth;
            canvas.height = cellHeight;
            canvas.className = 'item';
            canvas.id = 'fontdisplayer_glyph' + i;
            canvas.addEventListener('click', cellSelect, false);
            parent.insertBefore(canvas, marker);
          }
        }

        prepareGlyphList();

        scope.$watch(
          'ttf',
          function(ttf) {
            opentype.load(
              '/services/' +
                PortalsFactory.getPortalId() +
                '/style/ttf/file?f=json' +
                '&name=' +
                ttf,
              function(err, font) {
                if (err) {
                  console.log('error');
                  return;
                }
                // extract the font name from the ttf if provided
                scope.fontdata.name = font.familyName ? font.familyName : null;
                onFontLoaded(font);
              }
            );
          },
          1
        );
      },
    };
  };

  fontdisplayer.$inject = [
      'PortalsFactory'
  ];
  return fontdisplayer;
});
