<div class="list-group">
  <h4 id ="exercise_caption" class="list-group-item-heading" data-exercise-id="<%=@request_for_comment.exercise.id%>" data-comment-exercise-url="<%=create_comment_exercise_request_for_comment_path%>" data-rfc-id = "<%= @request_for_comment.id %>" >
    <% if @request_for_comment.solved? %>
        <span class="fa fa-check" aria-hidden="true"></span>
    <% end %>
    <%= link_to(@request_for_comment.exercise.title, [:implement, @request_for_comment.exercise]) %>
  </h4>
  <p class="list-group-item-text">
      <%
        user = @request_for_comment.user
        submission =  @request_for_comment.submission
        testruns = Testrun.where(:submission_id => @request_for_comment.submission)
      %>
    <%= user.displayname %> | <%= @request_for_comment.created_at.localtime %>
  </p>
  <div class="rfc">
    <div class="description">
      <h5>
        <%= t('activerecord.attributes.exercise.description') %>
      </h5>
      <div class="text">
        <span class="fa fa-chevron-up collapse-button"></span>
        <%= render_markdown(@request_for_comment.exercise.description) %>
      </div>
    </div>

    <div class="question">
      <h5>
        <%= t('activerecord.attributes.request_for_comments.question')%>
      </h5>
      <div class="text">
        <% question = @request_for_comment.question %>
        <%= question.nil? or question.empty? ? t('request_for_comments.no_question') : question %>
      </div>
    </div>

    <% if policy(@request_for_comment).mark_as_solved? and not @request_for_comment.solved? %>
        <%= render('mark_as_solved') %>
    <% end %>
    
    <% if testruns.size > 0 %>
      <div class="testruns">
        <% output_runs = testruns.select { |run| run.cause == 'run' } %>
        <% if output_runs.size > 0 %>
          <h5><%= t('request_for_comments.runtime_output') %></h5>
          <div class="collapsed testrun-output text">
            <span class="fa fa-chevron-down collapse-button"></span>
            <% output_runs.each do |testrun| %>
              <%
                output = testrun.try(:output)
                if output
                  messages = output.scan(/{(?:(?:".+?":".+?")+?,?)+}/)
                  messages.map! {|el| JSON.parse(el)}
                  messages.keep_if {|message| message['cmd'] == 'write'}
                  messages.map! {|message| message['data']}
                  output = messages.join ''
                end
              %>
              <pre><%= output or t('request_for_comments.no_output') %></pre>
            <% end %>
          </div>
        <% end %>

        <% assess_runs = testruns.select { |run| run.cause == 'assess' } %>
        <% if assess_runs.size > 0 %>
          <h5><%= t('request_for_comments.test_results') %></h5>
          <div class="testrun-assess-results">
            <% assess_runs.each do |testrun| %>
              <div class="testrun-container">
                <div class="result <%= testrun.passed ? 'passed' : 'failed' %>"></div>
                <div class="collapsed testrun-output text">
                  <span class="fa fa-chevron-down collapse-button"></span>
                  <pre><%= testrun.output or t('request_for_comments.no_output')%></pre>
                </div>
              </div>
            <% end %>
          </div>
        <% end %>
      </div>
    <% end %>

    <% if @current_user.admin? && user.is_a?(ExternalUser) %>
        <%= render('admin_menu') %>
    <% end %>

    <hr>

    <div class="howto">
      <h5>
        <%= t('request_for_comments.howto_title') %>
      </h5>
      <div class="text">
        <%= render_markdown(t('request_for_comments.howto')) %>
      </div>
    </div>
  </div>
</div>

<div class="hidden sanitizer"></div>
<!--
do not put a carriage return in the line below. it will be present in the presentation of the source code, otherwise.
also, all settings from the rails model needed for the editor configuration in the JavaScript are attached to the editor as data attributes here.
-->
<% submission.files.each do |file| %>
  <%= (file.path or "") + "/" + file.name +  file.file_type.file_extension %><br>
  &nbsp;&nbsp;<i class="fa fa-arrow-down" aria-hidden="true"></i> <%= t('request_for_comments.click_here') %>
  <div id='commentitor' class='editor' data-read-only='true' data-file-id='<%=file.id%>' data-mode='<%=file.file_type.editor_mode%>'><%= file.content %>
  </div>
