/* eslint-disable */

const AttributedStringIterator = function (text) {
  this.rtrim = function (str) {
    const patt2 = /\s+$/g;
    return str.replace(patt2, "");
  };

  text = text.replace(/(\s)+/, " ");
  this.text = this.rtrim(text);

  this.beginIndex = 0;
  this.endIndex = this.text.length;
  this.currentIndex = this.beginIndex;

  let i = 0;
  let string = this.text;
  let fullPos = 0;

  this.startWordOffsets = [];
  this.startWordOffsets.push(fullPos);

  // TODO: remove i 1000
  while (i < 1000) {
    const pos = string.search(/[ \t\n\f-\.\,]/);
    if (pos === -1)
      break;

    // whitespace start
    fullPos += pos;
    string = string.substr(pos);
    ////console.log("fullPos: " + fullPos + ", pos: " + pos +  ", string: ", string);

    // remove whitespaces
    const pos1 = string.search(/[^ \t\n\f-\.\,]/);
    if (pos1 === -1)
      break;

    // whitespace end
    fullPos += pos1;
    string = string.substr(pos1);

    ////console.log("fullPos: " + fullPos);
    this.startWordOffsets.push(fullPos);

    i++;
  }
  //console.log("startWordOffsets: ", this.startWordOffsets);
  //console.groupEnd();

  this.getEndIndex = function (pos) {
    if (typeof(pos) === "undefined")
      return this.endIndex;

    const string = this.text.substr(pos, this.endIndex - pos);

    const posEndOfLine = string.search(/[\n]/);
    if (posEndOfLine === -1)
      return this.endIndex;
    else
      return pos + posEndOfLine;
  };
  this.getBeginIndex = function () {
    return this.beginIndex;
  };
  this.isWhitespace = function (pos) {
    const str = this.text[pos];
    const whitespaceChars = " \t\n\f";

    return (whitespaceChars.indexOf(str) !== -1);
  };
  this.isNewLine = function (pos) {
    const str = this.text[pos];
    const whitespaceChars = "\n";

    return (whitespaceChars.indexOf(str) !== -1);
  };
  this.preceding = function (pos) {
    //console.group("[AttributedStringIterator.preceding]");
    for (const i in this.startWordOffsets) {
      const startWordOffset = this.startWordOffsets[i];
      if (pos < startWordOffset && i > 0) {
        //console.log("startWordOffset: " + this.startWordOffsets[i-1]);
        //console.groupEnd();
        return this.startWordOffsets[i - 1];
      }
    }
    //console.log("pos: " + pos);
    //console.groupEnd();
    return this.startWordOffsets[i];
  };
  this.following = function (pos) {
    //console.group("[AttributedStringIterator.following]");
    for (const i in this.startWordOffsets) {
      const startWordOffset = this.startWordOffsets[i];
      if (pos < startWordOffset && i > 0) {
        //console.log("startWordOffset: " + this.startWordOffsets[i]);
        //console.groupEnd();
        return this.startWordOffsets[i];
      }
    }
    //console.log("pos: " + pos);
    //console.groupEnd();
    return this.startWordOffsets[i];
  };
  this.ltrim = function (str) {
    const patt2 = /^\s+/g;
    return str.replace(patt2, "");
  };

  this.getLayout = function (start, limit) {
    return this.text.substr(start, limit - start);
  };
  this.getCharAtPos = function (pos) {
    return this.text[pos];
  };
};
AttributedStringIterator.prototype = {

};

