(function($) {
  $.extend({ iv_user_cal: {} });

  //----------------------------- Available Hours --------------------------

  $.fn.iv_user_cal_avail_hours = function(options) {
    return this.each(function() {
      new $.iv.user_cal_avail_hours(this, options);
    });
  };

  $.fn.iv_user_cal_avail_hours_save = function(options) {
    return this.each(function() {
      var ah = $.data(this, 'user_cal_avail_hours');
      if(ah) { ah.save(options) };      
    });
  };

  $.iv.user_cal_avail_hours = function(el, options) {
    options = $.extend({
      same_hours_per_day: 1,
      days: [],
      avail_days: {},
      time_slots: [],
      availability: {},
      strings: {},
      save_uri: null,
      source: 'default',
      equipment_id: null,
      employee_id: null,
      default_start_time: '0800',
      default_end_time: '1700'
    }, options);
  
    var $$ = $(el);
    $.data(el, 'user_cal_avail_hours', this);

    var $cur_tbody         = null;
    var $cur_day_selection = $('#cur_day_selection', $$);
    var $cur_day           = $('#cur_day', $$);
    var num_rows           = 0;
    var select_start_re    = /^row_start_(\d+)$/;
    var select_end_re      = /^row_end_(\d+)$/;
    var cur_select_value   = 0;
    
    _init_form();

    this.save = _save;
    
    function _init_form() {
      $.each(options.days, function(i, n) {
        if(options.avail_days[n.value] === 1) {
          $('#day_' + n.value).attr('checked', 'checked');
        }
        else {
          $('#day_' + n.value).removeAttr('checked');
        }
      });
      
      if(options.same_hours_per_day) {
        $('#same_hours', $$).attr('checked', 'checked');
      }
      else {
        $('#vary_hours', $$).attr('checked', 'checked');
      }
      
      // When their available days are changed, we need to add or remove that day from the drop down.
      $('input.day_select', $$).change(function() {
        var $day = $(this);
        if($('input.day_select:checked', $$).length == 0) {
          $day.attr('checked', 'checked');
          return(false);
        }

        if($day.is(':checked')) {
          $("option[value='" + $day.val() + "']", $cur_day).removeAttr('disabled');
        }
        else {
          $("option[value='" + $day.val() + "']", $cur_day).attr('disabled', 'disabled');
          if($cur_day.val() === $day.val()) {
            // When a day is unchecked and the drop down is currently on that day, we need to change to
            // the first enabled day.
            $cur_day.val( $cur_day.find('option:enabled:first').val() );
            if(options.same_hours_per_day == 0) {
              _change_tbody($cur_day.val());
            }
          }
        }
      });
      
      $('#same_hours', $$).click(function() {
        options.same_hours_per_day = 1;
        $cur_day_selection.hide();
        _change_tbody('all');
      });
      $('#vary_hours', $$).click(function() {
        options.same_hours_per_day = 0;
        $cur_day_selection.show();
        _change_tbody($cur_day.val());
      });
  
      $cur_day.change(function() {
        $cur_day = $(this);
        $cur_tbody.hide();
        _change_tbody($cur_day.val());
      });

      options.days.push({ value: 'all', name: 'All' });
      $.each(options.days, function(i, n) {
        $cur_tbody = $('#avail_rows_' + n.value, $$);
        if(options.availability[n.value]) {
          var avail = true;
          $.each(options.availability[n.value], function(j,m) {
            _add_row({ loc: 'end',
                       avail: avail,
                       start_time: m.start,
                       end_time: m.end
                     });
            avail = avail ? false : true;
          });
        }
        else {
          _add_row({ loc: 'end',
                     avail: true,
                     start_time: options.default_start_time,
                     end_time: options.default_end_time
                   });
        }
      });
      
      if(options.same_hours_per_day == 1) {
        $cur_tbody = $('#avail_rows_all', $$).show();
      }
      else {
        $cur_tbody = $('#avail_rows_' + $cur_day.val(), $$).show();
      }

      $$.unbind('submit').submit( function() {
        _save();
        
      });
      
//      $('span.save_hours_btn', $$).click(function() {
//        $(this).iv_button_disable();
//        _save();
//      });
    }

    function _change_tbody(num) {
      $cur_tbody.hide();
      $cur_tbody = $('#avail_rows_' + num, $$).show();      
    }
    
    function _add_row(args) {
      var row_id = num_rows++;
      
      var $tr = $('<tr></tr>').attr({id: 'row_' + row_id}).addClass(args.avail ? 'avail' : 'not_avail');
      $('<td></td>').append(args.avail ? options.strings.avail : options.strings.not_avail).appendTo($tr);
      
      var $start_select = $('<select id="row_start_' + row_id + '" name="row_start_' + row_id + '"></select>').change(_time_change).focus(_save_cur_val);
      var $end_select = $('<select id="row_end_' + row_id + '" name="row_end_' + row_id + '"></select>').change(_time_change).focus(_save_cur_val);
      $.each(options.time_slots, function(i, n) {
        var $opt = $('<option value="' + n.value + '">' + n.text + '</option>');
        if(parseInt(args.start_time, 10) == parseInt(n.value, 10)) {
          $opt.attr('selected', 'selected');
        }
        $start_select.append($opt);
        
        if(parseInt(n.value, 10) > parseInt(args.start_time, 10)) {
          var $opt = $('<option value="' + n.value + '">' + n.text + '</option>');
          if(parseInt(args.end_time, 10) == parseInt(n.value, 10)) {
            $opt.attr('selected', 'selected');
          }
          $end_select.append($opt);
        }
      });
      $('<td></td>').append($start_select).appendTo($tr);
      $('<td></td>').append($end_select).appendTo($tr);

      var $link = null;
      if(args.avail) {
        $link = $('<span id="row_link_' + row_id + '" class="link">' + options.strings.add_break + '</span>');
        $link.click(_add_break);
      }
      else {
        $link = $('<span id="row_link_' + row_id + '" class="link">' + options.strings.remove_break + '</span>');
        $link.click(_remove_break);
      }        
      $('<td></td>').append($link).appendTo($tr);

      if(args.loc == 'end') {
        $cur_tbody.append($tr);
      }
      else if(args.loc == 'after') {
        $('#row_' + args.loc_ref, $cur_tbody).after($tr);
      }
      _update_link_display($tr);
      return(row_id);
    }

    function _add_break() {
      var row_id = this.id.replace(/^row_link_/, '');
      var $cur_row = $(this).closest('tr');
      var start_time = $('select:eq(0)', $cur_row).val();
      var end_time = $('select:eq(1)', $cur_row).val();
//      console.log([row_id, start_time, end_time].join(', '));
      var diff = end_time - start_time - 100;
      if(diff.toString().match(/50$/)) {
        diff += 50;
      }
      var mid = diff / 2;
//      console.log([row_id, start_time, end_time, diff, mid].join(', '));
      _update_times({ select: $('select:eq(1)', $cur_row),
                      start_time: start_time,
                      exclude_start: true,
                      end_time: parseInt(start_time, 10) + mid });
      var break_row_id = _add_row({ loc: 'after',
                                    loc_ref: row_id,
                                    avail: false,
                                    start_time: parseInt(start_time, 10) + mid,
                                    end_time: parseInt(end_time, 10) - mid
                                  });
      var avail_row_id = _add_row({ loc: 'after',
                                    loc_ref: break_row_id,
                                    avail: true,
                                    start_time: parseInt(end_time, 10) - mid,
                                    end_time: end_time
                                  });
      _update_link_display($cur_row);
    }

    function _remove_break() {
      var $cur_row    = $(this).closest('tr');
      var $prev_row   = $cur_row.prev();
      var $next_row   = $cur_row.next();
      var $next_break = $next_row.next();
      var end_val     = $('select:eq(1)', $next_row).val();
      var end_time    = null;
      
      if($next_break.length === 1) {
        end_time = $('select:eq(0)', $next_break).val()
      }
      else {
        end_time = options.time_slots[options.time_slots.length - 1].value;
      }
      
      _update_times( { select: $('select:eq(1)', $prev_row),
                       sel_time: end_val,
                       exclude_start: true,
                       start_time: $('select:eq(0)', $prev_row).val(),
                       end_time: end_time });
      $cur_row.remove();
      $next_row.remove();
      _update_link_display($prev_row);
    }

    function _update_times(args) {
      var $select = args.select;
      if($select) {
//        console.log(args);
        var start_time = args.start_time ? args.start_time : $('option:first', $select).val();
        var end_time = args.end_time ? args.end_time : $('option:last', $select).val();
        if(args.exclude_start) {
          start_time = parseInt(start_time, 10) + 50;
        }
        var selected = args.sel_time ? args.sel_time : args.keep_sel ? $('option:selected', $select).val() : args.sel_first ? start_time : end_time;
//        console.log([start_time, end_time, selected].join(', '));
        $select.empty();
        $.each(options.time_slots, function(i, n) {
          if(parseInt(n.value, 10) >= parseInt(start_time, 10) || args.show_all_times) {
            $select.append('<option value="' + n.value + '"' + (selected == n.value ? 'selected="selected"' : '') + '>' + n.text + '</option>');
          }
        });
      }
    }

    function _time_change() {
      var $select     = $(this);
      var start_match = null;
      var end_match   = null;
      
      if(start_match = this.id.match(select_start_re)) {
        var $cur_row  = $select.closest('tr');
        var $prev_row = $cur_row.prev();
        var $next_row = $cur_row.next();
        var cur_val   = parseInt($select.val(), 10);
        var $cur_end_select = $('select:eq(1)', $cur_row);
        var cur_end_val = parseInt($cur_end_select.val(), 10);
        
        var $prev_start_select = $prev_row.length === 1 ? $('select:eq(0)', $prev_row) : null;
        var prev_start_val = $prev_row.length === 1 ? parseInt($prev_start_select.val(), 10) : 0;
        
        var action = 'proceed';
//        console.log([cur_val, cur_end_val, $next_row.length, prev_start_val].join(', '));
        if((cur_val >= cur_end_val && $next_row.length === 1)
           || ($prev_start_select && prev_start_val >= cur_val)) {
          $("#range_overlap_dialog").dialog({
	    resizable: false,
	    height:100,
	    modal: true,
            draggable: false,
	    overlay: {
	      backgroundColor: '#aaa',
	      opacity: 0.6
	    },
	    buttons: {
	      Yes: function() {
		_time_change_merge();
                $(this).dialog('close');
	      },
	      No: function() {
		_time_change_revert();
                $(this).dialog('close');
	      }
	    },
	    close: function() {
	      _time_change_revert();
	    }
	  });
        }
        else {          
          // Update end select
          _update_times( { select: $cur_end_select,
                           start_time: $select.val(),
                           keep_sel: true,
                           exclude_start: true } );
          if($prev_row.length === 1) {
            // Update the end times of the previous row
            _update_times( { select: $('select:eq(1)', $prev_row), end_time: $select.val(), sel_last: true } );
            _update_link_display($prev_row);
          }
          _update_link_display($cur_row);
        }

        function _time_change_merge() {
          if($cur_row.hasClass('not_avail')) {
            $('span.link', $cur_row).trigger('click');
          }
          else if(cur_val > cur_end_val) {
            $('span.link', $next_row).trigger('click');
          }
          else {
            $('span.link', $prev_row).trigger('click');
          }
          $("#range_overlap_dialog").dialog('destroy');
        }

        function _time_change_revert() {
          $select.val(cur_select_value);
          $("#range_overlap_dialog").dialog('destroy');
        }
      }
      else if(end_match = this.id.match(select_end_re)) {
        var $cur_row = $select.closest('tr');
        var $next_row = $select.closest('tr').next();
        if($next_row.length === 1) {
          // Update this select
          _update_times( { select: $select, end_time: $select.val() } );
          // Update the start times of the current row
          _update_times( { select: $('select:eq(0)', $cur_row),
                           keep_sel: true,
                           show_all_times: true,
                           sel_first: true } );
          // Update the start times of the next row
          _update_times( { select: $('select:eq(0)', $next_row),
                           start_time: $select.val(),
                           show_all_times: true,
                           sel_first: true } );
          // Update the end times of the next row
          _update_times( { select: $('select:eq(1)', $next_row),
                           start_time: $select.val(),
                           keep_sel: true,
                           exclude_start: true } );
          _update_link_display($next_row);
        }
        _update_link_display($cur_row);
      }
    }

    function _save_cur_val() {
      cur_select_value = $(this).val();
    }
    
    function _update_link_display($row) {
      if($row.hasClass('avail')) {
        var start_val = parseInt( $('select:eq(0)', $row).val(), 10);
        var end_val   = parseInt( $('select:eq(1)', $row).val(), 10);
        if(end_val - start_val <= 100) {
          $('.link', $row).hide();
        }
        else {
          $('.link', $row).show();
        }
      }
    }

    function _save() {
      $('span.save_hours_btn', $$).iv_button_disable();
      var params = {
        source: options.source,
        equipment_id: options.equipment_id,
        employee_id: options.employee_id,
        same_hours_per_day: options.same_hours_per_day ? 1 : 0,
        avail_days: [],
        times: {
          all: [],
          1: [],
          2: [],
          3: [],
          4: [],
          5: [],
          6: [],
          7: []
        }
      };
      
      $('tbody.times', $$).each(function() {
        var id = this.id.replace(/^avail_rows_/, '');
        $('tr', $(this)).each(function() {
          var $tr = $(this);
          params.times[id].push( [$('select:eq(0)', $tr).val(), $('select:eq(1)', $tr).val()] );
        });
      });

      $('input.day_select:checked', $$).each(function() {
        params.avail_days.push($(this).val());
      });

//      console.log(params);
      $.iv.post_json(options.save_uri, { params: JSON.stringify(params) }, _saved);
    }

    function _saved(json) {
      if(json.success_uri) {
        $.iv.post_uri(json.success_uri);
      }
      else if(json.success_inline) {
        var messages = {};
        $.each(json.successes, function(i, n) {
          messages[n.message] = 1;
        });

        var msg_box = $('div.form_success').empty();
        if (!msg_box.length) {
          msg_box = $('<div></div>').addClass('form_success');
        }

        $.each(messages, function(key, val) {
          msg_box.append('<div>' + key + '</div>');
        });
        $$.prepend(msg_box);

        var to_id =  window.setTimeout(function() {
          window.clearTimeout(to_id);
          msg_box.remove();
        }, 5000);
        
      }
      else {
        $('span.save_hours_btn', $$).iv_button_enable();
      }
    }
  };

  //----------------------------- End Available Hours ----------------------

  //----------------------------- Resource Adjustments ---------------------

  $.fn.iv_user_cal_resource_adj_type_change = function(options) {
    return this.each(function() {
      var a = $.data(this, 'user_cal_resource_adj');
      if(a) { a.type_change(options); }
      else { new $.iv_user_cal.resource_adj(this, options); }
    });
  }

  $.iv_user_cal.resource_adj = function(el, options) {
    
    options = $.extend({
      action: null,
      resource_field: null,
      default_resource_id: null
    }, options);
    
    var self = this;
    var $$ = $(el);
    $.data(el, 'user_cal_resource_adj', this);
//    $.iv_user_cal.cur_appt_obj = this;
    
    _type_change();
    
    this.type_change = _type_change;

    function _type_change() {
      var params = {
        resource_type: $$.val()
      };
      $.iv.post_json(options.action, params, _process_resources);
    }

    function _process_resources(json) {
      if(json.success) {
        var $resource_field = $('#' + options.resource_field).empty();
        var selected_index = 0;
        $.each(json.resources, function(i, n) {
          $resource_field.append('<option value="' + n.id + '">' + n.string + '</option>');
          if(n.id == options.default_resource_id) {
            selected_index = i;
          }
        });
        $resource_field[0].selectedIndex = selected_index;
      }
    }
  };

  //----------------------------- EndResource Adjustments ------------------
  
  //----------------------------- Setting Appointments ---------------------

  $.iv_user_cal.cur_appt_obj = null;
  
  $.fn.iv_user_cal_appt_type_change = function(options) {
    return this.each(function() {
      var a = $.data(this, 'user_cal_avail_appts');
      if(a) { a.type_change(options); }
      else { new $.iv_user_cal.appt_avail_appts(this, options); }
    });
  }

//  $.fn.iv_user_cal_appt_date_change = function(options) {
//    return this.each(function() {
//      var a = $.data(this, 'user_cal_avail_appts');
//      if(a) { a.date_change(options); }
//    });
//  }

  $.iv_user_cal.appt_date_change = function(date) {
    $.iv_user_cal.cur_appt_obj.date_change(date);
  }
  
  $.fn.iv_user_cal_appt_party_size_change = function() {
    $.iv_user_cal.cur_appt_obj.party_size_change();
  }
  
  $.fn.iv_user_cal_appt_update_resources = function(options) {
    $.iv_user_cal.cur_appt_obj.update_resources();
  }

  $.iv_user_cal.appt_avail_appts = function(el, options) {
    options = $.extend({
      action: null,
      cal_id: 0,
      desc_field: null,
      party_size_field: null,
      date_field: null,
      time_field: null,
      resource_field: null,
      facility_field: null,
      website_id: 0,
      default_datetime: null,
      container_id: null
    }, options);
    
    var self = this;
    var $$ = $(el);
    var appt_date = null;
    var resource_slots = {};
    var selected_employee_id = null;
    $.data(el, 'user_cal_avail_appts', this);
    $.iv_user_cal.cur_appt_obj = this;
    
    _type_change();
    
    this.type_change = _type_change;
    this.date_change = _date_change;
    this.party_size_change = _party_size_change;
    this.update_resources = _update_resources;

    function _type_change() {
      var params = {
        website_id: options.website_id,
        cal_id: options.cal_id,
        type_id: $$.val()
      };
      if(options.party_size_field) { params['party_size'] = $('#' + options.party_size_field).val(); }
      if(appt_date) { params['appt_date'] = appt_date; }
      else if(options.default_datetime) { params['appt_date'] = options.default_datetime; }
      $.iv.post_json(options.action, params, _process_times);
    };
    
    function _date_change(date) {
      appt_date = date;
      var params = {
        website_id: options.website_id,
        cal_id: options.cal_id,
        type_id: $$.val()
      };
      if(appt_date) { params['appt_date'] = appt_date; }
      if(options.party_size_field) { params['party_size'] = $('#' + options.party_size_field).val(); }
      $.iv.post_json(options.action, params, _process_times);      
    };
    
    function _party_size_change() {
      var params = {
        website_id: options.website_id,
        cal_id: options.cal_id,
        type_id: $$.val(),
        party_size: $('#' + options.party_size_field).val()
      };
      if(appt_date) { params['appt_date'] = appt_date; }
      else if(options.default_datetime) { params['appt_date'] = options.default_datetime; }
      $.iv.post_json(options.action, params, _process_times);
    };
    
    function _process_times(json) {
      if(json.description && options.desc_field) {
        $('#' + options.desc_field).text(json.description);
      }
      if(json.success) {
        var $time_field;
        if (options.container_id) {
          $time_field = $('#' + options.time_field, $('#'+options.container_id)).empty();
        } else {
          $time_field = $('#' + options.time_field).empty();
        }
        var selected_index = 0;
        $.each(json.appt_list, function(i, n) {
          $time_field.append('<option value="' + n.id + '">' + n.string + '</option>');
          if(n.id == options.default_datetime) {
            selected_index = i;
          }
        });
        $time_field[0].selectedIndex = selected_index;
        resource_slots = json.resource_slots || {};
        selected_employee_id = json.selected_employee_id || null;
        _update_resources();
      }
    };

    function _update_resources() {
      var time;
      if (options.container_id) {
        time = $('#' + options.time_field, $('#'+options.container_id)).val();
      } else {
        time = $('#' + options.time_field).val();
      }
      if(resource_slots[time]) {
        var $e = $('#' + options.resource_field).empty();
        var selected_index = 0;
        var i = 0;
        $.each(resource_slots[time], function(k, v) {
          $e.append('<option value="' + k + '">' + v + '</option>');
          if(k == selected_employee_id) {
            selected_index = i;
          }
          ++i;
        });
        $e[0].selectedIndex = selected_index;
      }
    };
  }

  //----------------------------- End Setting Appointments -----------------
  
})(jQuery);
