exports.Task = extend(TolokaHandlebarsTask, function (options) {
  TolokaHandlebarsTask.call(this, options);
}, {
  validate: function (solution) {
    var output_values = solution.output_values;

    if (output_values.state == 'is_not_loaded') {
      if (output_values.result && output_values.result.length > 0) {
        return {
          task_id: this.getTask().id,
          errors: {
            state: {
              code: 'NOT_ALLOWED',
              message: 'Не выделяйте светофоры, если изображение не загрузилось!'
            }
          }
        }
      }
    } else if (output_values.state == 'is_empty') {
      if (output_values.result && output_values.result.length > 0) {
        return {
          task_id: this.getTask().id,
          errors: {
            state: {
              code: 'NOT_ALLOWED',
              message: 'Вы нарисовали прямоугольники, но указали, что светофоры отсутствуют!'
            }
          }
        }
      }
    } else if (output_values.state == "is_not_empty") {
      if (!output_values.is_empty && !output_values.result) {
        return {
          task_id: this.getTask().id,
          errors: {
            state: {
              code: 'NOT_ALLOWED',
              message: 'Обведите светофоры или укажите, что они отсутствуют!'
            }
          }
        };
      }
    }

    if (this.getTask().input_values.golden_rects) {
      var golden_rects = this.getTask().input_values.golden_rects;
      var user_rects = output_values.result;
      var golden_rects_count = golden_rects.length;
      var user_rects_count = user_rects ? user_rects.length : 0;
      var is_correct = true;
      if (golden_rects_count != user_rects_count) {
        is_correct = false;
      } else if (golden_rects_count == 0 && user_rects_count == 0) {
          is_correct = true;
      } else {
        for (var i = 0; i < golden_rects_count; i++) {
          var is_found = false;
          for (var j = 0; j < user_rects_count; j++) {
            is_found = iou(golden_rects[i], user_rects[j]) > 0.7;
            if (is_found) {
              break;
            }
          }
          if (!is_found) {
            is_correct = false;
            break;
          }
        }
      }
      this.setSolutionOutputValue("is_correct", is_correct)
    }

    return null;
  },
  onRender: function() {
    if (this.getTask().input_values.annotations) {
      this.setSolutionOutputValue("result", this.getTask().input_values.annotations);
    }
  }
});

function iou(rect1, rect2) {
  var x1_min = Math.min(rect1.data.p1.x, rect1.data.p2.x);
  var x1_max = Math.max(rect1.data.p1.x, rect1.data.p2.x);
  var y1_min = Math.min(rect1.data.p1.y, rect1.data.p2.y);
  var y1_max = Math.max(rect1.data.p1.y, rect1.data.p2.y);

  var x2_min = Math.min(rect2.data.p1.x, rect2.data.p2.x);
  var x2_max = Math.max(rect2.data.p1.x, rect2.data.p2.x);
  var y2_min = Math.min(rect2.data.p1.y, rect2.data.p2.y);
  var y2_max = Math.max(rect2.data.p1.y, rect2.data.p2.y);

  if (x2_max <= x1_min || x1_max <= x2_min) {
    return 0.;
  } else if (y2_max <= y1_min || y1_max <= y2_min) {
    return 0.;
  } else {
    var x_min = Math.max(x1_min, x2_min);
    var x_max = Math.min(x1_max, x2_max);
    var y_min = Math.max(y1_min, y2_min);
    var y_max = Math.min(y1_max, y2_max);

    var area = (x_max - x_min) * (y_max - y_min);
    var area1 = (x1_max - x1_min) * (y1_max - y1_min);
    var area2 = (x2_max - x2_min) * (y2_max - y2_min);

    return area / (area1 + area2 - area);
  }
}

function extend(ParentClass, constructorFunction, prototypeHash) {
  constructorFunction = constructorFunction || function () {};
  prototypeHash = prototypeHash || {};
  if (ParentClass) {
    constructorFunction.prototype = Object.create(ParentClass.prototype);
  }
  for (var i in prototypeHash) {
    constructorFunction.prototype[i] = prototypeHash[i];
  }
  return constructorFunction;
}
