// Typer.js is built by Layervault
// Link: https://github.com/layervault/jquery.typer.js

String.prototype.rightChars = function (n) {
  if (n<=0) {
    return "";
  } else if (n > this.length) {
    return this;
  } else {
    return this.substring(this.length, this.length - n);
  }
};

(function ($) {
  var
    options = {
      highlightSpeed: 50,
      typeSpeed: 100,
      clearDelay: 500,
      typeDelay: 100,
      clearOnHighlight: true,
      typerDataAttr: 'data-typer-targets',
      typerInterval: 2000
    },
    highlight,
    clearText,
    backspace,
    type,
    spanWithColor,
    clearDelay,
    typeDelay,
    clearData,
    isNumber,
    typeWithAttribute,
    getHighlightInterval,
    getTypeInterval,
    typerInterval;

  spanWithColor = function(color, backgroundColor) {
    if (color === 'rgba(0, 0, 0, 0)') {
      color = 'rgb(0,0,100)';
    }

    return $('<span></span>')
      .css('color', color)
      .css('background-color', backgroundColor);
  };

  isNumber = function(n) {
    return !isNaN(parseFloat(n)) && isFinite(n);
  };

  clearData = function($e) {
    $e.removeData([
      'typePosition',
      'highlightPosition',
      'leftStop',
      'rightStop',
      'primaryColor',
      'backgroundColor',
      'text',
      'typing'
    ]);
  };

  type = function($e) {
    var
    // position = $e.data('typePosition'),
      text = $e.data('text'),
      oldLeft = $e.data('oldLeft'),
      oldRight = $e.data('oldRight');

    // if (!isNumber(position)) {
    // position = $e.data('leftStop');
    // }

    if (!text || text.length === 0) {
      clearData($e);
      return;
    }

    $e.text(
      oldLeft +
      text.charAt(0) +
      oldRight
    ).data({
      oldLeft: oldLeft + text.charAt(0),
      text: text.substring(1)
    });

    // $e.text($e.text() + text.substring(position, position + 1));

    // $e.data('typePosition', position + 1);

    setTimeout(function() {
      type($e);
    }, getTypeInterval());
  };

  clearText = function($e) {
    $e.find('span').remove();

    setTimeout(function() {
      type($e);
    }, typeDelay());
  };

  highlight = function($e) {
    var
      position = $e.data('highlightPosition'),
      leftText,
      highlightedText,
      rightText;

    if (!isNumber(position)) {
      position = $e.data('rightStop') + 1;
    }

    if (position <= $e.data('leftStop')) {
      setTimeout(function() {
        clearText($e);
      }, clearDelay());
      return;
    }

    leftText = $e.text().substring(0, position - 1);
    highlightedText = $e.text().substring(position - 1, $e.data('rightStop') + 1);
    rightText = $e.text().substring($e.data('rightStop') + 1);

    $e.html(leftText)
      .append(
        spanWithColor(
          $e.data('backgroundColor'),
          $e.data('primaryColor')
        )
        .append(highlightedText)
      )
      .append(rightText);

    $e.data('highlightPosition', position - 1);

    setTimeout(function() {
      return highlight($e);
    }, getHighlightInterval());
  };

  typeWithAttribute = function($e) {
    var targets;

    if ($e.data('typing')) {
      return;
    }

    try {
      targets = JSON.parse($e.attr($.typer.options.typerDataAttr)).targets;
    } catch (e) {}

    if (typeof targets === "undefined") {
      targets = $.map($e.attr($.typer.options.typerDataAttr).split(','), function(e) {
        return $.trim(e);
      });
    }

    $e.typeTo(targets[Math.floor(Math.random() * targets.length)]);
  };

  // Expose our options to the world.
  $.typer = (function() {
    return {
      options: options
    };
  })();

  $.extend($.typer, {
    options: options
  });

  //-- Methods to attach to jQuery sets

  $.fn.typer = function() {
    var $elements = $(this);

    return $elements.each(function() {
      var $e = $(this);

      if (typeof $e.attr($.typer.options.typerDataAttr) === "undefined") {
        return;
      }

      typeWithAttribute($e);
      setInterval(function() {
        typeWithAttribute($e);
      }, typerInterval());
    });
  };

  $.fn.typeTo = function(newString) {
    var
      $e = $(this),
      currentText = $e.text(),
      i = 0,
      j = 0;

    if (currentText === newString) {
      console.log("Our strings our equal, nothing to type");
      return $e;
    }

    if (currentText !== $e.html()) {
      console.error("Typer does not work on elements with child elements.");
      return $e;
    }

    $e.data('typing', true);

    while (currentText.charAt(i) === newString.charAt(i)) {
      i++;
    }

    while (currentText.rightChars(j) === newString.rightChars(j)) {
      j++;
    }

    newString = newString.substring(i, newString.length - j + 1);

    $e.data({
      oldLeft: currentText.substring(0, i),
      oldRight: currentText.rightChars(j - 1),
      leftStop: i,
      rightStop: currentText.length - j,
      primaryColor: $e.css('color'),
      backgroundColor: $e.css('background-color'),
      text: newString
    });

    highlight($e);

    return $e;
  };

  //-- Helper methods. These can one day be customized further to include things like ranges of delays.

  getHighlightInterval = function() {
    return $.typer.options.highlightSpeed;
  };

  getTypeInterval = function() {
      return $.typer.options.typeSpeed;
    },

    clearDelay = function() {
      return $.typer.options.clearDelay;
    },

    typeDelay = function() {
      return $.typer.options.typeDelay;
    };

  typerInterval = function() {
    return $.typer.options.typerInterval;
  };
})(jQuery);