const LineBreakMeasurer = function (paper, x, y, text, fontAttrs) {
  this.paper = paper;
  this.text = new AttributedStringIterator(text);
  this.fontAttrs = fontAttrs;

  if (this.text.getEndIndex() - this.text.getBeginIndex() < 1) {
    throw {message: "Text must contain at least one character.", code: "IllegalArgumentException"};
  }

  //this.measurer = new TextMeasurer(paper, this.text, this.fontAttrs);
  this.limit = this.text.getEndIndex();
  this.pos = this.start = this.text.getBeginIndex();

  this.rafaelTextObject = this.paper.text(x, y, this.text.text).attr(fontAttrs).attr("text-anchor", "start");
  this.svgTextObject = this.rafaelTextObject[0];

  this.getLineBreakIndex = function (pos, wrappingWidth) {
    //console.group("[getLineBreakIndex]");
    //console.log("pos:"+pos + ", text: \""+ this.text.text.replace(/\n/g, "_").substr(pos, 1) + "\"");

    const bb = this.rafaelTextObject.getBBox();

    let charNum = -1;
    try {
      const svgPoint = this.svgTextObject.getStartPositionOfChar(pos);
      //const dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.blue});
      svgPoint.x = svgPoint.x + wrappingWidth;
      //svgPoint.y = bb.y;
      //console.log("svgPoint:", svgPoint);

      //const dot = this.paper.ellipse(svgPoint.x, svgPoint.y, 1, 1).attr({"stroke-width": 0, fill: Color.red});

      charNum = this.svgTextObject.getCharNumAtPosition(svgPoint);
    } catch (e) {
      console.warn("getStartPositionOfChar error, pos:" + pos);
      /*
       const testPos = pos + 1;
       if (testPos < this.limit) {
       return testPos
       }
       */
    }
    //console.log("charNum:", charNum);
    if (charNum === -1) {
      //console.groupEnd();
      return this.text.getEndIndex(pos);
    } else {
      // When case there is new line between pos and charnum then use this new line
      const newLineIndex = this.text.getEndIndex(pos);
      if (newLineIndex < charNum) {
        console.log("newLineIndex <= charNum, newLineIndex:" + newLineIndex + ", charNum:" + charNum, "\"" + this.text.text.substr(newLineIndex + 1).replace(/\n/g, "?") + "\"");
        //console.groupEnd();

        return newLineIndex;
      }

      //const charAtMaxAdvance  = this.text.text.substring(charNum, charNum + 1);
      const charAtMaxAdvance = this.text.getCharAtPos(charNum);
      //console.log("!!charAtMaxAdvance: " + charAtMaxAdvance);
      //console.groupEnd();
      return charNum;
    }
  };

  this.nextOffset = function (wrappingWidth, offsetLimit, requireNextWord) {
    //console.group("[nextOffset]");
    let nextOffset = this.pos;
    if (this.pos < this.limit) {
      if (offsetLimit <= this.pos) {
        throw {message: "offsetLimit must be after current position", code: "IllegalArgumentException"};
      }

      const charAtMaxAdvance = this.getLineBreakIndex(this.pos, wrappingWidth);
      //charAtMaxAdvance --;
      //console.log("charAtMaxAdvance:", charAtMaxAdvance, ", [" + this.text.getCharAtPos(charAtMaxAdvance) + "]");

      if (charAtMaxAdvance === this.limit) {
        nextOffset = this.limit;
        //console.log("charAtMaxAdvance == this.limit");
      } else if (this.text.isNewLine(charAtMaxAdvance)) {
        //console.log("isNewLine");
        nextOffset = charAtMaxAdvance + 1;
      } else if (this.text.isWhitespace(charAtMaxAdvance)) {
        // TODO: find next noSpaceChar
        //return nextOffset;
        nextOffset = this.text.following(charAtMaxAdvance);
      } else {
        // Break is in a word;  back up to previous break.
        /*
         const testPos = charAtMaxAdvance + 1;
         if (testPos == this.limit) {
         console.error("hbz...");
         } else {
         nextOffset = this.text.preceding(charAtMaxAdvance);
         }
         */
        nextOffset = this.text.preceding(charAtMaxAdvance);

        if (nextOffset <= this.pos) {
          nextOffset = Math.max(this.pos + 1, charAtMaxAdvance);
        }
      }
    }
    if (nextOffset > offsetLimit) {
      nextOffset = offsetLimit;
    }
    //console.log("nextOffset: " + nextOffset);
    //console.groupEnd();
    return nextOffset;
  };

  this.nextLayout = function (wrappingWidth) {
    //console.groupCollapsed("[nextLayout]");
    if (this.pos < this.limit) {
      const requireNextWord = false;
      const layoutLimit = this.nextOffset(wrappingWidth, this.limit, requireNextWord);
      //console.log("layoutLimit:", layoutLimit);
      if (layoutLimit === this.pos) {
        //console.groupEnd();
        return null;
      }
      const result = this.text.getLayout(this.pos, layoutLimit);
      //console.log("layout: \"" + result + "\"");

      // remove end of line

      //const posEndOfLine = this.text.getEndIndex(this.pos);
      //if (posEndOfLine < result.length)
      //	result = result.substr(0, posEndOfLine);

      this.pos = layoutLimit;

      //console.groupEnd();
      return result;
    } else {
      //console.groupEnd();
      return null;
    }
  };

  this.getPosition =  function () {
    return this.pos;
  }
};

export default LineBreakMeasurer;
