var StudentSelector = Behavior.create({
  initialize: function(){
    this.student_list = new StudentSelectorList(this.element.down('.selected_students'));
    this.student_list.selector = this;
    this.student_list_message = this.element.down('tr.message');
    this.button_box = $('button_box');
    if(this.button_box)
      this.button_box.hide();
    this.group_list = new StudentGroupList(this.element.down('.group_list'), this);
    this.autocompleter = new StudentAutocompleter(this.element.down('.autocomplete_field').down('input'), this);
    new Ajax.Request('/students.json', {'method':'get', onComplete: this.onComplete.bind(this)});
  },
  onComplete: function(response){
    this.student_data = response.responseJSON;
    this.autocompleter.importData(this.student_data);
  },
  addStudents: function(){
    $A(arguments).flatten().reverse().each(function(id){
      var found = this.student_data.find(function(s){ return s.id == id; });
      if(found)
        this.student_list.addStudent(found);
      if(this.student_list_message && this.student_list_message.visible()){
        this.student_list_message.hide();
        this.button_box.show();
      }
    }.bind(this));
  },
  studentSelected: function(id){
      return this.student_list.studentSelected(id);
  },
  onclick: function(e){
    if(e.findElement('a.reset_selection')){
      e.stop();
      $$('tr').each(function(row){ // Another IE8 hack
        if($(row).id.match(/student/))
          $(row).remove();
      });
      this.student_list_message.show();
      this.button_box.hide();
      this.autocompleter.fieldChanged(this.autocompleter.element, $F(this.autocompleter.element));
    }
  }
});
var StudentSelectorList = Behavior.create({
  addStudent: function(data){
    if(!this.element.down('#student_'+data.id)){
      var newStudent = $tr({'id': 'student_' + data.id, 'class': 'student'},
        $td(data.first_name, ' ', data.last_name, $input({'value': data.id, 'type': 'hidden', 'name': 'student_ids[]'})),
        $td(data.group),
        $td({'class': 'links'}, 
          $div({'class':'buttons'}, 
            $button({'title':'Remove', 'class': 'negative', 'type': 'button'}, "Remove"))));
      this.element.insert({top: newStudent});
      newStudent.highlight();
    }
  },
  studentSelected: function(id){
      return this.element.down('#student_'+ id);
  }, 
  onclick: function(event) {
    var button = $(event.findElement('button'));
    var table = $(event.findElement('table'));
    
    if(button){
      var row = button.up('tr');
        var selector_list = this;
      row.highlight({startcolor: '#FBE3E4', duration: 0.4, afterFinish: function(effect) {
        Element.remove(effect.element);
        var autocompleter = selector_list.selector.autocompleter;
        autocompleter.fieldChanged(autocompleter.element, $F(autocompleter.element));
        if($$('tr').length <= 2){ // IE8 doesn't like nice selectors
          table.down('tr.message').show();
          $('button_box').hide();
          
        }
      }});
      event.stop();
    }
  }
});

var StudentSingleSelector = Behavior.create({
  initialize: function(url){
    this.url_template = url;
    this.autocompleter = new StudentAutocompleter(this.element.down('.autocomplete_field').down('input'), this);
    new Ajax.Request('/students.json', {'method':'get', onComplete: this.onComplete.bind(this)});
  },
  onComplete: function(response){
    this.student_data = response.responseJSON;
    this.autocompleter.importData(this.student_data);
  },
  addStudents: function(ids){
    var id = $A(ids).first();
    this.goTo(this.url_template.interpolate({'id': id}));
  },
  goTo: function(url){
    window.location.href = url;
  },
  studentSelected: function(id) { return false; }
});

var StudentGroupList = Behavior.create({
  initialize: function(selector){
    this.selector = selector;
    new Ajax.Request('/groups.json', {'method': 'get', onComplete: this.onComplete.bind(this)});
  },
  onComplete: function(response){
    this.group_data = response.responseJSON['all'];
    this.selected = response.responseJSON['selected']
    this.buildElements();
  },
  buildElements: function(){
    var groupHash = $H(this.group_data);
    groupHash.keys().sort().each(function(group) {
      var item = $li({'id': 'group_' + group.toString().gsub(' ', '').underscore(), 'title': group, 'class':'group'}, $a(group));
      if(!$A(this.selected).include(group))
        item.addClassName('more').addClassName('hidden');
      this.element.insert(item);
    }.bind(this));
  },
  onclick: function(e){
    e.stop();
    var item = e.findElement('li');
    var groupName = item.title;
    this.selector.addStudents(this.group_data[groupName]);
  }
});