<% end %>

<%= render('shared/modal', id: 'comment-modal', title: t('exercises.implement.comment.dialogtitle'), template: 'exercises/_comment_dialogcontent') %>

<script type="text/javascript">

  $('.modal-content').draggable({
    handle: '.modal-header'
  }).resizable({
    autoHide: true
  });

  var solvedButton = $('#mark-as-solved-button');
  var addCommentExerciseButton = $('#addCommentExerciseButton');

  var thankYouContainer = $('#thank-you-container');

  solvedButton.on('click', function(){
    $.ajax({
      dataType: 'json',
      method: 'GET',
      url: location + '/mark_as_solved'
    }).done(function(response){
      if(response.solved){
        solvedButton.removeClass('btn-primary');
        solvedButton.addClass('btn-success');
        solvedButton.html('<%= t('request_for_comments.solved') %>');
        solvedButton.off('click');
        thankYouContainer.show();
      }
    });
  });

  $('#send-thank-you-note').on('click', function () {
    var value = $('#thank-you-note').val();
    if (value) {
      $.ajax({
        dataType: 'json',
        method: 'POST',
        url: location + '/set_thank_you_note',
        data: {
            note: value
        }
      }).done(function() {
        thankYouContainer.hide();
      });
    }
  });

  $('#cancel-thank-you-note').on('click', function () {
    thankYouContainer.hide();
  });

  $('.text > .collapse-button').on('click', function(e) {
    $(this).toggleClass('fa-chevron-down');
    $(this).toggleClass('fa-chevron-up');
    $(this).parent().toggleClass('collapsed');
  });

  // set file paths for ace
  var ACE_FILES_PATH = '/assets/ace/';
  _.each(['modePath', 'themePath', 'workerPath'], function(attribute) {
    ace.config.set(attribute, ACE_FILES_PATH);
  });

  var commentitor = $('.editor');

  commentitor.each(function (index, editor) {
    var currentEditor = ace.edit(editor);
    currentEditor.setReadOnly(true);
    // set editor mode (used for syntax highlighting
    currentEditor.getSession().setMode($(editor).data('mode'));
    currentEditor.getSession().setOption("useWorker", false);

    currentEditor.commentVisualsByLine = {};
    setAnnotations(currentEditor, $(editor).data('file-id'));
    currentEditor.on("guttermousedown", handleSidebarClick);
    currentEditor.on("guttermousemove", showPopover);
  });

  function preprocess(commentText) {
    // sanitize comments to deal with XSS attacks:
    commentText = $('div.sanitizer').text(commentText).html();
    // display original line breaks:
    return commentText.replace(/\n/g, '<br>');
  }

  function generateCommentHtmlContent(comments) {
    var htmlContent = '';
    comments.forEach(function(comment, index) {
      var commentText = preprocess(comment.text);
      if (index !== 0) {
        htmlContent += '<div class="comment-divider"></div>'
      }
      htmlContent += '\
        <div class="comment" data-comment-id=' + comment.id + '> \
          <div class="comment-header"> \
            <div class="comment-username">' + preprocess(comment.username) + '</div> \
            <div class="comment-date">' + comment.date + '</div> \
            <div class="comment-updated' + (comment.updated ? '' : ' hidden') + '"> \
              <i class="fa fa-pencil" aria-hidden="true"></i> \
              <%= t('request_for_comments.comment_edited') %> \
            </div> \
          </div> \
          <div class="comment-content">' + commentText + '</div> \
          <textarea class="comment-editor">' + commentText + '</textarea> \
          <div class="comment-actions' + (comment.editable ? '' : ' hidden') + '"> \
            <button class="action-edit btn btn-xs btn-warning"><%= t('shared.edit') %></button> \
            <button class="action-delete btn btn-xs btn-danger"><%= t('shared.destroy') %></button> \
          </div> \
        </div>';
    });
    return htmlContent;
  }

  function buildPopover(comments, where) {
    // only display the newest three comments in preview
    var maxComments = 3;
    var htmlContent = generateCommentHtmlContent(comments.reverse().slice(0, maxComments));
    if (comments.length > maxComments) {
      // add a hint that there are more comments than shown here
      htmlContent += '<div class="popover-footer"><%= t('request_for_comments.click_for_more_comments') %></div>'
        .replace('${numComments}', String(comments.length - maxComments));
    }
    where.popover({
      content: htmlContent,
      html: true, // necessary to style comments. XSS is not possible due to comment pre-processing (sanitizing)
      trigger: 'manual', // can only be triggered by $(where).popover('show' | 'hide')
      container: 'body'
    });
  }

  function setAnnotations(editor, fileid) {
    var session = editor.getSession();

    var jqrequest = $.ajax({
      dataType: 'json',
      method: 'GET',
      url: '/comments',
      data: {
        file_id: fileid
      }
    });

    jqrequest.done(function(response){
      $.each(response, function(index, comment) {
        comment.className = 'code-ocean_comment';
      });
      session.setAnnotations(response);
    });
  }

  function getCommentsForRow(editor, row){
    return editor.getSession().getAnnotations().filter(function(element) {
      return element.row === row;
    })
  }

  function deleteComment(commentId, editor, file_id, callback) {
    var jqxhr = $.ajax({
      type: 'DELETE',
      url: "/comments/" + commentId
    });
    jqxhr.done(function () {
      setAnnotations(editor, file_id);
      callback();
    });
    jqxhr.fail(ajaxError);
  }

  function updateComment(commentId, text, editor, file_id, callback) {
    var jqxhr = $.ajax({
      type: 'PATCH',
      url: "/comments/" + commentId,
      data: {
        comment: {
          text: text
        }
      }
    });
    jqxhr.done(function () {
      setAnnotations(editor, file_id);
      callback();
    });
    jqxhr.fail(ajaxError);
  }

  function createComment(file_id, row, editor, commenttext){
    var jqxhr = $.ajax({
      data: {
        comment: {
          file_id: file_id,
          row: row,
          column: 0,
          text: commenttext,
          request_id: $('h4#exercise_caption').data('rfc-id')
        }
      },
      dataType: 'json',
      method: 'POST',
      url:  "/comments"
    });
    jqxhr.done(function(){
      setAnnotations(editor, file_id);
    });
    jqxhr.fail(ajaxError);
  }

  function subscribeToRFC(subscriptionType, checkbox){
    checkbox.attr("disabled", true);
    var jqxhr = $.ajax({
      data: {
        subscription: {
          request_for_comment_id: $('h4#exercise_caption').data('rfc-id'),
          subscription_type: subscriptionType
        }
      },
      dataType: 'json',
      method: 'POST',
      url:  "/subscriptions.json"
    });
    jqxhr.done(function(subscription) {
      checkbox.data('subscription', subscription.id);
      checkbox.attr("disabled", false);
    });
    jqxhr.fail(function(response) {
      checkbox.prop('checked', false);
      checkbox.attr("disabled", false);
      ajaxError(response);
    });
  }

  function unsubscribeFromRFC(checkbox) {
    checkbox.attr("disabled", true);
    var subscriptionId = checkbox.data('subscription');
    var jqxhr = $.ajax({
      url:  '/subscriptions/' + subscriptionId + '/unsubscribe.json'
    });
    jqxhr.done(function(response) {
      checkbox.prop('checked', false);
      checkbox.data('subscription', null);
      checkbox.attr("disabled", false);
      $.flash.success({text: response.message});
    });
    jqxhr.fail(function(response) {
      checkbox.prop('checked', true);
      checkbox.attr("disabled", false);
      ajaxError(response);
    });
  }

  var lastRow = null;
  var lastTarget = null;
  function showPopover(e) {
    var target  = e.domEvent.target;
    var row = e.getDocumentPosition().row;

    if (target.className.indexOf('ace_gutter-cell') === -1 || lastRow === row) {
      return;
    }
    if (lastTarget === target) {
      // sometimes the row gets updated before the DOM event target, so we need to wait for it to change
      return;
    }
    lastRow = row;

    var editor = e.editor;
    var comments = getCommentsForRow(editor, row);
    buildPopover(comments, $(target));
    lastTarget = target;

    $(target).popover('show');
    $(target).on('mouseleave', function () {
      $(this).off('mouseleave');
      $(this).popover('destroy');
    });
  }

  $('.ace_gutter').on('mouseleave', function () {
    lastRow = null;
    lastTarget = null;
  });

  function handleSidebarClick(e) {
    var target  = e.domEvent.target;
    if (target.className.indexOf('ace_gutter-cell') === -1) return;

    var editor =  e.editor;
    var fileid = $(editor.container).data('file-id');

    var row = e.getDocumentPosition().row;
    e.stop();
    $('.modal-title').text('<%= t('request_for_comments.modal_title') %>'.replace('${line}', row + 1));

    var commentModal = $('#comment-modal');

    var otherComments = commentModal.find('#otherComments');
    var htmlContent = generateCommentHtmlContent(getCommentsForRow(editor, row));
    if (htmlContent) {
      otherComments.show();
      var container = otherComments.find('.container');
      container.html(htmlContent);

      var deleteButtons = container.find('.action-delete');
      deleteButtons.on('click', function (event) {
        var button = $(event.target);
        var parent = $(button).parent().parent();
        var commentId = parent.data('comment-id');

        deleteComment(commentId, editor, fileid, function () {
          parent.html('<div class="comment-removed"><%= t('comments.deleted') %></div>');
        });
      });

      var editButtons = container.find('.action-edit');
      editButtons.on('click', function (event) {
        var button = $(event.target);
        var parent = $(button).parent().parent();
        var commentId = parent.data('comment-id');
        var currentlyEditing = button.data('editing');

        var deleteButton = parent.find('.action-delete');
        var commentContent = parent.find('.comment-content');
        var commentEditor = parent.find('textarea.comment-editor');
        var commentUpdated = parent.find('.comment-updated');

        if (currentlyEditing) {
          updateComment(commentId, commentEditor.val(), editor, fileid, function () {
            button.text('<%= t('shared.edit') %>');
            button.data('editing', false);
            commentContent.text(commentEditor.val());
            deleteButton.show();
            commentContent.show();
            commentEditor.hide();
            commentUpdated.removeClass('hidden');
          });
        } else {
          button.text('<%= t('comments.save_update') %>');
          button.data('editing', true);
          deleteButton.hide();
          commentContent.hide();
          commentEditor.show();
        }
      });
    } else {
      otherComments.hide();
    }

    var subscribeCheckbox = commentModal.find('#subscribe');
    subscribeCheckbox.prop('checked', subscribeCheckbox.data('subscription'));
    subscribeCheckbox.off('change');
    subscribeCheckbox.on('change', function() {
      if (this.checked) {
        subscribeToRFC('author', $(this));
      } else {
        unsubscribeFromRFC($(this));
      }
    });

    var addCommentButton = commentModal.find('#addCommentButton');
    addCommentButton.off('click');
    addCommentButton.on('click', function(){
      var commentTextarea = commentModal.find('#myComment > textarea');
      var commenttext = commentTextarea.val();
      if (commenttext !== "") {
        createComment(fileid, row, editor, commenttext);
        commentTextarea.val('') ;
        commentModal.modal('hide');
      }
    });

    commentModal.modal('show');
  }

  function ajaxError(response) {
    var message = ((response || {}).responseJSON || {}).message || '';

    $.flash.danger({
      text: message.length > 0 ? message : $('#flash').data('message-failure')
    });
  }

</script>
