var meetingNotice = Class.create({
  initialize: function(data) {
    this.id = data.id;
    this.startDate = new Date(data.startDate);
    this.endDate = new Date(data.endDate);
    this.publicBodyName = data.publicBodyName;
  }
});

var pmnCalendar = Class.create({
  initialize: function() {
    $('pmnCalendar').removeClassName('hide');
    $('meetings').update();
    this.upcomingNotices = 6;
    this.baseurl = (document.location.hostname.include('.gov') || document.location.hostname.include('.us')) ? 'http://apps.tn.gov' : '';
    this.today = new Date();
    this.userDate = new Date(this.today.getTime());
    this.noticesByMonth = {};
    this.dateTemplate = new Template('<td id="#{id}" class="#{className}"><span>#{day}</span></td>');
    this.linkTemplate = new Template('<a href="#{pmnLink}">#{numMeetings}</a>');
    this.meetingListTemplate = new Template('<li><a href="'+this.baseurl+'/pmn/sitemap/notice/#{pmnId}.html" title="#{fullPublicBodyName}">#{month}/#{day} &ndash; #{truncPublicBodyName}</a></li>');
    this.monthNames = [
        "January", "February", "March",
        "April", "May", "June",
        "July", "August", "September",
        "October", "November", "December"
    ];
    this.tip = new Element('div', {id:'pmnTip'});
    this.tipOut = false;
    this.requestPending = false;
    this.initTable();
    this.makeRequest();
  },
  
  getQuery: function() {
    return 'year='+this.userDate.getFullYear()+'&month='+(this.userDate.getMonth()+1)+'&day='+this.userDate.getDate();
  },
  
  initTable: function() {
    $('prevMonth', 'nextMonth').invoke('observe', 'click', this.changeMonth.bind(this));
    $('pmnDates').observe('mouseover', (function(e) {
      var el = Event.element(e);
      el = el.hasClassName('hasMeeting') ? el : el.up('.hasMeeting');
      if (el) {this.showTip(el);};
    }).bind(this)).observe('mouseout', (function(e) {
      this.hideTip();
    }).bind(this)).observe('click', (function(e) {
      var el = Event.element(e);
      el = el.hasClassName('hasMeeting') ? el : el.up('.hasMeeting');
      if (el) {document.location.href = el.down('a').readAttribute('href');};
    }).bind(this));
  },
  
  changeMonth: function(e) {
    e.stop();
    if (!this.requestPending) {
      var el = Event.element(e);
      if (el.id == 'prevMonth') {
        this.userDate.setMonth(this.userDate.getMonth()-1, 1);
        if (this.userDate <= this.today) {
          this.userDate = new Date(this.today.getTime());
          el.addClassName('hide');
        };
      } else {
        this.userDate.setMonth(this.userDate.getMonth()+1, 1);
        $('prevMonth').removeClassName('hide');
      }
      this.makeRequest();
    };
  },
  
  makeRequest: function() {
    if (!this.currentNotices()) {
      this.requestPending = true;
      $('monthYear').update('<img src="/images/spinner.gif" alt="" />').addClassName('loading');
      this.noticesByMonth[(this.userDate.getMonth()+1).toString()+this.userDate.getFullYear().toString()] = {};
      var myObj = this;
      new Ajax.Request('/pmnout/notice/listByMonth?'+this.getQuery(), {
        method: 'get',
        onSuccess: function(response) {
          if (response.responseText != 'Error') {
            var prevNotice = {};
            myObj.currentNotices().allNotices = [];
            myObj.currentNotices().noticesGroupedByDate = [];
            response.responseText.evalJSON().notices.each(function(n) {
              var mn = new meetingNotice(n);
              myObj.currentNotices().allNotices.push(mn);
              if (prevNotice.startDate) {
                if (prevNotice.startDate.getDate() == mn.startDate.getDate()) {
                  myObj.currentNotices().noticesGroupedByDate.last().push(mn);
                  return;
                }
              }
              myObj.currentNotices().noticesGroupedByDate.push([mn]);
              prevNotice = mn;
            });
            myObj.updateDisplay();
          } else {
            myObj.showError();
          };
        },
        onFailure: function(response) {
          myObj.showError();
        }
      });
    } else {
      this.updateDisplay();
    }
  },
  
  updateDisplay: function() {
    $('monthYear').removeClassName('loading').update(this.getMonthName(this.userDate)+" "+this.userDate.getFullYear());
    
    var cal = '';
    var tmpDate = new Date(this.userDate.getTime());
    var nextMonth = new Date(this.userDate.getTime());
    nextMonth.setDate(1);
    nextMonth.setMonth(nextMonth.getMonth()+1);
    tmpDate.setDate(1);
    if (tmpDate.getDay()) {tmpDate.setDate(-(tmpDate.getDay()-1));};

    while (tmpDate < nextMonth) {
      cal += '<tr>';
      for (var i=0; i < 7; i++) {
        var myId = this.getMonthName(tmpDate)+tmpDate.getDate();
        var myClass = tmpDate.getMonth() != this.userDate.getMonth() ? 'overlap' : '';
        cal += this.dateTemplate.evaluate({id:myId, className:myClass, day:tmpDate.getDate()});
        tmpDate.setDate(tmpDate.getDate()+1);
      };
      cal += '</tr>';
    }
    
    $('pmnDates').update(cal);

    this.currentNotices().noticesGroupedByDate.each(function(ng) {
      var d = $(this.getMonthName(ng[0].startDate)+ng[0].startDate.getDate());
      d.addClassName('hasMeeting').insert(this.linkTemplate.evaluate({pmnLink:this.baseurl+'/pmn/search_result.html?date='+ng[0].startDate.getTime(), numMeetings:ng.length})).myNotices = ng;
    }, this);
    
    var m = $('meetings').update();
    if (this.currentNotices().allNotices.length) {
      for (var i=0; i < this.upcomingNotices; i++) {
        var n = this.currentNotices().allNotices[i];
        if (!n) {break;};
        m.insert(this.meetingListTemplate.evaluate({pmnId:n.id, month: n.startDate.getMonth()+1, day: n.startDate.getDate(), truncPublicBodyName:n.publicBodyName.truncate(23), fullPublicBodyName:n.publicBodyName}));
      };
    } else {
      m.insert('<li>There are no upcoming meetings for '+this.getMonthName(this.userDate)+', '+this.userDate.getFullYear()+'.</li>');
    }
    m.insert('<li class="more"><a href="'+this.baseurl+'/pmn/">Browse all meeting notices &raquo;</a></li>');
    
    this.requestPending = false;
  },
  
  getMonthName: function(d) {
    return this.monthNames[d.getMonth()];
  },
  
  currentNotices: function() {
    return this.noticesByMonth[(this.userDate.getMonth()+1).toString()+this.userDate.getFullYear().toString()];
  },
  
  getDateList: function(notices) {
    var list = '<ul>';
    notices.each(function(n) {
      list += '<li>'+n.publicBodyName+'</li>';
    });
    list += '</ul>';
    return list;
  },
  
  showTip: function(el) {
    //el.myNotices
    if (!this.tipOut) {
      var coords = el.positionedOffset();
      $('pmnOut').insert(this.tip.update(this.getDateList(el.myNotices)));
      var measurements = this.tip.getDimensions();
      this.tip.setStyle({top:(coords.top-measurements.height)+'px', left:(coords.left+12-measurements.width/2)+'px'});
      this.tipOut = !this.tipOut;
    };
  },
  
  hideTip: function() {
    if (this.tipOut) {
      this.tip.remove();
      this.tipOut = !this.tipOut;
    };
  },
  
  showError: function() {
    $('pmnCalendar').hide();
    $('meetings').update('<li class="note">The listing for upcoming meetings is currently unavailable. Please <a href="'+this.baseurl+'/pmn/">visit the public meeting notice site.</a></li>');
  }
  
});
new pmnCalendar();
