// Tworzenie zmiennej globalnej w celu dodania modeli, kolekcji i widoków
window.app = {};

// Tworzenie modelu zadania do wykonania
app.Todo = Backbone.Model.extend({
   // Ustawianie wartości domyślnych dla nowej instancji modelu zadania do wykonania
   defaults: {
      position: 1,
      title: '',
      done: false
   },

   // Inicjowanie modelu z kilkoma funkcjami rejestrującymi operacje
   initialize: function() {
      this
         .on('invalid', function(model, error) {
            console.log(error);
         })
         .on('add', function(model, error) {
            console.log('Dodano zadanie do wykonania o tytule "' + model.get('title') + '".');
         })
         .on('remove', function(model, error) {
            console.log('Usunięto zadanie do wykonania o tytule "' + model.get('title') + '".');
         })
         .on('change', function(model, error) {
            console.log('Zaktualizowano zadanie do wykonania o tytule "' + model.get('title') + '".');
         });
   },

   // Funkcja sprawdzająca poprawność właściwości modelu
   validate: function(attributes) {
      if(!attributes.title) {
         return 'Tytuł jest wymagany i nie może być pusty.';
      }

      if(attributes.position === undefined || parseInt(attributes.position, 10) < 1) {
         return 'Pozycja musi być wartością dodatnią.';
      }
   }
});

// Tworzenie kolekcji zadań do wykonania
app.todoList = new (Backbone.Collection.extend({
   // Określanie, że jest to kolekcja modeli zadań do wykonania
   model: app.Todo,

   // Magazyn lokalny przechowujący zadania do wykonania
   localStorage: new Backbone.LocalStorage('todo-list'),

   comparator: 'position',

   initialize: function() {
      this.on('add remove', this.collectionChanged);
   },

   collectionChanged: function(todo) {
      // Elementy są aktualizowane tylko wtedy, gdy nowy element jest poprawny
      if (todo.isValid()) {
         this.each(function(element, index) {
            element.save({
               position: index + 1
            });
         });
         this.sort();
      }
   }
}));

// Tworzenie widoku zadania do wykonania
app.TodoView = Backbone.View.extend({
   tagName: 'li',
   className: 'todo',

   template: _.template($('#todo-template').html()),

   events: {
      'blur .todo-position': 'updateTodo',
      'change .todo-done': 'updateTodo',
      'keypress .todo-title': 'updateOnEnter',
      'click .todo-delete': 'deleteTodo'
   },

   initialize: function() {
      this.listenTo(this.model, 'change', this.render);
      this.listenTo(this.model, 'destroy', this.remove);
   },

   deleteTodo: function() {
      // Usuwanie modelu z magazynu
      this.model.destroy();
   },

   updateTodo: function() {
      this.model.save({
         title: $.trim(this.$title.text()),
         position: parseInt(this.$position.text(), 10),
         done: this.$done.is(':checked')
      });
   },

   updateOnEnter: function(event) {
      if (event.which === 13) {
         this.updateTodo();
      }
   },

   render: function() {
      this.$el.html(this.template(this.model.toJSON()));
      this.$title = this.$('.todo-title');
      this.$position = this.$('.todo-position');
      this.$done = this.$('.todo-done');

      return this;
   }
});

// Tworzenie widoku aplikacji
app.appView = Backbone.View.extend({
   el: '#todo-sheet',

   events: {
      'click #new-todo-save': 'createTodo'
   },

   initialize: function() {
      this.$input = this.$('#new-todo');
      this.$list = this.$('ul.todos');

      this.listenTo(app.todoList, 'reset sort destroy', this.showTodos);
      this.listenTo(app.todoList, 'invalid', this.showError);

      // Pobieranie zestawu modeli z magazynu i ustawianie ich w kolekcji
      app.todoList.fetch();
   },

   createTodo: function() {
      // Tworzenie nowego zadania do wykonania, sprawdzanie jego poprawności i zapisywanie go na początku listy,
      // gdy jest poprawne
      app.todoList.create(
         {
            title: this.$input.val().trim()
         },
         {
            at: 0,
            validate: true
         }
      );

      // Resetowanie pola danych wejściowych
      this.$input.val('');
   },

   showError: function(collection, error, model) {
      // Wyświetlanie błędu użytkownikowi
      this
         .$('.error-message')
         .finish()
         .html(error)
         .fadeIn('slow')
         .delay(2000)
         .fadeOut('slow');
   },

   showTodo: function(todo) {
      // Dodanie pozycji tylko wtedy, gdy model jest poprawny
      if (todo.isValid()) {
         var view = new app.TodoView({ model: todo });
         this.$list.prepend(view.render().el);
      }
   },

   showTodos: function() {
      this.$list.empty();
      var todos = app.todoList.sortBy(function(element) {
         return -1 * parseInt(element.get('position'), 10);
      });
      for(var i = 0; i < todos.length; i++) {
         this.showTodo(todos[i]);
      }
   }
});

new app.appView();