$(function() {
  // ruby part adds the relative_url_root, if it is set.
  var ACE_FILES_PATH = '<%= (defined?  Rails.application.config.relative_url_root) &&  Rails.application.config.relative_url_root != nil &&  Rails.application.config.relative_url_root != "" ?  Rails.application.config.relative_url_root : "" %>' + '/assets/ace/';
  var THEME = 'ace/theme/textmate';

  var TAB_KEY_CODE = 9;

  var execution_environments;
  var file_types;



  var configureEditors = function() {
    _.each(['modePath', 'themePath', 'workerPath'], function(attribute) {
      ace.config.set(attribute, ACE_FILES_PATH);
    });
  };

  var initializeEditor = function(index, element) {
    var editor = ace.edit(element);

    var document = editor.getSession().getDocument();
    // insert pre-existing code into editor. we have to use insertLines, otherwise the deltas are not properly added
    var file_id = $(element).data('file-id');
    var content = $('.editor-content[data-file-id=' + file_id + ']');

    document.insertLines(0, content.text().split(/\n/));
    // remove last (empty) that is there by default line
    document.removeLines(document.getLength() - 1, document.getLength() - 1);
    editor.setReadOnly($(element).data('read-only') !== undefined);
    editor.setShowPrintMargin(false);
    editor.setTheme(THEME);

    var textarea = $('textarea[id="exercise_files_attributes_'+index+'_content"]');
    var content = textarea.val();

    if (content != undefined)
    {
      editor.getSession().setValue(content);
      editor.getSession().on('change', function(){
        textarea.val(editor.getSession().getValue());
      });
    }

    editor.commands.bindKey("ctrl+alt+0", null);
    var session = editor.getSession();
    session.setMode($(element).data('mode'));
    session.setTabSize($(element).data('indent-size'));
    session.setUseSoftTabs(true);
    session.setUseWrapMode(true);
  }

  var initializeEditors = function() {
    // initialize ace editors for all code textareas in the dom except the last one. The last one is the dummy area for new files, which is cloned when needed.
    // this one must NOT! be initialized.
    $('.editor:not(:last)').each(initializeEditor)
  };

  var addFileForm = function(event) {
    event.preventDefault();
    var element = $('#dummies').children().first().clone();

    // the timestamp is used here, since it is most probably unique. This is strange, but was originally designed that way.
    var latestTextAreaIndex = new Date().getTime();
    var html = $('<div>').append(element).html().replace(/index/g, latestTextAreaIndex);
    $('#files').append(html);
    $('#files li:last select[name*="file_type_id"]').val(getSelectedExecutionEnvironment().file_type_id);
    $('#files li:last select').chosen(window.CodeOcean.CHOSEN_OPTIONS);
    $('body, html').scrollTo('#add-file');
    // if we collapse the file forms by default, we need to click on the new element in order to open it.
    // however, this crashes for more files (if we add several ones by clicking the add button more often), since the elements are probably not correctly added to the files list.
    //$('#files li:last>div:first>a>div').click();

    // initialize the ace editor for the new textarea.
    // pass the correct index and the last ace editor under the node files. this is the last one, since we just added it.
    initializeEditor(latestTextAreaIndex, $('#files .editor').last()[0]);
  };

  var ajaxError = function() {
    $.flash.danger({
      text: $('#flash').data('message-failure')
    });
  };

  var buildCheckboxes = function() {
    $('tbody tr').each(function(index, element) {
      var td = $('td.public', element);
      var checkbox = $('<input>', {
        checked: td.data('value'),
        type: 'checkbox'
      });
      td.on('click', function(event) {
        event.preventDefault();
        checkbox.prop('checked', !checkbox.prop('checked'));
      });
      td.html(checkbox);
    });
  };

  var discardFile = function(event) {
    event.preventDefault();
    $(this).parents('li').remove();
  };

  var enableBatchUpdate = function() {
    $('thead .batch a').on('click', function(event) {
      event.preventDefault();
      if (!$(this).data('toggled')) {
        $(this).data('toggled', true);
        $(this).text($(this).data('text'));
        buildCheckboxes();
      } else {
        performBatchUpdate();
      }
    });
  };

  var enableInlineFileCreation = function() {
    $('#add-file').on('click', addFileForm);
    $('#files').on('click', 'li .discard-file', discardFile);
    $('form.edit_exercise, form.new_exercise').on('submit', function() {
      $('#dummies').html('');
    });
  };

  var findFileTypeByFileExtension = function(file_extension) {
    return _.find(file_types, function(file_type) {
      return file_type.file_extension === file_extension;
    }) || {};
  };

  var getSelectedExecutionEnvironment = function() {
    return _.find(execution_environments, function(execution_environment) {
      return execution_environment.id === parseInt($('#exercise_execution_environment_id').val());
    }) || {};
  };

  var highlightCode = function() {
    $('pre code').each(function(index, element) {
      hljs.highlightBlock(element);
    });
  };

  var inferFileAttributes = function() {
    $(document).on('change', 'input[type="file"]', function() {
      var filename = $(this).val().split(/\\|\//g).pop();
      var file_extension = '.' + filename.split('.')[1];
      var file_type = findFileTypeByFileExtension(file_extension);
      var name = filename.split('.')[0];
      var parent = $(this).parents('li');
      parent.find('input[name*="name"]').val(name);
      parent.find('select[name*="file_type_id"]').val(file_type.id).trigger('chosen:updated');
    });
  };

  var insertTabAtCursor = function(textarea) {
    var selection_start = textarea.get(0).selectionStart;
    var selection_end = textarea.get(0).selectionEnd;
    textarea.val(textarea.val().substring(0, selection_start) + "\t" + textarea.val().substring(selection_end));
    textarea.get(0).selectionStart = selection_start + 1;
    textarea.get(0).selectionEnd = selection_start + 1;
  };

  var observeFileRoleChanges = function() {
    $(document).on('change', 'select[name$="[role]"]', function() {
      var is_test_file = $(this).val() === 'teacher_defined_test';
      var parent = $(this).parents('.panel');
      var fields = parent.find('.test-related-fields');
      if (is_test_file) {
        fields.slideDown();
      } else {
        fields.slideUp();
        parent.find('[name$="[feedback_message]"]').val('');
        parent.find('[name$="[weight]"]').val(1);
      }
    });
  };

  var overrideTextareaTabBehavior = function() {
    $('.form-group textarea[name$="[content]"]').on('keydown', function(event) {
      if (event.which === TAB_KEY_CODE) {
        event.preventDefault();
        insertTabAtCursor($(this));
      }
    });
  };

  var performBatchUpdate = function() {
    var jqxhr = $.ajax({
      data: {
        exercises: _.map($('tbody tr'), function(element) {
          return {
            id: $(element).data('id'),
            public: $('.public input', element).prop('checked')
          };
        })
      },
      dataType: 'json',
      method: 'PUT'
    });
    jqxhr.done(window.CodeOcean.refresh);
    jqxhr.fail(ajaxError);
  };

  var toggleCodeHeight = function() {
    $('code').on('click', function() {
      $(this).css({
        'max-height': 'initial'
      });
    });
  };

  var updateFileTemplates = function(fileType) {
      var rel_url_root = '<%= (defined?  Rails.application.config.relative_url_root) &&  Rails.application.config.relative_url_root != nil &&  Rails.application.config.relative_url_root != "" ?  Rails.application.config.relative_url_root : "" %>';
      var jqxhr = $.ajax({
          url:  rel_url_root + '/file_templates/by_file_type/' + fileType + '.json',
          dataType: 'json'
      });
      jqxhr.done(function(response) {
          var noTemplateLabel = $('#noTemplateLabel').data('text');
          var options = "<option value>" + noTemplateLabel + "</option>";
          for (var i = 0; i < response.length; i++) {
              options += "<option value='" + response[i].id + "'>" + response[i].name + "</option>"
          }
          $("#code_ocean_file_file_template_id").find('option').remove().end().append($(options));
      });
      jqxhr.fail(ajaxError);
  }

  if ($.isController('exercises')) {
      // ignore tags table since it is in the dom before other tables
    if ($('table:not(#tags-table)').isPresent()) {
      enableBatchUpdate();
    } else if ($('.edit_exercise, .new_exercise').isPresent()) {
      execution_environments = $('form').data('execution-environments');
      file_types = $('form').data('file-types');
      // new MarkdownEditor('#exercise_instructions');
      // new MarkdownEditor('#exercise_description')
      // todo: add an ace editor for each file
      new PagedownEditor('#exercise_description');

      enableInlineFileCreation();
      inferFileAttributes();
      observeFileRoleChanges();
      overrideTextareaTabBehavior();
    } else if ($('#files.jstree').isPresent()) {
        var fileTypeSelect = $('#code_ocean_file_file_type_id');
        fileTypeSelect.on("change", function() {updateFileTemplates(fileTypeSelect.val())});
        updateFileTemplates(fileTypeSelect.val());
    }
    toggleCodeHeight();
    if (window.hljs) {
      highlightCode();
    }
  }


  if ($('#editor-edit').isPresent()) {
    configureEditors();
    initializeEditors();
    $('.frame').show();
  }


});
