Array.prototype.remove_program = function(e){
  for (var index = 0, len = this.length; index < len; ++index) {
    var item = this[index];
    if (item.id == e){
      this.splice(index,1);
      return this
    }
  }
};

Array.prototype.get_program = function(id){
  for (var index = 0, len = this.length; index < len; ++index) {
    var item = this[index];
    if (item.id == id)
      return item
  }

  return -1;
};

Array.prototype.intersect = function(programs){
  if (this.length == 0)
    return [];

  var res = [];

  for (var index = 0, len = programs.length; index < len; ++index) {
    var program = this.get_program(programs[index]);
    if (program != -1)
      res.push(program);
  }

  this.splice(0,this.length);
  for (var index = 0, len = res.length; index < len; ++index)
      this.push(res[index])
};

var DEFAULT_OPTIONS = {
  answer_key: 'answers_',
  question_tag: 'question_block_',
  required: ['answers_level_one_tag', 'answers_5', 'answers_18', 'answers_3'],
  program_selector: 'answers_program',
  program_info: 'program_info',
  programs_by_zip: [],
  default_program_id: 0,
  base_url: null,
  submit_button: 'submit_button',
  submit_button_spinner: 'ajax_spinner' 
};

var ObserverBase = Class.create({
  trigger_callback: function(cbName, arg) {
    if ('function' == typeof this[cbName])
      this[cbName](this, arg);
  },

  get_selector_id: function(e){
    var id = e.id;

    if (id == undefined)
      return -1;

    return id.split(this.selector_tag)[1];
  },

  selector_tag: 'tag_',
  onSuccess: null,
  onFailure: null,
  error_div: null,
  ajax_spinner: null
});

/// When a program is selected, display a campus description (if exists)
var CampusObserver = Class.create(ObserverBase, {
  initialize: function (e, base_url) {
    this.element = $(e);
    this.element.observe('change', this.update.bind(this));
    this.base_url = base_url;
  },

  update: function () {
    var val = this.element.value;
    if (val.blank()) return;

    var url = this.base_url + '/get_campus_content?zip=' + $('answers_7').value + '&program=' + $('answers_program').value;
    new Ajax.Request(url, {
      method: 'get',
      onSuccess: function (transport) {
        if (transport.responseText) {
          $('campus_info').show();
          $('campus_description').innerHTML = transport.responseText;
        }
      }
    });
  }
});

var ZipCodeObserver = Class.create(ObserverBase, {
  initialize: function(e, programs, base_url){
    this.element = $(e);
    this.element.observe('change', this.update.bind(this));
    this.base_url = base_url;

    if (programs == undefined){
      var val = $(e).value;
      if (!val.blank())
        this.update();
    }
    else
      Object.extend(this.programs, programs || []);
  },

  update: function(){
    var val = this.element.value;
    if (val.blank())
      return;

    var url = this.base_url + '/programs_by_zip?zip=' + val;
    var cls = this;
    $(this.ajax_spinner).show();
    new Ajax.Request(url, {
      method: 'get',
      onSuccess: function(transport) {
        cls.programs = [];
        $(cls.error_div).innerHTML = '';
        Object.extend(cls.programs, transport.responseJSON || []);
        $(cls.ajax_spinner).hide();
        cls.trigger_callback('onSuccess');
      },
      onFailure: function(transport){
        $(cls.ajax_spinner).hide();
        $(cls.error_div).innerHTML = transport.responseText;
        cls.trigger_callback('onFailure');
      }
    });
  },

  programs: [],
  element: null,
  error_div: 'errors_for_7',
  ajax_spinner: 'zip_spinner'
});

var OnlineCampusSelector = Class.create(ObserverBase, {
  initialize: function(ids){
    $(ids).each(function(id){
      $(id).observe('change', this.update.bind(this));
      this.update($(id));
    }.bind(this));    
  },

  update: function(e){
    if (e.target != undefined)
      e = e.target;

    var id = this.get_selector_id(e);

    if (id == 'campus')
      this.campus = e.checked;
    else if (id == 'online')
      this.online = e.checked;

    this.trigger_callback('callback');
  },

  worker: function(programs){
    if (this.campus && this.online)
      return programs;
    else if (this.campus && !this.online)
      return this.campus_programs(programs);
    else if (this.online && !this.campus)
      return this.online_programs(programs);

    return [];
  },

  online_programs: function(programs){
    return this.get_programs(programs, 'online')
  },

  campus_programs: function(programs){
    return this.get_programs(programs, 'campus')
  },

  get_programs: function(programs, key){
    var list = [];
    programs.each(function(program){
      if (program[key]){
        list.push(program);}
    });

    return list;
  },

  online: false,
  campus: false,
  callback: null,
  selector_tag: 'answers_campus_online_value_'
});

var ProgramInfo = Class.create({
  initialize: function(e, base_url){
    this.content = e;
    this.base_url = base_url;
  },
  get: function(id){
    this.url = this.base_url + '/program_info?id=' + id;
    new Ajax.Updater(this.content, this.url, {evalScripts:true})
  }
});

var Notifier = Class.create({
  initialize: function(popup_id){
    this.popup = popup_id;
  },
  show_message: function(){
    if (this.popup != undefined && !this.popup.blank() &&  $(this.popup) != undefined) {
      $(this.popup).show();
      center($(this.popup + '_content'));
    } else
      alert('Undefined popup ID.')
  },

  popup: 'sp_popup'
});

