let Submission = Backbone.Model.extend({
  idAttribute: "student",
  urlRoot: base_url + "/formgrader/api/submission/" + assignment_id,
});

let Submissions = Backbone.Collection.extend({
  model: Submission,
  url: base_url + "/formgrader/api/submissions/" + assignment_id,
});

let SubmissionUI = Backbone.View.extend({
  events: {},

  initialize: function () {
    this.$student_name = this.$el.find(".student-name");
    this.$student_id = this.$el.find(".student-id");
    this.$timestamp = this.$el.find(".timestamp");
    this.$status = this.$el.find(".status");
    this.$score = this.$el.find(".score");
    this.$autograde = this.$el.find(".autograde");
    this.$generate_feedback = this.$el.find(".generate-feedback");
    this.$release_feedback = this.$el.find(".release-feedback");

    this.listenTo(this.model, "sync", this.render);

    this.render();
  },

  clear: function () {
    this.$student_name.empty();
    this.$student_id.empty();
    this.$timestamp.empty();
    this.$status.empty();
    this.$score.empty();
    this.$autograde.empty();
    this.$generate_feedback.empty();
    this.$release_feedback.empty();
  },

  render: function () {
    this.clear();

    let student = this.model.get("student");
    let assignment = this.model.get("name");

    // student name
    let last_name = this.model.get("last_name");
    let first_name = this.model.get("first_name");
    if (last_name === null) last_name = "None";
    if (first_name === null) first_name = "None";
    let name = last_name + ", " + first_name;
    this.$student_name.attr("data-order", name);
    if (this.model.get("autograded")) {
      this.$student_name.append(
        $("<a/>")
          .attr(
            "href",
            base_url +
              "/formgrader/manage_students/" +
              student +
              "/" +
              assignment
          )
          .text(name)
      );
    } else {
      this.$student_name.text(name);
    }

    // student id
    this.$student_id.attr("data-order", student);
    this.$student_id.text(student);

    // timestamp
    let timestamp = this.model.get("timestamp");
    let display_timestamp = this.model.get("display_timestamp");
    if (timestamp === null) {
      timestamp = "None";
      display_timestamp = "None";
    }
    this.$timestamp.attr("data-order", timestamp);
    this.$timestamp.text(display_timestamp);

    // status
    if (!this.model.get("autograded")) {
      this.$status.attr("data-order", 0);
      this.$status.append(
        $("<span/>").addClass("label label-warning").text("needs autograding")
      );
    } else if (this.model.get("needs_manual_grade")) {
      this.$status.attr("data-order", 1);
      this.$status.append(
        $("<span/>").addClass("label label-info").text("needs manual grading")
      );
    } else {
      this.$status.attr("data-order", 2);
      this.$status.append(
        $("<span/>").addClass("label label-success").text("graded")
      );
    }

    // score
    if (this.model.get("autograded")) {
      let score = roundToPrecision(this.model.get("score"), 2);
      let max_score = roundToPrecision(this.model.get("max_score"), 2);
      if (max_score === 0) {
        this.$score.attr("data-order", 0.0);
      } else {
        this.$score.attr("data-order", score / max_score);
      }
      this.$score.text(score + " / " + max_score);
    } else {
      this.$score.attr("data-order", 0.0);
    }

    // autograde
    this.$autograde.append(
      $("<a/>")
        .attr("href", "#")
        .on("click", _.bind(this.autograde, this))
        .append(
          $("<span/>")
            .addClass("glyphicon glyphicon-flash")
            .attr("aria-hidden", "true")
        )
    );

    // generate feedback
    this.$generate_feedback.append(
      $("<a/>")
        .attr("href", "#")
        .on("click", _.bind(this.generate_feedback, this))
        .append(
          $("<span/>")
            .addClass("glyphicon glyphicon-comment")
            .attr("aria-hidden", "true")
        )
    );

    // release feedback
    this.$release_feedback.append(
      $("<a/>")
        .attr("href", "#")
        .on("click", _.bind(this.release_feedback, this))
        .append(
          $("<span/>")
            .addClass("glyphicon glyphicon-envelope")
            .attr("aria-hidden", "true")
        )
    );
  },

  autograde: function () {
    this.clear();
    this.$student_name.text("Please wait...");
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    $.post(
      base_url +
        "/formgrader/api/submission/" +
        assignment +
        "/" +
        student +
        "/autograde"
    )
      .done(_.bind(this.autograde_success, this))
      .fail(_.bind(this.autograde_failure, this));
  },

  autograde_success: function (response) {
    this.model.fetch();
    response = JSON.parse(response);
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    if (response["success"]) {
      createLogModal(
        "success-modal",
        "Success",
        "Successfully autograded '" +
          assignment +
          "' for student '" +
          student +
          "'.",
        response["log"]
      );
    } else {
      createLogModal(
        "error-modal",
        "Error",
        "There was an error autograding '" +
          assignment +
          "' for student '" +
          student +
          "':",
        response["log"],
        response["error"]
      );
    }
  },

  autograde_failure: function (response) {
    this.model.fetch();
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    createModal(
      "error-modal",
      "Error",
      "There was an error autograding '" +
        assignment +
        "' for student '" +
        student +
        "'."
    );
  },

  generate_feedback: function () {
    let select =
      '<form id="feedback_form"><strong>Please select the version of feedback to be generated.</strong><br><br>\
        <input type="radio" name="feedback_radio" id="show_cells" checked="checked"> <label for="show_cells">Show autograded cells</label><br>\
        <input type="radio" name="feedback_radio" id="hide_cells"> <label for="hide_cells">Hide autograded cells</label></form>';

    let container_start = "<div>";
    let container_end = "</div></div>";
    let body = $(container_start + select + container_end);

    let footer = $("<div/>");
    footer.append(
      $("<button/>")
        .addClass("btn btn-primary feedback")
        .attr("type", "button")
        .text("Select")
    );
    footer.append(
      $("<button/>")
        .addClass("btn btn-danger")
        .attr("type", "button")
        .attr("data-dismiss", "modal")
        .text("Cancel")
    );

    this.$modal = createModal(
      "generate-feedback-modal",
      "Generate feedback: " + this.model.get("name"),
      body,
      footer
    );
    this.$modal_select = this.$modal.find("button.feedback");
    this.$modal_select.click(_.bind(this.feedback, this));
  },

  feedback: function () {
    $("#generate-feedback-modal").modal("hide");
    this.clear();
    this.$student_name.text("Please wait...");
    let url =
      base_url +
      "/formgrader/api/assignment/" +
      this.model.get("name") +
      "/" +
      this.model.get("student") +
      "/generate_feedback";
    $.post(
      url +
        "?" +
        new URLSearchParams({
          hide_cells: document.getElementById("hide_cells").checked,
        })
    )
      .done(_.bind(this.generate_feedback_success, this))
      .fail(_.bind(this.generate_feedback_failure, this));
  },

  generate_feedback_success: function (response) {
    this.model.fetch();
    response = JSON.parse(response);
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    if (response["success"]) {
      createLogModal(
        "success-modal",
        "Success",
        "Successfully generated feedback for '" +
          assignment +
          "' for student '" +
          student +
          "'.",
        response["log"]
      );
    } else {
      createLogModal(
        "error-modal",
        "Error",
        "There was an error generating feedback for '" +
          assignment +
          "' for student '" +
          student +
          "':",
        response["log"],
        response["error"]
      );
    }
  },

  generate_feedback_failure: function (response) {
    this.model.fetch();
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    createModal(
      "error-modal",
      "Error",
      "There was an error generating feedback for '" +
        assignment +
        "' for student '" +
        student +
        "'."
    );
  },

  release_feedback: function () {
    this.clear();
    this.$student_name.text("Please wait...");
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    $.post(
      base_url +
        "/formgrader/api/assignment/" +
        assignment +
        "/" +
        student +
        "/release_feedback"
    )
      .done(_.bind(this.release_feedback_success, this))
      .fail(_.bind(this.release_feedback_failure, this));
  },

  release_feedback_success: function (response) {
    this.model.fetch();
    response = JSON.parse(response);
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    if (response["success"]) {
      createLogModal(
        "success-modal",
        "Success",
        "Successfully released feedback for '" +
          assignment +
          "' for student '" +
          student +
          "'.",
        response["log"]
      );
    } else {
      createLogModal(
        "error-modal",
        "Error",
        "There was an error releasing feedback for '" +
          assignment +
          "' for student '" +
          student +
          "':",
        response["log"],
        response["error"]
      );
    }
  },

  release_feedback_failure: function (response) {
    this.model.fetch();
    let student = this.model.get("student");
    let assignment = this.model.get("name");
    createModal(
      "error-modal",
      "Error",
      "There was an error releasing feedback for '" +
        assignment +
        "' for student '" +
        student +
        "'."
    );
  },
});

let insertRow = function (table) {
  let row = $("<tr/>");
  row.append($("<td/>").addClass("student-name"));
  row.append($("<td/>").addClass("text-center student-id"));
  row.append($("<td/>").addClass("text-center timestamp"));
  row.append($("<td/>").addClass("text-center status"));
  row.append($("<td/>").addClass("text-center score"));
  row.append($("<td/>").addClass("text-center autograde"));
  row.append($("<td/>").addClass("text-center generate-feedback"));
  row.append($("<td/>").addClass("text-center release-feedback"));
  table.append(row);
  return row;
};

let loadSubmissions = function () {
  let tbl = $("#main-table");

  const models = new Submissions();
  models.loaded = false;
  models.fetch({
    success: function () {
      tbl.empty();
      models.each(function (model) {
        new SubmissionUI({
          model: model,
          el: insertRow(tbl),
        });
      });
      insertDataTable(tbl.parent());
      models.loaded = true;
    },
  });
};

$(window).on("load", function () {
  loadSubmissions();
});
