(function () {

  var _this;
  var _days = ['P', 'W', 'Ś', 'C', 'P', 'S', 'N'];
  var _months = ['Styczeń', 'Luty', 'Marzec', 'Kwiecień', 'Maj', 'Czerwiec', 'Lipiec', 'Sierpień', 'Wrzesień', 'Październik', 'Listopad', 'Grudzień'];
  var _currentMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 1);

  var _hours = $('<select></select>');
  for (var i = 7; i <= 23; i++) {
    _hours.append($('<option value="' + i + '">' + i + ':00</option>'));
  }
  _hours.append($('<option value="0">00:00</option>'));

  function json(key, value) {
    return ['"', key, '":"', value, '"'].join('');
  }

  function _clickHandler(e) {
    var clicked = $((e.target) ? e.target : e.srcElement);
    if (clicked.hasClass('available')) {
      clicked.toggleClass('selected');
    }
    e.bubbles = false;
  }

  function _showReservationForm () {
    $('#reservationFormContainer .day, #reservationFormContainer .separator').remove();
    var selected = _this.getSelected();
    var nrSelected = selected.length;
    if (nrSelected) {
      var ul = $('#reservationForm ul');

      ul.append('<li class="separator">Wybrane dni:</li>');
      for (var i = 0; i < nrSelected; i++) {
        var li = $('<li class="day"></li>');
        li.append($('<label>' + _formatDate($(selected[i]).text()) + '</label>'));
        var from = _hours.clone();
        var to   = _hours.clone();
        from.find('option:last').remove();
        to.find('option:first').remove();
        li.append(from).append($('<span> - </span>')).append(to);
        ul.append(li);
        from.change(function() {_adjustToField(this);});
      }
      $('#reservationFormContainer').fadeIn();
    } else {
      _showErrorMsg('Nie wybrano żadnego wolnego dnia');
    }
  }

  function _hideReservationForm () {
    $('#reservationFormContainer').fadeOut();
  }

  function _showErrorMsg(txt) {
    _this.errorMsg.text(txt).fadeIn();
    setTimeout(function () {
      _this.errorMsg.fadeOut()
    }, 2000);
  }

  function _adjustToField(from) {
    from = $(from);
    var to = from.nextAll('select');
    var fromVal = parseInt(from.val(), 10);

    var options = to.find('option');
    var nrOptions = options.length;
    for (var i = 0; i < nrOptions; i++) {
      var option = $(options[i]);
      var optionVal = parseInt(option.val(), 10);
      (optionVal > fromVal) ? option.show() : option.hide();
      (optionVal == fromVal + 1) ? option.attr('selected', 'selected') : option.removeAttr('selected');
    }
  }

  function _formatDate (day) {
    return ((parseInt(day, 10) < 10) ? '0' : '') + day + '.' + ((_this.month < 10) ? '0' : '') + _this.month;
  }

  Calendar = function (month, year, room) {
    month = (typeof month != 'undefined') ? month : new Date().getMonth() + 1;
    year  = (typeof year  != 'undefined') ? year  : new Date().getFullYear();

    this.first = new Date(parseInt(year, 10), parseInt(month, 10) - 1, 1); // Date Object for first day in month
    this.month = this.first.getMonth() + 1;
    this.year  = this.first.getFullYear();
    this.days  = Math.round((new Date(this.year, this.month, 1).getTime() - this.first.getTime()) / 1000 / 60 / 60 / 24);
    this.room  = parseInt(room, 10) || 1;
    this.height = 0; // #calendar height
    this.obj;
    this.switchHandler;
    this.errorMsg;
    this.showingPast = false;

    _this = this;
  };

  Calendar.prototype.setSwitchHandler = function (f) {
    this.switchHandler = f;
    return this;
  };

  Calendar.prototype.get = function () {
    this.obj = $('<ol id="calendar"></ol>'); 
    var pre  = (this.first.getDay() == 0) ? 6 : this.first.getDay() - 1;
    var post = (7 - ((pre + this.days) % 7)) % 7;

    for (var i = 0; i < 7; i++) {
      this.obj.append($('<li class="header">' + _days[i] + '</li>'));
    }
    for (var i = 0; i < pre; i++) {
      this.obj.append($('<li class="empty">&nbsp;</li>'));
    }

    var reservations = this.getReservations();
    for (var i = 0; i < this.days; i++) {
      var li = $('<li id="day' + (i + 1) + '">' + (i + 1) + '</li>');

      var status = '';
      switch (reservations[i]) {
        case '0':
          status = 'available';
          break;
        case '1':
          status = 'awaiting';
          break;
        case '2':
          status = 'reserved';
          break;
      }
      if (status != '') {
        li.addClass(status);
      }

      this.obj.append(li);
    }
    
    for (var i = 0; i < post; i++) {
      this.obj.append($('<li class="empty">&nbsp;</li>'));
    }

    this.obj.append($('<li class="clear"></li>'));

    var dummy = $('<div></div>');
    dummy.append(this.obj);
    $(document.body).append(dummy);
    this.height = this.obj.height() - 1;
    dummy.remove();

    $('#reservationForm').unbind('submit').submit(this.makeReservation);
    $('#reservationFormCancel').unbind('click').click(_hideReservationForm);
    this.obj.click(_clickHandler);

    return this.obj;
  };

  Calendar.prototype.getWithButtons = function () {
    var result = $('<div></div>');
    var header = $('<div id="calendarHeader"></div>');
    var container = $('<div id="mainCalendarContainer"></div>');

    header.append(this.getPrevButton('&laquo; Poprzedni'))
          .append($('<h2>' + _months[_this.month-1] + ' ' + _this.year + '</h2>'))
          .append(this.getNextButton('Następny &raquo;'));

    var calendar = this.get();
    container.append(this.getPrevButton('&laquo;', true))
             .append(calendar)
             .append(this.getNextButton('&raquo;', true))
             .append('<div class="clear"></div>');

    var reserve = $('<span class="input link" id="reserve">Rezerwuj</span>').click(_showReservationForm);
    this.errorMsg = $('<div id="calendarError"></div').hide();

    result.append(header)
          .append(container)
          .append($('<div id="calendarButtons"></div>').append(reserve))
          .append(this.errorMsg);

    return result;
  };

  Calendar.prototype.getPrevButton = function (text, fullHeight) {
    text = text || '';
    fullHeight = !!fullHeight || false;

    var switchHandler = (_this.switchHandler) ? _this.switchHandler : switchCalendar;
    var prev = $('<span class="input">' + text + '</span>');
    if (this.showingPast || new Date(_this.year, _this.month - 2, 1).getTime() >= _currentMonth.getTime()) { 
      prev.addClass('link').click(function () {
        switchHandler.call(_this, _this.month - 1, _this.year);
      });
    }

    if (fullHeight && this.height) {
      if ($.browser.msie) {
        prev.addClass('fullHeight');
      } else {
        prev.css('lineHeight', this.height + 'px');
      }
    }

    return prev;
  };

  Calendar.prototype.getNextButton = function (text, fullHeight) {
    text = text || '';
    fullHeight = !!fullHeight || false;

    var switchHandler = (_this.switchHandler) ? _this.switchHandler : switchCalendar;
    var next = $('<span class="input link">' + text + '</span>').click(function () {
        switchHandler.call(_this, _this.month + 1, _this.year);
    });

    if (fullHeight && this.height) {
      if ($.browser.msie) {
        next.addClass('fullHeight');
      } else {
        next.css('lineHeight', this.height + 'px');
      }
    }

    return next;
  };

  Calendar.prototype.getReservations = function () {
    var reservations = [];

    var result = rpcQuery('rpc.php?function=rooms.getReservations', {id: this.room, month: this.month, year: this.year});
    if (result[0] == 'OK') {
      reservations = result[1].split(':');
    } else {
    }

    return reservations;
  };

  Calendar.prototype.getSelected = function () {
    return this.obj.find('.available.selected');
  };

  Calendar.prototype.makeReservation = function () {
    var form = $('#reservationForm');
    form.find('.error').removeClass('error');
    $('#reservationError').empty();

    // form fields to JSON
    var elements = form[0].elements;
    var nrElements = elements.length;
    var params = [json('id', _this.room), json('month', _this.month), json('year', _this.year)];

    for (var i = 0; i < nrElements; i++) {
      var element = $(elements[i]);
      var name = $(element).attr('name');
      if (name) {
        params[params.length] = json(name, form.find('input[name=' + name + ']').val());
      }
    }
    
    var iDays = [];
    // reservations to JSON
    var days = [];
    $('#reservationForm li.day').each(function (i, li) {
      li = $(li);
      var day = parseInt(li.find('label').text(), 10);
      iDays[iDays.length] = day;
      days[days.length] = '"' + day + '":"' + li.find('select:first option:selected').text() + '-' + li.find('select:last option:selected').text() + '"';
    });
    params[params.length] = '"reservations":{' + days.join(',') +  '}';

    var jsonString = '{' + params.join(',') + '}';
    var result = rpcQuery('rpc.php?function=rooms.makeReservation', {data: jsonString});
    if (result[0] == 'OK') {
      var nrIDays = iDays.length;
      for (var i = 0; i < nrIDays; i++) {
        _this.obj.find('#day' + iDays[i]).removeClass('selected').removeClass('available').addClass('awaiting');
      }
      _hideReservationForm();
      $('#reservationForm').triggerHandler('reserved');
    } else {
      if (result[1]) {
        $('#reservationError').text(result[1]);
      }
      if (result[2]) {
        form.find('input[name=' + result[2] + ']').addClass('error').focus();
      }
    }
    return false;
  };

  Calendar.prototype.showPast = function () {
    this.showingPast = true;
    return this;
  };

  Calendar.prototype.setRoom = function (id) {
    this.room = parseInt(id, 10);

    return this;
  }

})();

