var GoalSelector = Behavior.create({
  initialize: function(){
    this.element.reset();
    this.subject_selector = new CascadingSelector('subject_selector', 'category_selector', 'subject');
    this.category_selector = new CascadingSelector('category_selector', 'long_term_selector', 'category');
    this.goal_populator = new GoalPopulator('long_term_goal_id', 'goals');
    this.goal_watcher = new GoalWatcher('goals');
    this.buttons = this.element.down('.complete').hide();
  },
  "ongoals:changed": function(e){
    e.stop();
    if(this.goal_watcher.hasGoals() &&
          this.category_selector.targetHasValue() &&
          !this.goal_watcher.hasEdit())
       this.buttons.show();
    else
      this.buttons.hide();
  }
});

var CascadingSelector = Behavior.create({
  initialize: function(target, classPrefix){
    this.classPrefix = classPrefix;
    this.target = $(target);
    this.selectbox = this.element.down('select');
    this.targetSelect = this.target.down('select');
    this.targetOptions = [];
    this.resetTargetOptions();
    this.currentValue = $F(this.selectbox);
    if(Prototype.Browser.IE)
      this.element.onclick = this._iechange.bind(this);
  },
  _iechange: function(){
    var newValue = $F(this.selectbox);
    if(this.currentValue != newValue)
      this.onchange();
    this.currentValue = newValue;
  },
  onchange: function(e){
    this.resetTargetOptions();
    if($F(this.selectbox).blank()){
      this.target.hide();
    } else {
      var className = this.optionClassName();
      var splitOptions = this.targetOptions.partition(function(opt){
        return opt.hasClassName(className);
      });
      this.targetOptions = splitOptions[1];
      splitOptions[0].each(function(opt){
        this.targetSelect.insert(opt);
      }.bind(this));
      this.target.show().highlight();
      this.target.down('select').focus();
      this.target.select("."+this.optionClassName()).invoke('show');
    }
  },
  "oncascade:reset": function(e){
    this.target.hide();
    this.resetTargetOptions();
  },
  resetTargetOptions: function(){
    this.target.down('option[value=""]').selected = true;
    var optionsToRemove = this.target.select('option[class]');
    this.targetOptions = this.targetOptions.concat(optionsToRemove);
    optionsToRemove.invoke('remove');
    this.target.down('select').fire('cascade:reset');
  },
  optionClassName: function(){
    return '#{classPrefix}_#{id}'.interpolate({classPrefix: this.classPrefix, id: $F(this.selectbox)});
  },
  targetHasValue: function(){
    return !$F(this.targetSelect).blank();
  }
});

var GoalPopulator = Behavior.create({
  initialize: function(target){
    this.target = $(target);
    $('add_custom').observe('click', this.addCustom.bindAsEventListener(this));
    new Ajax.Request('/short_term_goals.json', {method: 'get', onComplete: this.dataComplete.bind(this)});
  },
  dataComplete: function(response){
    this.data = response.responseJSON;
  },
  onchange: function(e){
    this.reset();
    var value = $F(this.element);
    if(!value.blank()){
      this.target.up('table').show();
      this.target.up('table').down('th').update(this.element.options[this.element.selectedIndex].innerHTML);
      this.buildElements(value).each(function(el){ this.target.insert(el) }.bind(this));
      (function(){ this.target.fire("goals:changed") }).bind(this).defer();
    }
  },
  "oncascade:reset": function(){ this.reset(); },
  buildElements: function(value){
    return this.data[value].map(this.buildRow);
  },
  reset: function(){
    this.target.up('table').hide();
    this.target.update('');
    this.target.fire('goals:changed');
  },
  buildRow: function(row){
    var name = $td(row.name);
    var data = $td(DateSelectors.create('goals[]', 'target_date'),
                    $input({'type':'hidden', 'name':'goals[][name]', 'value':row.name}),
                    $input({'type':'hidden', 'name':'goals[][description]', 'value':row.description}));
    var buttons = $td(
                    $div({'class':'buttons'},
                      $a({'class':'positive'},'Edit'),
                      $a({'class':'negative'}, 'Remove')));
    return $tr({'class':'goal'},
                  name, data, buttons);
  },
  addCustom: function(){
    var affectedRow = this.buildRow({'name':'', 'description':''});
    this.target.insert(affectedRow);
    var editRow = $tr($td({'class':'edit new', 'colspan':3}));
    affectedRow.insert({'before': editRow}).hide();
    new GoalEditor(editRow, affectedRow);
  }
});

