/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

var loop = loop || {};
loop.shared = loop.shared || {};
loop.shared.views = loop.shared.views || {};
loop.shared.views.LinkifiedTextView = (function(mozL10n) {
  "use strict";

  /**
   * Given a rawText property, renderer a version of that text with any
   * links starting with http://, https://, or ftp:// as actual clickable
   * links inside a <p> container.
   */
  var LinkifiedTextView = React.createClass({
    propTypes: {
      // Call this instead of allowing the default <a> click semantics, if
      // given.  Also causes sendReferrer and suppressTarget attributes to be
      // ignored.
      linkClickHandler: React.PropTypes.func,
      // The text to be linkified.
      rawText: React.PropTypes.string.isRequired,
      // Should the links send a referrer?  Defaults to false.
      sendReferrer: React.PropTypes.bool,
      // Should we suppress target="_blank" on the link? Defaults to false.
      // Mostly for testing use.
      suppressTarget: React.PropTypes.bool
    },

    mixins: [
      React.addons.PureRenderMixin
    ],

    _handleClickEvent: function(e) {
      e.preventDefault();
      e.stopPropagation();

      this.props.linkClickHandler(e.currentTarget.href);
    },

    _generateLinkAttributes: function(href) {
      var linkAttributes = {
        href: href
      };

      if (this.props.linkClickHandler) {
        linkAttributes.onClick = this._handleClickEvent;

        // if this is specified, we short-circuit return to avoid unnecessarily
        // creating target and rel attributes.
        return linkAttributes;
      }

      if (!this.props.suppressTarget) {
        linkAttributes.target = "_blank";
      }

      if (!this.props.sendReferrer) {
        linkAttributes.rel = "noreferrer";
      }

      return linkAttributes;
    },

    /**                                                              a
     * Parse the given string into an array of strings and React <a> elements
     * in the order in which they should be rendered (i.e. FIFO).
     *
     * @param {String} s the raw string to be parsed
     *
     * @returns {Array} of strings and React <a> elements in order.
     */
    parseStringToElements: function(s) {
      var elements = [];
      var result = loop.shared.urlRegExps.fullUrlMatch.exec(s);
      var reactElementsCounter = 0; // For giving keys to each ReactElement.

      while (result) {
        // If there's text preceding the first link, push it onto the array
        // and update the string pointer.
        if (result.index) {
          elements.push(s.substr(0, result.index));
          s = s.substr(result.index);
        }

        // Push the first link itself, and advance the string pointer again.
        elements.push(
          <a { ...this._generateLinkAttributes(result[0]) }
            key={reactElementsCounter++}>
            {result[0]}
          </a>
        );
        s = s.substr(result[0].length);

        // Check for another link, and perhaps continue...
        result = loop.shared.urlRegExps.fullUrlMatch.exec(s);
      }

      if (s) {
        elements.push(s);
      }

      return elements;
    },

    render: function () {
      return ( <p>{ this.parseStringToElements(this.props.rawText) }</p> );
    }
  });

  return LinkifiedTextView;

})(navigator.mozL10n || document.mozL10n);
