# modules/utf8.js

    import { jsPDF } from "../jspdf.js";
    import { toPDFName } from "../libs/pdfname.js";

    /**
     * @name utf8
     * @module
     */
    (function(jsPDF) {
      "use strict";
      var jsPDFAPI = jsPDF.API;

      /***************************************************************************************************/
      /* function : pdfEscape16                                                                          */
      /* comment : The character id of a 2-byte string is converted to a hexadecimal number by obtaining */
      /*   the corresponding glyph id and width, and then adding padding to the string.                  */
      /***************************************************************************************************/
      var pdfEscape16 = (jsPDFAPI.pdfEscape16 = function(text, font) {
        var widths = font.metadata.Unicode.widths;
        var padz = ["", "0", "00", "000", "0000"];
        var ar = [""];
        for (var i = 0, l = text.length, t; i < l; ++i) {
          t = font.metadata.characterToGlyph(text.charCodeAt(i));
          font.metadata.glyIdsUsed.push(t);
          font.metadata.toUnicode[t] = text.charCodeAt(i);
          if (widths.indexOf(t) == -1) {
            widths.push(t);
            widths.push([parseInt(font.metadata.widthOfGlyph(t), 10)]);
          }
          if (t == "0") {
            //Spaces are not allowed in cmap.
            return ar.join("");
          } else {
            t = t.toString(16);
            ar.push(padz[4 - t.length], t);
          }
        }
        return ar.join("");
      });

      var toUnicodeCmap = function(map) {
        var code, codes, range, unicode, unicodeMap, _i, _len;
        unicodeMap =
          "/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo <<\n  /Registry (Adobe)\n  /Ordering (UCS)\n  /Supplement 0\n>> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000><ffff>\nendcodespacerange";
        codes = Object.keys(map).sort(function(a, b) {
          return a - b;
        });

        range = [];
        for (_i = 0, _len = codes.length; _i < _len; _i++) {
          code = codes[_i];
          if (range.length >= 100) {
            unicodeMap +=
              "\n" +
              range.length +
              " beginbfchar\n" +
              range.join("\n") +
              "\nendbfchar";
            range = [];
          }

          if (
            map[code] !== undefined &&
            map[code] !== null &&
            typeof map[code].toString === "function"
          ) {
            unicode = ("0000" + map[code].toString(16)).slice(-4);
            code = ("0000" + (+code).toString(16)).slice(-4);
            range.push("<" + code + "><" + unicode + ">");
          }
        }

        if (range.length) {
          unicodeMap +=
            "\n" +
            range.length +
            " beginbfchar\n" +
            range.join("\n") +
            "\nendbfchar\n";
        }
        unicodeMap +=
          "endcmap\nCMapName currentdict /CMap defineresource pop\nend\nend";
        return unicodeMap;
      };

      var identityHFunction = function(options) {
        var font = options.font;
        var out = options.out;
        var newObject = options.newObject;
        var putStream = options.putStream;

        if (
          font.metadata instanceof jsPDF.API.TTFFont &&
          font.encoding === "Identity-H"
        ) {
          //Tag with Identity-H
          var widths = font.metadata.Unicode.widths;
          var data = font.metadata.subset.encode(font.metadata.glyIdsUsed, 1);
          var pdfOutput = data;
          var pdfOutput2 = "";
          for (var i = 0; i < pdfOutput.length; i++) {
            pdfOutput2 += String.fromCharCode(pdfOutput[i]);
          }
          var fontTable = newObject();
          putStream({ data: pdfOutput2, addLength1: true, objectId: fontTable });
          out("endobj");

          var cmap = newObject();
          var cmapData = toUnicodeCmap(font.metadata.toUnicode);
          putStream({ data: cmapData, addLength1: true, objectId: cmap });
          out("endobj");

          var fontDescriptor = newObject();
          out("<<");
          out("/Type /FontDescriptor");
          out("/FontName /" + toPDFName(font.fontName));
          out("/FontFile2 " + fontTable + " 0 R");
          out("/FontBBox " + jsPDF.API.PDFObject.convert(font.metadata.bbox));
          out("/Flags " + font.metadata.flags);
          out("/StemV " + font.metadata.stemV);
          out("/ItalicAngle " + font.metadata.italicAngle);
          out("/Ascent " + font.metadata.ascender);
          out("/Descent " + font.metadata.decender);
          out("/CapHeight " + font.metadata.capHeight);
          out(">>");
          out("endobj");

          var DescendantFont = newObject();
          out("<<");
          out("/Type /Font");
          out("/BaseFont /" + toPDFName(font.fontName));
          out("/FontDescriptor " + fontDescriptor + " 0 R");
          out("/W " + jsPDF.API.PDFObject.convert(widths));
          out("/CIDToGIDMap /Identity");
          out("/DW 1000");
          out("/Subtype /CIDFontType2");
          out("/CIDSystemInfo");
          out("<<");
          out("/Supplement 0");
          out("/Registry (Adobe)");
          out("/Ordering (" + font.encoding + ")");
          out(">>");
          out(">>");
          out("endobj");

          font.objectNumber = newObject();
          out("<<");
          out("/Type /Font");
          out("/Subtype /Type0");
          out("/ToUnicode " + cmap + " 0 R");
          out("/BaseFont /" + toPDFName(font.fontName));
          out("/Encoding /" + font.encoding);
          out("/DescendantFonts [" + DescendantFont + " 0 R]");
          out(">>");
          out("endobj");

          font.isAlreadyPutted = true;
        }
      };

      jsPDFAPI.events.push([
        "putFont",
        function(args) {
          identityHFunction(args);
        }
      ]);

      var winAnsiEncodingFunction = function(options) {
        var font = options.font;
        var out = options.out;
        var newObject = options.newObject;
        var putStream = options.putStream;

        if (
          font.metadata instanceof jsPDF.API.TTFFont &&
          font.encoding === "WinAnsiEncoding"
        ) {
          //Tag with WinAnsi encoding
          var data = font.metadata.rawData;
          var pdfOutput = data;
          var pdfOutput2 = "";
          for (var i = 0; i < pdfOutput.length; i++) {
            pdfOutput2 += String.fromCharCode(pdfOutput[i]);
          }
          var fontTable = newObject();
          putStream({ data: pdfOutput2, addLength1: true, objectId: fontTable });
          out("endobj");

          var cmap = newObject();
          var cmapData = toUnicodeCmap(font.metadata.toUnicode);
          putStream({ data: cmapData, addLength1: true, objectId: cmap });
          out("endobj");

          var fontDescriptor = newObject();
          out("<<");
          out("/Descent " + font.metadata.decender);
          out("/CapHeight " + font.metadata.capHeight);
          out("/StemV " + font.metadata.stemV);
          out("/Type /FontDescriptor");
          out("/FontFile2 " + fontTable + " 0 R");
          out("/Flags 96");
          out("/FontBBox " + jsPDF.API.PDFObject.convert(font.metadata.bbox));
          out("/FontName /" + toPDFName(font.fontName));
          out("/ItalicAngle " + font.metadata.italicAngle);
          out("/Ascent " + font.metadata.ascender);
          out(">>");
          out("endobj");
          font.objectNumber = newObject();
          for (var j = 0; j < font.metadata.hmtx.widths.length; j++) {
            font.metadata.hmtx.widths[j] = parseInt(
              font.metadata.hmtx.widths[j] * (1000 / font.metadata.head.unitsPerEm)
            ); //Change the width of Em units to Point units.
          }
          out(
            "<</Subtype/TrueType/Type/Font/ToUnicode " +
              cmap +
              " 0 R/BaseFont/" +
              toPDFName(font.fontName) +
              "/FontDescriptor " +
              fontDescriptor +
              " 0 R" +
              "/Encoding/" +
              font.encoding +
              " /FirstChar 29 /LastChar 255 /Widths " +
              jsPDF.API.PDFObject.convert(font.metadata.hmtx.widths) +
              ">>"
          );
          out("endobj");
          font.isAlreadyPutted = true;
        }
      };

      jsPDFAPI.events.push([
        "putFont",
        function(args) {
          winAnsiEncodingFunction(args);
        }
      ]);

      var utf8TextFunction = function(args) {
        var text = args.text || "";
        var x = args.x;
        var y = args.y;
        var options = args.options || {};
        var mutex = args.mutex || {};

        var pdfEscape = mutex.pdfEscape;
        var activeFontKey = mutex.activeFontKey;
        var fonts = mutex.fonts;
        var key = activeFontKey;

        var str = "",
          s = 0,
          cmapConfirm;
        var strText = "";
        var encoding = fonts[key].encoding;

        if (fonts[key].encoding !== "Identity-H") {
          return {
            text: text,
            x: x,
            y: y,
            options: options,
            mutex: mutex
          };
        }
        strText = text;

        key = activeFontKey;
        if (Array.isArray(text)) {
          strText = text[0];
        }
        for (s = 0; s < strText.length; s += 1) {
          if (fonts[key].metadata.hasOwnProperty("cmap")) {
            cmapConfirm =
              fonts[key].metadata.cmap.unicode.codeMap[strText[s].charCodeAt(0)];
            /*
                 if (Object.prototype.toString.call(text) === '[object Array]') {
                    var i = 0;
                   // for (i = 0; i < text.length; i += 1) {
                        if (Object.prototype.toString.call(text[s]) === '[object Array]') {
                            cmapConfirm = fonts[key].metadata.cmap.unicode.codeMap[strText[s][0].charCodeAt(0)]; //Make sure the cmap has the corresponding glyph id
                        } else {

                        }
                    //}

                } else {
                    cmapConfirm = fonts[key].metadata.cmap.unicode.codeMap[strText[s].charCodeAt(0)]; //Make sure the cmap has the corresponding glyph id
                }*/
          }
          if (!cmapConfirm) {
            if (
              strText[s].charCodeAt(0) < 256 &&
              fonts[key].metadata.hasOwnProperty("Unicode")
            ) {
              str += strText[s];
            } else {
              str += "";
            }
          } else {
            str += strText[s];
          }
        }
        var result = "";
        if (parseInt(key.slice(1)) < 14 || encoding === "WinAnsiEncoding") {
          //For the default 13 font
          result = pdfEscape(str, key)
            .split("")
            .map(function(cv) {
              return cv.charCodeAt(0).toString(16);
            })
            .join("");
        } else if (encoding === "Identity-H") {
          result = pdfEscape16(str, fonts[key]);
        }
        mutex.isHex = true;

        return {
          text: result,
          x: x,
          y: y,
          options: options,
          mutex: mutex
        };
      };

      var utf8EscapeFunction = function(parms) {
        var text = parms.text || "",
          x = parms.x,
          y = parms.y,
          options = parms.options,
          mutex = parms.mutex;
        var tmpText = [];
        var args = {
          text: text,
          x: x,
          y: y,
          options: options,
          mutex: mutex
        };

        if (Array.isArray(text)) {
          var i = 0;
          for (i = 0; i < text.length; i += 1) {
            if (Array.isArray(text[i])) {
              if (text[i].length === 3) {
                tmpText.push([
                  utf8TextFunction(Object.assign({}, args, { text: text[i][0] }))
                    .text,
                  text[i][1],
                  text[i][2]
                ]);
              } else {
                tmpText.push(
                  utf8TextFunction(Object.assign({}, args, { text: text[i] })).text
                );
              }
            } else {
              tmpText.push(
                utf8TextFunction(Object.assign({}, args, { text: text[i] })).text
              );
            }
          }
          parms.text = tmpText;
        } else {
          parms.text = utf8TextFunction(
            Object.assign({}, args, { text: text })
          ).text;
        }
      };

      jsPDFAPI.events.push(["postProcessText", utf8EscapeFunction]);
    })(jsPDF);