var DateSelectors = Class.create({
  initialize: function(prefix, field, date){
    this.prefix = prefix;
    this.field = field;
    this.date = date;
    this.index = "#{index}"
    this.fieldNameTemplate = "#{prefix}[#{field}(#{index}i)]".interpolate(this);
  },
  toHTML: function(){
    return $div(this.monthSelector(), this.daySelector(), this.yearSelector());
  },
  monthSelector: function(){
    var options = $R(0,11).map(function(idx){
      var selected = (this.date.getMonth() == idx);
      return $option({"value": idx+1, "selected": selected}, this.months[idx]);
    }.bind(this));
    options.unshift({"name": this.fieldNameTemplate.interpolate({index: '1'})});
    return $select.apply(this, options);
  },
  daySelector: function(){
    var options = $R(1,31).map(function(day){
      var selected = (this.date.getDate() == day);
      return $option({"value": day, "selected": selected}, day.toString());
    }.bind(this));
    options.unshift({"name": this.fieldNameTemplate.interpolate({index: '2'})});
    return $select.apply(this, options);
  },
  yearSelector: function(){
    var options = $R(this.date.getFullYear(), this.date.getFullYear() + 5).map(function(year){
      var selected = (this.date.getFullYear() == year);
      return $option({"value": year, "selected": selected}, year.toString());
    }.bind(this));
    options.unshift({"name": this.fieldNameTemplate.interpolate({index: '0'})});
    return $select.apply(this, options);
  },
  months: $w("January February March April May June July August September October November December")
});

DateSelectors.create = function(prefix, field){
  var today = new Date();
  return new DateSelectors(prefix, field, today).toHTML();
};

var GoalWatcher = Behavior.create({
  hasGoals: function(){
    return this.element.childNodes.length != 0;
  },
  hasEdit: function() {
    return this.element.select('table').length != 0;
  },
  onclick: function(evt){
    var link = evt.findElement('a');
    if(link){
      var affectedRow = link.up('tr');
      if($(link).innerHTML.match(/Remove/)){ // clicked Remove
        affectedRow.highlight({startcolor: '#FBE3E4', duration: 0.4, afterFinish: function(){
          affectedRow.remove();
          this.element.fire('goals:changed');
          }.bind(this)});
      } else { // clicked Edit
        var editRow = $tr($td({'class':'edit', 'colspan':3}));
        affectedRow.insert({'before': editRow}).hide();
        new GoalEditor(editRow, affectedRow);
      }
    }
  }
});

