"use strict";

/**
 * Handles editing a reply to a comment in a review.
 *
 * This will handle the "New Comment" link and the draft banners for the
 * review.
 */
RB.ReviewRequestPage.ReviewReplyEditorView = Backbone.View.extend({
  commentTemplate: _.template(`<li <% if (isDraft) { %>class="draft"<% } %>
    <% if (commentID) { %>data-comment-id="<%= commentID %>"<% } %>>
 <% if (anchorName) { %>
  <a class="comment-anchor" name="<%- anchorName %>"></a>
  <div class="floating-anchor">
   <a href="#<%- anchorName %>"
      class="fa fa-link fa-flip-horizontal"></a>
  </div>
 <% } %>
 <div class="rb-c-discussion-header -has-avatar -is-compact">
  <div class="rb-c-discussion-header__avatar">
   <div class="avatar-container"><%= avatarHTML %></div>
  </div>
  <div class="rb-c-discussion-header__title">
   <div class="rb-c-user">
    <a class="user" href="<%= userPageURL %>"><%- fullName %></a>
   </div>
  </div>
  <div class="rb-c-discussion-header__timestamp">
   <% if (timestamp) { %>
    <span class="timestamp">
     <time class="timesince" datetime="<%= timestampISO %>"><%=
      timestamp %></time>
    </span>
   <% } %>
  </div>
 </div>
 <div>
  <pre id="<%= id %>" class="comment-text reviewtext"><%- text %></pre>
 </div>
</li>`),
  events: {
    'click .add_comment_link': '_onAddCommentClicked'
  },
  /**
   * Initialize the view.
   *
   * Args:
   *     options (object):
   *         Options for the view.
   *
   * Option Args:
   *     reviewRequestEditor (RB.ReviewRequestEditor):
   *         The editor model.
   */
  initialize(options) {
    this.options = options;
    this._$addCommentLink = null;
    this._$draftComment = null;
    this._$editor = null;
    this._$commentsList = null;
    this._inlineEditorView = null;
  },
  /**
   * Render the comment section.
   *
   * If there were any draft comments found, then editors will be
   * created for them, the New Comment link will be hidden.
   *
   * Returns:
   *     RB.ReviewRequestPage.ReviewReplyEditorView:
   *     This object, for chaining.
   */
  render() {
    this._$addCommentLink = this.$('.add_comment_link');
    this._$commentsList = this.$('.reply-comments');

    /* See if there's a draft comment to import from the page. */
    const $draftComment = this._$commentsList.children('.draft');
    if ($draftComment.length !== 0) {
      const $time = $draftComment.find('time');
      const $reviewText = $draftComment.find('.reviewtext');
      this.model.set({
        commentID: $draftComment.data('comment-id'),
        text: $reviewText.html(),
        timestamp: new Date($time.attr('datetime')),
        richText: $reviewText.hasClass('rich-text'),
        hasDraft: true
      });
      this._createCommentEditor($draftComment);
    }
    this.listenTo(this.model, 'textUpdated', () => {
      if (this._$editor) {
        const reviewRequest = this.model.get('review').get('parentObject');
        RB.formatText(this._$editor, {
          newText: this.model.get('text'),
          richText: this.model.get('richText'),
          bugTrackerURL: reviewRequest.get('bugTrackerURL')
        });
      }
    });
    this.model.on('resetState', () => {
      if (this._$draftComment) {
        this._$draftComment.fadeOut(() => {
          this._$draftComment.remove();
          this._$draftComment = null;
        });
      }
      this._$addCommentLink.fadeIn();
    });
    this.model.on('published', this._onPublished, this);
  },
  /**
   * Open the comment editor for a new comment.
   */
  openCommentEditor() {
    this._createCommentEditor(this._makeCommentElement());
    this._inlineEditorView.startEdit();
  },
  /**
   * Return whether this editor needs to be saved.
   *
   * Returns:
   *     boolean:
   *     Whether the comment editor has unsaved content.
   */
  needsSave() {
    return this._inlineEditorView && this._inlineEditorView.isDirty();
  },
  /**
   * Save the editor.
   *
   * Returns:
   *     Promise:
   *     A promise which resolves when the save is complete.
   */
  async save() {
    const value = this._inlineEditorView.submit({
      preventEvents: true
    });
    if (value) {
      const reviewRequestEditor = this.options.reviewRequestEditor;
      if (reviewRequestEditor) {
        reviewRequestEditor.decr('editCount');
      }
      this.model.set({
        richText: this._inlineEditorView.textEditor.richText,
        text: value
      });
      await this.model.save();
    }
  },
  /**
   * Create a comment editor for an element.
   *
   * Args:
   *     $draftComment (jQuery):
   *         The draft comment element.
   */
  _createCommentEditor($draftComment) {
    const reviewRequestEditor = this.options.reviewRequestEditor;
    this._$draftComment = $draftComment;
    this._$editor = $draftComment.find('pre.reviewtext');
    const inlineEditorView = new RB.RichTextInlineEditorView({
      editIconClass: 'rb-icon rb-icon-edit',
      el: this._$editor,
      formClass: 'inline-comment-editor',
      hasRawValue: true,
      multiline: true,
      notifyUnchangedCompletion: true,
      rawValue: this._$editor.data('raw-value') || '',
      textEditorOptions: {
        richText: this._$editor.hasClass('rich-text')
      }
    });
    inlineEditorView.render();
    this.listenTo(inlineEditorView, 'beginEdit', () => {
      if (reviewRequestEditor) {
        reviewRequestEditor.incr('editCount');
      }
    });
    this.listenTo(inlineEditorView, 'complete', value => {
      if (reviewRequestEditor) {
        reviewRequestEditor.decr('editCount');
      }
      this.model.set({
        richText: inlineEditorView.textEditor.richText,
        text: value
      });
      this.model.save();
    });
    this.listenTo(inlineEditorView, 'cancel', () => {
      if (reviewRequestEditor) {
        reviewRequestEditor.decr('editCount');
      }
      this.model.resetStateIfEmpty();
    });
    this._inlineEditorView = inlineEditorView;
    this._$editor.removeAttr('data-raw-value');
    this._$addCommentLink.hide();
  },
  /**
   * Create an element for the comment form.
   *
   * Args:
   *     options (object, optional):
   *         Options for the comment element.
   *
   * Option Args:
   *     now (Moment):
   *         The current time.
   *
   *     richText (boolean):
   *         Whether the text is in a rich-text format.
   *
   *     text (string):
   *         The text for the comment.
   *
   * Returns:
   *     jQuery:
   *     The newly-created element.
   */
  _makeCommentElement(options = {}) {
    const userSession = RB.UserSession.instance;
    const reviewRequest = this.model.get('review').get('parentObject');
    const now = options.now || moment().utcOffset(userSession.get('timezoneOffset'));
    const $el = $(this.commentTemplate(_.extend({
      anchorName: null,
      id: _.uniqueId('draft_comment_'),
      text: '',
      commentID: null,
      userPageURL: userSession.get('userPageURL'),
      fullName: userSession.get('fullName'),
      avatarHTML: userSession.getAvatarHTML(32),
      isDraft: true,
      timestampISO: now.format(),
      /*
       * Note that we format the a.m./p.m. this way to match
       * what's coming from the Django templates.
       */
      timestamp: now.format('MMMM Do, YYYY, h:mm ') + (now.hour() < 12 ? 'a.m.' : 'p.m.')
    }, options))).find('.user').user_infobox().end().find('time.timesince').timesince().end();
    if (options.text) {
      RB.formatText($el.find('.reviewtext'), {
        newText: options.text,
        richText: options.richText,
        bugTrackerURL: reviewRequest.get('bugTrackerURL')
      });
    }
    $el.appendTo(this._$commentsList);
    return $el;
  },
  /**
   * Handler for when the New Comment link is clicked.
   *
   * Creates a new comment form and editor.
   *
   * Args:
   *     e (Event):
   *         The event that triggered the callback.
   */
  _onAddCommentClicked(e) {
    e.preventDefault();
    e.stopPropagation();
    this.openCommentEditor();
  },
  /**
   * Handler for when the reply is published.
   *
   * Updates the draft comment to be a standard comment, and brings back
   * the New Comment link.
   */
  _onPublished() {
    if (this._$draftComment) {
      const model = this.model;
      const contextType = model.get('contextType');
      this._$draftComment.replaceWith(this._makeCommentElement({
        anchorName: model.get('anchorPrefix') + model.get('replyObject').id,
        commentID: model.get('commentID'),
        text: model.get('text'),
        richText: model.get('richText'),
        isDraft: false
      }));
      this._$draftComment = null;
    }
  }
});

//# sourceMappingURL=reviewReplyEditorView.js.map