var StudentAutocompleter = Behavior.create({
  initialize: function(selector){
    this.selector = selector;
    this.arrow = $('arrow');
    this.observer = new Observed(this.element, this.fieldChanged.bind(this), {frequency: 0.250});
    this.autocomplete_list = this.element.up('form').down('.autocomplete_list')
    this.autocomplete_list.observe('click', this.completionClicked.bindAsEventListener(this));
    this.close_item = this.autocomplete_list.select('li.close').first();
    this.all_item = this.autocomplete_list.select('li.all').first();
  },
  fieldChanged: function(el, value){
      var list = this.autocomplete_list;
      this.studentItems().invoke('remove');
      if(!value.blank() && this.findCompletions(value).length != 0){
        if(this.close_item){
            var close_item = this.close_item;
            this.elementsForCompletion(value).reverse().each(function(e){ close_item.insert({before: e})});
        }
        else
            this.elementsForCompletion(value).each(function(e){ list.insert(e); });
      list.show();
      this.arrow.show();
    } else {
      list.hide();
      this.arrow.hide();
    }
  },
  onblur: function(){
    var __StudentSelectorListHide = function(){ 
      this.arrow.hide();
      this.autocomplete_list.hide();
    }.bind(this);
    this.blurTimeout = setTimeout(__StudentSelectorListHide, 250);
  },
  onfocus: function(e){
    this.fieldChanged(e.element(), $F(e.element()));
  },
  onkeydown: function(e){
    if(e.keyCode == Event.KEY_RETURN)
      e.stop();
    else if(e.keyCode == Event.KEY_ESC){
      this.arrow.hide(); 
      this.autocomplete_list.hide(); 
      e.stop();
    }
  },
  importData: function(students){
    this.data = $H();
    students.each(function(object){
      var name = $A([object.first_name, object.middle_name, object.last_name]).compact().join(' ');
      this.data.set(object.id, [name, object.group]);
    }.bind(this));
  },
  findCompletions: function(pattern){
    var rgxs = this.regexesForCompletion(pattern);
    return this.data.findAll(function(pair){
      return rgxs.all(function(r){ return pair.value[0].match(r) || pair.value[1].match(r); });
    });
  },
  regexesForCompletion: function(pattern){
    return pattern.split(/\s+/).reject(function(s){ return s.blank(); }).map(function(t){ return new RegExp(t, 'i'); });
  },
  highlightMatches: function(pattern, found){
    var rgxs = this.regexesForCompletion(pattern);
    return rgxs.inject(found, function(text, r){
      return text.sub(r, function(match){
        return '<em>' + match[0] + '</em>';
      });
    });
  },
  buildElementForMatch: function(data, pattern){
    var matchText = this.highlightMatches(pattern, data[1][0]);
    var groupText = this.highlightMatches(pattern, data[1][1]);
    var id = "auto_student_" + data[0];
    var className = this.selector.studentSelected(data[0]) ? 'selected' : '';
    return $li({'id': id, 'class': className}).update(matchText).insert({top: $span({'class':'group'}).update(groupText)});
  },
  elementsForCompletion: function(pattern){
    return this.findCompletions(pattern).map(function(data){ return this.buildElementForMatch(data, pattern); }.bind(this));
  },
  completionClicked: function(e){
    e.stop();
    clearTimeout(this.blurTimeout);
    var item = e.findElement('li');
    if(item.id) {
        var sid = parseFloat(item.id.match(/\d+$/));
        this.selector.addStudents([sid]);
        if(this.close_item)
            item.addClassName('selected');
        if(this.studentItems().length == 0){
            this.autocomplete_list.hide();
            this.element.value = '';
            this.arrow.hide();
        }
    } else {
        if(item.hasClassName('all')){
            var sids = item.siblings('li').without(this.close_item).pluck('id').map(function(id){ 
                return parseFloat(id.match(/\d+$/)); });
            this.selector.addStudents(sids);
            this.studentItems().invoke('remove');
        }
        this.autocomplete_list.hide();
        this.element.value = '';
        this.arrow.hide();
    }
  },
    studentItems: function(){
       return this.autocomplete_list.select('li').without(this.close_item).without(this.all_item);
    }
});