var GoalEditor = Behavior.create({
  initialize: function(original){
    this.original = original;
    this.buildForm();
    this.getValuesFromOriginal();
    this.original.fire('goals:changed');
  },
  onclick: function(evt){
    var link = evt.findElement('a');
    if(link){
      evt.stop();
      if(link.innerHTML.match(/Save/))
        this.save();
      else
        this.cancel();
    }
  },
  save: function(){
    if(this.valid()) {
      this.setValuesOnOriginal();
      this.element.remove();
      this.original.show().highlight();
      if(this.original.hasClassName('short_term_group'))
        this.original.setStyle({backgroundColor: '#e8f5cb'});
      this.original.fire('goals:changed');
    } else
      this.markErrors();
  },
  cancel: function(){
    var originalParent = this.original.up();
    this.element.remove();
    if(this.element.down('td.edit.new'))
      this.original.remove();
    else
      this.original.show().highlight();
    originalParent.fire('goals:changed');
  },
  valid: function(){
    if(this.nameField.nextSibling) $(this.nameField.nextSibling).remove(); // Clear existing errors
    return !$F(this.nameField).blank();
  },
  markErrors: function(){
    if($F(this.nameField).blank())
      this.nameField.up().insert($span({'class':'form-error negative'}).update("&bull; required"));
  },
  buildForm: function(){
    var td = $(this.element.childNodes[0]); // IE8 doesn't like down/select
    var summary = td.hasClassName('new') ? "New Short-Term Goal" : 'Edit Short-Term Goal';
    this.nameField = $input({'id':this.original.identify()+'_name', 'name':this.original.identify()+'_name', 'type':'text', 'class':'textbox', 'size':60});
    var tbl = $table({'cellspacing':0, 'summary': summary},
      $thead($tr($th({'class':'subhead', 'colspan':2}, summary))),
      $tbody($tr(
        $td($label("Due date")).addClassName('one'),
        $td(DateSelectors.create(this.original.identify(),'target_date'))
        ),
      $tr(
        $td($label({'for':this.original.identify()+'_name'}, "Goal name")).addClassName('one'),
        $td(this.nameField)
        ),
      $tr(
        $td($label({'for':this.original.identify()+'_description'}, "Goal description")).addClassName('one'),
        $td($textarea({'id':this.original.identify()+'_description', 'name':this.original.identify()+'_description', 'class':'textbox', 'cols':60, 'rows':3}))
        ))
    );
    td.insert(tbl);
    td.insert($div({'class':'buttons', 'style':'margin-top:10px'},
            $a({'class':'negative', 'style': 'float:right;'}, "Cancel"),
            $a({'class':'positive', 'style': 'float:right;'}, "Save Changes")));
  },
  getValuesFromOriginal: function(){
    // for now, assume they're in the same order in both locations
      var values = this.original.select('input[type=hidden]').reject(this.detectIdInput).invoke('getValue');
    this.element.select('input, textarea').each(function(el, index){
      el.value = values[index];
    });
    var indexes = this.original.select('select').pluck('selectedIndex');
    this.element.select('select').each(function(el, index){
      el.selectedIndex = indexes[index];
    });
  },
  setValuesOnOriginal: function(){
    // for now, assume they're in the same order in both locations
    var values = this.element.select('input[type=text], textarea').invoke('getValue');
    this.original.select('input').reject(this.detectIdInput).each(function(el, index){
      el.value = values[index];
    });
    var indexes = this.element.select('select').pluck('selectedIndex');
    this.original.select('select').each(function(el, index){
      el.selectedIndex = indexes[index];
    });
    // Now update the first td with the goal name
    this.original.down('td').update(this.element.down('input').getValue());
  },
  detectIdInput: function(el){
      return el.name.match(/\[id\]$/);
  }
});

var ShortTermGroupEditor = Behavior.create({
    onclick: function(event){
        var affectedRow = this.element.up('tr');
        var editRow = $tr($td({'class':'edit', 'colspan':3}));
        affectedRow.insert({before: editRow}).hide();
        new GoalEditor(editRow, affectedRow);
        event.stop();
    }
});

var ShortTermGroupRemover = Behavior.create({
  onclick: function(event){
    if(confirm("Are you sure you want to delete this goal? All selected students will be affected.")){
      var affectedRow = this.element.up('tr');
      var removedRow = $tr($td({'style':'background-color: #FBE3E4; color: rgb(197, 35, 27)', 'colspan': 3}, "Goal \""+ affectedRow.down('td').innerHTML + "\" was deleted. You must save for this to take affect."));
      affectedRow.down('input.deleted-field').setValue('true');
      affectedRow.highlight({startcolor: '#FBE3E4', duration: 0.4, afterFinish: function(){
          affectedRow.hide().insert({before: removedRow});
        }});
    }
  }
});