var SchoolFormEngine = Class.create({
  initialize: function(form_id, program_list, programs_questions_map, programs_disqualification_map, options){
    Object.extend(this.options, DEFAULT_OPTIONS);
    Object.extend(this.options, options || { });

    this.global_program_list = program_list.clone();
    this.all_program_ids =  this.global_program_list.map(function(n) { return n.id });
    Object.extend(this.programs_disqualification, programs_disqualification_map || { });
    Object.extend(this.programs_questions, programs_questions_map || { });
    if (this.options.base_url == undefined || this.options.base_url.blank()){
        alert('Base url is undefined.');
        return;
    }
    this.zip_notifier = new Notifier('zip_error_popup');
    this.not_qualified_notifier = new Notifier('sp_popup');

    this.program_info = new ProgramInfo(this.options.program_info, this.options.base_url);
    $(this.options.submit_button).onclick = function(){
        if (this.programs_empty()){
          this.not_qualified_notifier.show_message();
          return false;
        }
        else{
          $(this.options.submit_button).disabled=true;
          $(form_id).submit();
          $(this.options.submit_button_spinner).show();
        }
    }.bind(this);

    var program_selector = $(this.options.program_selector);
    program_selector.observe('change', this.show_questions.bind(this));
    program_selector.observe('click', function(){
      if (this.programs_empty())
        this.not_qualified_notifier.show_message()
      }.bind(this)
    );

		if (e = $('answers_program')) {		
      this.campus_observer = new CampusObserver(e.id, this.options.base_url);
    }
    
    if (e = $('answers_7')){
        this.zip_observer = new ZipCodeObserver(e.id, this.options.programs_by_zip, this.options.base_url);
    
        this.zip_observer.onSuccess = function(){
          if (this.zip_observer.programs.length == 0)
            this.zip_notifier.show_message();
          else
            this.disqualify();
        }.bind(this);
    
        this.zip_observer.onFailure = function(){
          this.clear_programs();
          this.hide_questions();
        }.bind(this);
    }

    this.online_campus = new OnlineCampusSelector(['answers_campus_online_value_online',
      'answers_campus_online_value_campus']);

    this.online_campus.callback = function(){
      this.disqualify();
    }.bind(this);

    this.attach_handlers();

    this.disqualify();
  },

  options: {},
  global_program_list: [],
  programs: [],
  selected_program_id: - 1,
  programs_questions: [],
  programs_disqualification: [],
  zip_observer: undefined,
  campus_observer: undefined,

  programs_empty: function(){
    var program_selector = $(this.options.program_selector);
    return program_selector.options.length == 1
  },

  attach_handlers: function(){
    this.options.required.each(function(id){
      if (e = $(id))
        e.observe('change', this.disqualify.bind(this));
    }.bind(this));
  },

  hide_questions: function(){
    this.display_questions(false, this.selected_program_id)
  },

  show_questions: function(){
    this.hide_questions();
    this.display_questions(true)
  },

  display_questions: function(show, program_id){
    if (program_id == undefined){
      var program_selector = $(this.options.program_selector);
      program_id = parseInt(program_selector.options[program_selector.selectedIndex].value);
      this.selected_program_id = program_id;
    }

    var questions = this.get_questions(program_id);
    if (questions == undefined)
      return;

    if (show){
      this.program_info.get(program_id)
    }
    else {
      this.options.program_info.innerHTML = '';
    }

    questions.each(function(question){      
      if (show)
        $(this.options.question_tag + question).show();
      else
        $(this.options.question_tag + question).hide();
    }.bind(this));
  },

  disqualify: function (){
    this.programs = this.global_program_list.clone();
    this.hide_questions();
    this.options.required.each(function(id){
      if (e = $(id)){
        var e_id = this.get_question_id(e);
        var e_val = this.get_answer_id(e);
        this.disqualified_programs(e_id, e_val);
      }
    }.bind(this));

    if (this.zip_observer != undefined)
      this.programs.intersect(this.zip_observer.programs);

    this.programs = this.online_campus.worker(this.programs).clone();

    this.reorder_programs();
    this.populate_programs();
  },

  get_questions: function (program_id){
    return this.programs_questions[program_id]
  },

  clear_programs: function(){
    var program_selector = $(this.options.program_selector);
    program_selector.options.length = 0;
    program_selector.options.add(new Option("Please select"));
  },


  reorder_programs: function(){
      // console.warn(this.programs.map(function(n) { return n.id }));
      var ordered_result = [];
      this.all_program_ids.each(function(prog_id){
          this.programs.each(function(p){
              if (p.id==prog_id){
                  ordered_result.push(p);
              }
          })
      }.bind(this));
      this.programs = ordered_result;
      // console.warn(this.programs.map(function(n) { return n.id }));     
  },


  populate_programs: function(){
    this.clear_programs();
    
    var program_selector = $(this.options.program_selector);

    for (var index = 0, len = this.programs.length; index < len; ++index){
      var program = this.programs[index];
      var selected = program.id == this.options.default_program_id;
      program_selector.options.add(new Option(program.name, program.id, selected, selected));
    }

    if (program_selector.options.length > 1){
      this.show_questions();
    }
  },

  disqualified_programs: function (question_id, answer_id){
    var disqualified = this.get_disqualified_programs(question_id, answer_id);

    disqualified.each(function(item){
      this.programs.remove_program(item)
    }.bind(this));
  },

  get_question_id: function(e){
    var id = e.id;

    if (id == undefined)
      return -1;

    return id.split("answers_")[1];
  },

  get_answer_id: function(e){
    if (e.options[e.selectedIndex] == undefined)
      return -1;

    return e.options[e.selectedIndex].value;
  },

  get_disqualified_programs: function(question_id, answer_id){
    if (question_id == undefined || answer_id == undefined || answer_id == -1)
      return [];

    var disq = this.programs_disqualification[question_id];
    if (disq == undefined || disq[answer_id] == undefined)
      return [];

    return this.programs_disqualification[question_id][answer_id]
  }
});

var show_popup_onload = function(id){
 var notifier = new Notifier(id);
 notifier.show_message()
};

