var cmc = cmc || {};

cmc.MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
cmc.DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

cmc.SCOPE_URL = 'http://www.google.com/calendar/feeds/';

// CSS IDs
cmc.monthViewButtonId = 'monthViewButton';
cmc.weekViewButtonId = 'weekViewButton';
cmc.todayButtonId = 'todayButton';
cmc.prevWeekButtonId = 'prevWeek';
cmc.nextWeekButtonId = 'nextWeek';
cmc.prevMonthButtonId = 'prevMonth';
cmc.nextMonthButtonId = 'nextMonth';
cmc.yearChooserId = 'yearChooser';
cmc.weekDurationId = 'weekDuration';
cmc.yearHolderId = 'yearHolder';
cmc.monthHolderId = 'monthHolder';
cmc.loginLinkId = 'loginLink';

// CSS classes
cmc.columnHeadingClass = 'columnHeading';
cmc.weekViewCellClass = 'weekViewCell';
cmc.monthViewCellClass = 'monthViewCell';
cmc.contentCellClass = 'contentCell';
cmc.eventMouseOutClass = 'eventMouseOut';
cmc.eventMouseOverClass = 'eventMouseOver';

// string labels
cmc.AppStringLabel = 'Generic-Calendar-Container-1.0';
cmc.loginLabel = 'Log in';
cmc.logoutLabel = 'Log out';
cmc.monthViewButtonLabel = 'Month';
cmc.weekViewButtonLabel = 'Week';
cmc.todayButtonLabel = 'Today';
cmc.prevWeekButtonLabel = '<<';
cmc.nextWeekButtonLabel = '>>';
cmc.prevMonthButtonLabel = '<<';
cmc.nextMonthButtonLabel = '>>';
cmc.loadingLabel = ' loading... ';
cmc.moreLabel = 'more';

cmc.CalendarContainer = function() {  
  // fix quarks for IE
  cmc.fixIE();

  this.calendarService = new google.gdata.calendar.CalendarService(cmc.AppStringLabel);

  this.calendarBodyId = null;
  this.navControlId = null;
  this.viewControlId = null;
  this.loginControlId = null;
  this.statusControlId = null;
  this.eventDisplayId = null;
  this.eventCallback = null;
  this.calId = null;
  this.visibility = null;

  this.currentPivotDate = new Date();
  this.currentViewMode = null;
};

cmc.CalendarContainer.prototype.setCalendarBody = function(cssId) {
  this.calendarBodyId = cssId;
};

cmc.CalendarContainer.prototype.setNavControl = function(cssId) {
  this.navControlId = cssId;
};

cmc.CalendarContainer.prototype.setViewControl = function(cssId) {
  this.viewControlId = cssId;
};

cmc.CalendarContainer.prototype.setDefaultEventDisplay = function(cssId) {
  this.eventDisplayId = cssId;
};

cmc.CalendarContainer.prototype.setStatusControl = function(cssId) {
  this.statusControlId = cssId;
};

cmc.CalendarContainer.prototype.setEventCallback = function(trigger, callback) {
  this.eventTrigger = trigger;
  this.eventCallback = callback;
};

cmc.CalendarContainer.prototype.setCalendar = function(calId, visibility, cssId) {
  this.visibility = visibility;
  this.calId = calId;
  this.loginControlId = cssId;
};

cmc.CalendarContainer.prototype.setPublicCalendar = function(calId) {
  this.visibility = 'public';
  this.calId = calId;
};

cmc.CalendarContainer.prototype.setPrivateCalendar = function(calId) {
  this.visibility = 'private';
  this.calId = calId;
};

cmc.CalendarContainer.prototype.setLoginControl = function(cssId) {
  this.loginControlId = cssId;
};

cmc.CalendarContainer.prototype.render = function() {

  var calendar = this;

  calendar.createFittingSpan();

  // global init

  if (calendar.visibility == 'private') {
    calendar.initLoginControl();
  }
 
  // default view is month view
  calendar.initViewControl();
  
  if (!calendar.currentViewMode) {
    calendar.setDefaultView('month');
  }

  calendar.currentViewMode();

};  


cmc.CalendarContainer.prototype.setDefaultView = function(view) {
  switch(view) {
    case 'week':
      this.currentViewMode = this.initWeekView;
      break;
    case 'month':
      this.currentViewMode = this.initMonthView;
      break;
  }
};

cmc.CalendarContainer.prototype.getFeedUrl = function() {
  return ['http://www.google.com/calendar/feeds/', 
      this.calId, '/', this.visibility, '/full'].join('');
};

cmc.CalendarContainer.prototype.hasValidToken = function(scope) {

  var success = false;

  if (google.accounts.user.checkLogin(scope)) {

    success = true;

    google.accounts.user.getInfo(function(data) {
      var target = eval(data.currentTarget.responseText);
      //console.log(target);      
      success = true;
    });
  } 

  return success;
};

cmc.CalendarContainer.prototype.initLoginControl = function() {

  var calendar = this;

  var loginHtml = [];

  loginHtml.push('<a id="');
  loginHtml.push(cmc.loginLinkId);
  loginHtml.push('" href="">')
  loginHtml.push(cmc.loginLabel);
  loginHtml.push('</a>');

  var loginElement = jQuery(loginHtml.join(''));

  var scope = calendar.getFeedUrl();

  if (!calendar.hasValidToken(scope)) {
    loginElement.html(cmc.loginLabel);
  } else {
    loginElement.html(cmc.logoutLabel);
  }

  jQuery('#' + calendar.loginControlId).html(loginElement);

  loginElement.bind('click', function(event) {

    event.preventDefault();         

    if (!calendar.hasValidToken(scope)) {
      google.accounts.user.login(scope);     
    } else {
      google.accounts.user.logout();
      loginElement.html(cmc.loginLabel); 
    }
  });  

};

cmc.CalendarContainer.prototype.initViewControl = function() {

  var calendar = this;

  var viewControlHtml = [];

  viewControlHtml.push('<input type="button" id="');
  viewControlHtml.push(cmc.weekViewButtonId);
  viewControlHtml.push('" value="');
  viewControlHtml.push(cmc.weekViewButtonLabel);
  viewControlHtml.push('">');

  viewControlHtml.push('&nbsp;');
  
  viewControlHtml.push('<input type="button" id="');
  viewControlHtml.push(cmc.monthViewButtonId);
  viewControlHtml.push('" value="');
  viewControlHtml.push(cmc.monthViewButtonLabel);
  viewControlHtml.push('">');
  
  jQuery('#' + this.viewControlId).empty();
  jQuery('#' + this.viewControlId).html(viewControlHtml.join(''));

  // append click handler to view control buttons

  jQuery('#' + cmc.monthViewButtonId).click(function() {
    calendar.currentViewMode = calendar.initMonthView;
    calendar.currentViewMode();    
  });

  jQuery('#' + cmc.weekViewButtonId).click(function() {
    calendar.currentViewMode = calendar.initWeekView;
    calendar.currentViewMode();
  });

};

cmc.CalendarContainer.prototype.updateWeekDuration = function() {
  var weekStart = cmc.getFirstDateOfWeek(this.currentPivotDate);
  var weekEnd = new Date(weekStart);
  weekEnd.setDate(weekEnd.getDate() + 6);

  var durationString = [];
  
  durationString.push(cmc.monthString(weekStart.getMonth()));
  durationString.push(' ');
  durationString.push(weekStart.getDate());
  durationString.push(' - ');
  durationString.push(cmc.monthString(weekEnd.getMonth()));
  durationString.push(' ');
  durationString.push(weekEnd.getDate());  
  durationString.push(' ');
  durationString.push(weekEnd.getFullYear());  
  
  jQuery('#' + cmc.weekDurationId).empty()
  jQuery('#' + cmc.weekDurationId).html(durationString.join(''));
};

cmc.CalendarContainer.prototype.initWeekView = function() {      
  this.initWeekNavControl();
  this.updateWeekView();
};

cmc.CalendarContainer.prototype.initWeekNavControl = function() {

  var calendar = this;

  var navControlHtml = [];

  navControlHtml.push('<input type="button" id="');
  navControlHtml.push(cmc.todayButtonId);
  navControlHtml.push('" value="');
  navControlHtml.push(cmc.todayButtonLabel);
  navControlHtml.push('"/>');

  navControlHtml.push('&nbsp;');   
  
  navControlHtml.push('<input type="button" id="');
  navControlHtml.push(cmc.prevWeekButtonId);
  navControlHtml.push('" value="');
  navControlHtml.push(cmc.prevWeekButtonLabel);
  navControlHtml.push('"/>');

  navControlHtml.push('&nbsp;');

  navControlHtml.push('<span id="');
  navControlHtml.push(cmc.weekDurationId);
  navControlHtml.push('"></span>');

  navControlHtml.push('&nbsp;');

  navControlHtml.push('<input type="button" id="');
  navControlHtml.push(cmc.nextWeekButtonId);
  navControlHtml.push('" value="');
  navControlHtml.push(cmc.nextWeekButtonLabel);
  navControlHtml.push('"/>');

  jQuery('#' + calendar.navControlId).empty();
  jQuery('#' + calendar.navControlId).html(navControlHtml.join(''));

  calendar.updateWeekDuration();

  jQuery('#' + cmc.todayButtonId).click(function() {      
    calendar.currentPivotDate = new Date();
    calendar.currentViewMode();
  });

  jQuery('#' + cmc.prevWeekButtonId).click(function() {      
    calendar.currentPivotDate.setDate(calendar.currentPivotDate.getDate() - 7);     
    calendar.updateWeekView();
  });

  jQuery('#' + cmc.nextWeekButtonId).click(function() {
    calendar.currentPivotDate.setDate(calendar.currentPivotDate.getDate() + 7);
    calendar.updateWeekView();
  });
};

cmc.CalendarContainer.prototype.updateWeekView = function() {

  this.updateWeekDuration();

  var firstDate = cmc.getFirstDateOfWeek(this.currentPivotDate);

  var lastDate = new Date(firstDate);
  lastDate.setDate(firstDate.getDate() + 6);

  var weekViewHtml = [];

  weekViewHtml.push('<table style="border-collapse: separate;">');

  weekViewHtml.push('<tr>');

  var dateHolder = new Date(firstDate);

  for (var i = 0; i < 7; i++) {

    var weekDateHeading = [dateHolder.getFullYear(), '-', 
        cmc.padZero(dateHolder.getMonth() + 1), '-', cmc.padZero(dateHolder.getDate())].join('');

    var weekDateHeading = [];

    weekDateHeading.push(cmc.dayString(dateHolder.getDay()));
    weekDateHeading.push(' ');
    weekDateHeading.push(dateHolder.getMonth() + 1);
    weekDateHeading.push('/');
    weekDateHeading.push(dateHolder.getDate());


    weekViewHtml.push('<td class="');
    weekViewHtml.push(cmc.columnHeadingClass);
    weekViewHtml.push('">');
    weekViewHtml.push(weekDateHeading.join(''));
    weekViewHtml.push('</td>');      

    dateHolder.setDate(dateHolder.getDate() + 1);
  }
  weekViewHtml.push('</tr>');

  var dateHolder = new Date(firstDate);

  weekViewHtml.push('<tr>');
  for (var i = 0; i < 7; i++) {
    var dateCellId = [dateHolder.getFullYear(), cmc.padZero(dateHolder.getMonth() + 1), 
        cmc.padZero(dateHolder.getDate())].join('');
    var dateContentId = ['content', dateHolder.getFullYear(), cmc.padZero(dateHolder.getMonth() + 1), 
        cmc.padZero(dateHolder.getDate())].join('');

    weekViewHtml.push('<td>');

    var dateHtml = [];
    dateHtml.push('<div class="');
    dateHtml.push(cmc.weekViewCellClass);
    dateHtml.push('" id=');
    dateHtml.push(dateCellId);
    dateHtml.push('>');
    //dateHtml.push(cmc.dayString(i));

    dateHtml.push('<div class="');
    dateHtml.push(cmc.contentCellClass);
    dateHtml.push('" id=');
    dateHtml.push(dateContentId);
    dateHtml.push('>');
    dateHtml.push('</div>');      
    dateHtml.push('</div>');
    
    weekViewHtml.push(dateHtml.join(''));

    weekViewHtml.push('</td>');
    
    dateHolder.setDate(dateHolder.getDate() + 1);
  }

  weekViewHtml.push('</tr>');
  weekViewHtml.push('</table>');
 
  jQuery('#' + this.calendarBodyId).empty();
  jQuery('#' + this.calendarBodyId).html(weekViewHtml.join(''));

  this.overlayGData(firstDate, lastDate);
};

cmc.CalendarContainer.prototype.setYearChooser = function(year) {

  var options =  jQuery('#' + cmc.yearChooserId).get(0).options;    

  for (var i = 0; i < options.length ; i++) {
    var option = options[i];
    
    if (option.value == year) {
      jQuery('#' + cmc.yearChooserId).get(0).selectedIndex = i;
      break;
    }
  }
};

cmc.CalendarContainer.prototype.createYearChooser = function() {
  
  var calendar = this;

  var year = 2000;
  var html = [];

  html.push('<select id="');
  html.push(cmc.yearChooserId);
  html.push('">');

  for (var i = 0; i < 20; i++)
  {
    var now = new Date();  
    if (year == now.getFullYear()) {
      html.push('<option selected="yes" value="');
    } else {
      html.push('<option value="');
    }

    html.push(year);
    html.push('">');
    html.push(year);
    html.push('</option>');
    year++;
  }

  html.push('</select>');

  html = html.join('');

  var element = jQuery(html).change(function() {
    calendar.currentPivotDate.setFullYear(
        $(this).get(0).options[$(this).get(0).selectedIndex].value);
    calendar.updateMonthView();
  });

  return element;
};

cmc.CalendarContainer.prototype.initMonthView = function() {
  this.initMonthNavControl();
  this.updateMonthView();
};

cmc.CalendarContainer.prototype.initMonthNavControl = function() {

  var calendar = this;

  var navControlHtml = [];

  navControlHtml.push('<input type="button" id="');
  navControlHtml.push(cmc.todayButtonId);
  navControlHtml.push('" value="');
  navControlHtml.push(cmc.todayButtonLabel);
  navControlHtml.push('">');

  navControlHtml.push('&nbsp;'); 
  
  navControlHtml.push('<input type="button" id="');
  navControlHtml.push(cmc.prevMonthButtonId);
  navControlHtml.push('" value="');
  navControlHtml.push(cmc.prevMonthButtonLabel);
  navControlHtml.push('">');
  
  navControlHtml.push('&nbsp;');
  
  navControlHtml.push('<span id="');
  navControlHtml.push(cmc.yearHolderId);
  navControlHtml.push('"/>');

  navControlHtml.push('&nbsp;');
  
  navControlHtml.push('<span id="');
  navControlHtml.push(cmc.monthHolderId);
  navControlHtml.push('">');
  navControlHtml.push(cmc.monthString(this.currentPivotDate.getMonth()));
  navControlHtml.push('</span>');
  
  navControlHtml.push('&nbsp;');

  navControlHtml.push('<input type="button" id="');
  navControlHtml.push(cmc.nextMonthButtonId);
  navControlHtml.push('" value="');
  navControlHtml.push(cmc.nextMonthButtonLabel);
  navControlHtml.push('">');

  jQuery('#' + calendar.navControlId).empty();
  jQuery('#' + calendar.navControlId).html(navControlHtml.join(''));

  jQuery('#' + cmc.yearHolderId).html(this.createYearChooser());

  jQuery('#' + cmc.todayButtonId).click(function() {      
    calendar.currentPivotDate = new Date();
    calendar.currentViewMode();
  });

  jQuery('#' + cmc.prevMonthButtonId).click(function() {

    var currentMonth = calendar.currentPivotDate.getMonth();
    calendar.currentPivotDate.setMonth(currentMonth - 1);
    calendar.currentPivotDate.setDate(1);                     

    calendar.updateMonthView();
  });

  jQuery('#' + cmc.nextMonthButtonId).click(function() {      
    
    var currentMonth = calendar.currentPivotDate.getMonth();
    calendar.currentPivotDate.setMonth(currentMonth + 1);
    calendar.currentPivotDate.setDate(1);

    calendar.updateMonthView();
  });
};

cmc.CalendarContainer.prototype.updateMonthNavControl = function() {          
  this.setYearChooser(this.currentPivotDate.getFullYear());
  jQuery('#' + cmc.monthHolderId).empty();
  jQuery('#' + cmc.monthHolderId).html(cmc.monthString(this.currentPivotDate.getMonth()));
};

cmc.CalendarContainer.prototype.initMonthGrid = function() {
  var monthViewHtml = [];

  monthViewHtml.push('<table style="border-collapse: separate;">');    
  monthViewHtml.push('<tr>');
  for (var i=0; i<7; i++ )
  {
      monthViewHtml.push('<td class="');
      monthViewHtml.push(cmc.columnHeadingClass);
      monthViewHtml.push('">');

      monthViewHtml.push(cmc.dayString(i));
      monthViewHtml.push('</td>');      
  }
  monthViewHtml.push('</tr>');

  var index = 0;

  for (var i=0; i<6; i++ )
  {
    monthViewHtml.push('<tr>');
    for (var j=0; j<7 ;j++ )
    {
      monthViewHtml.push('<td id="date' + index + '">');
      monthViewHtml.push('&nbsp;');
      monthViewHtml.push('</td>');
      index++;
    }
    monthViewHtml.push('</tr>');
  }

  monthViewHtml.push('</table>');

  jQuery('#' + this.calendarBodyId).empty();
  jQuery('#' + this.calendarBodyId).html(monthViewHtml.join(''));
};

cmc.CalendarContainer.prototype.updateMonthView = function() {

  this.initMonthGrid();
  this.updateMonthNavControl();

  // fill the month dates 

  var firstDate = (new Date(this.currentPivotDate));
  firstDate.setDate(1);

  var daysInMonth = cmc.getDaysInMonth(firstDate);
  
  var dateHolder = new Date(firstDate);

  var startIndex = firstDate.getDay();      

  for (var i = 0; i < daysInMonth; i++ ) {

    var dateCellId = [dateHolder.getFullYear(), cmc.padZero(dateHolder.getMonth() + 1), 
        cmc.padZero(dateHolder.getDate())].join('');
    var dateContentId = ['content', dateHolder.getFullYear(), cmc.padZero(dateHolder.getMonth() + 1), 
        cmc.padZero(dateHolder.getDate())].join('');

    var dateHtml = [];

    dateHtml.push('<div class="');
    dateHtml.push(cmc.monthViewCellClass);
    dateHtml.push('" id=');
    dateHtml.push(dateCellId);
    dateHtml.push('>');

    dateHtml.push('<div class="');
    dateHtml.push(cmc.contentCellClass);
    dateHtml.push('" id=');
    dateHtml.push(dateContentId);
    dateHtml.push('>');
    
    dateHtml.push(dateHolder.getDate());

    dateHtml.push('</div>');      
    dateHtml.push('</div>');
    
    jQuery('#date' + startIndex).html(dateHtml.join(''));

    dateHolder.setDate(dateHolder.getDate() + 1);
    startIndex++;
  }  

  var lastDate = new Date(firstDate);
  lastDate.setDate(daysInMonth);

  this.overlayGData(firstDate, lastDate);
};

cmc.CalendarContainer.prototype.defaultEventCallback = function(event) {
    
  var title = event.getTitle().getText();  
  var date = event.getTimes()[0].getStartTime().getDate();
  var content = event.getContent().getText();  
  
  // if this is a calendar gadget, handle the content this way
  if (event.getWebContentLink()) {
    var wcl = event.getWebContentLink();
    var type = wcl.getType();
    var wc = wcl.getWebContent();
    var height = wc.getHeight();
    var width = wc.getWidth();
    var url = wc.getUrl();

    if (type && type.match(/^image/i)) {
      var img = jQuery('<img/>');
      img.attr({src: url});
      content = img;
    }

    if (type && type.match(/^text/i)) {
      var iframe = jQuery('<iframe/>');
      iframe.attr({src: url});
      iframe.attr({height: height});
      iframe.attr({width: width});
      content = iframe;
    }
  }
  
  var eventHtml = [];
  eventHtml.push(date.toString());
  eventHtml.push('<br><br>');
  eventHtml.push('<b>Title:</b>');
  eventHtml.push('<br>');
  eventHtml.push(title);
  eventHtml.push('<br>');
  eventHtml.push('<br>');
  eventHtml.push('<b>Content:</b>');
  eventHtml.push('<p style="font-size: 11px;">');
  eventHtml.push(content); 
  eventHtml.push('</p>');
  eventHtml.push('<br>');

  jQuery('#' + this.eventDisplayId).html(eventHtml.join(''));
};

cmc.CalendarContainer.prototype.appendEvent = function(id, event) {

  var calendar = this;

  var title = event.getTitle().getText();    
  var eventId = event.getId().getValue();

  var cell = jQuery('#' + id);

  // special case, this is a date element that doesn't exist in the current view.  
  // This is most likely that an event that spans across two months.  This script 
  // currently doesn't handle multi-day events yet.
  if (cell.length == 0) {
    return;
  }
  
  var cellHeight = jQuery('.' + cmc.contentCellClass).parent().height();
  var cellWidth = cell.width();//jQuery('.' + cmc.contentCellClass).parent().width();
  var contentFontHeight = parseInt(cell.css('font-size'));

  var currentContentHeight = cell.height();
  
  //console.log('appending event: ' + title);
  //console.log(cellHeight + ' ' + currentContentHeight + ' ' + contentFontHeight);
  
  var bottomMargin = 5;

  if (cellHeight < currentContentHeight + contentFontHeight + bottomMargin) {
    // The contentCell is overflowing, too many events
    
    //console.log(cell.get(0).lastChild.innerHTML);

    if (cell.get(0).lastChild.innerHTML == cmc.moreLabel) {
      // Can return right away, there is already a "more" link
      //console.log('has more');
      return;
    }
    
    jQuery(cell.get(0).lastChild).empty();
    jQuery(cell.get(0).lastChild).remove();

    var moreHtml = [];
    moreHtml.push('<div align="right" class="');
    moreHtml.push(cmc.eventMouseOutClass);
    moreHtml.push('">');
    moreHtml.push(cmc.moreLabel);
    moreHtml.push('</div>');

    var moreDiv = jQuery(moreHtml.join(''));

    moreDiv.bind('click', function() {
      calendar.currentPivotDate = event.getTimes()[0].getStartTime().getDate();
      calendar.currentControlView = calendar.initWeekView;
      calendar.initWeekView();
    });

    moreDiv.bind('mouseover', function() {
      moreDiv.removeClass(cmc.eventMouseOutClass);
      moreDiv.addClass(cmc.eventMouseOverClass); 
    });

    moreDiv.bind('mouseout', function() {
      moreDiv.removeClass(cmc.eventMouseOverClass); 
      moreDiv.addClass(cmc.eventMouseOutClass); 
    });

    cell.append(moreDiv);    

  } else {

    var eventHtml = [];
    eventHtml.push('<div id="');
    eventHtml.push(eventId);
    eventHtml.push('" class="');
    eventHtml.push(cmc.eventMouseOutClass);
    eventHtml.push('">');
    eventHtml.push(calendar.fitText('&nbsp;' + title, cellWidth));
    eventHtml.push('</div>');

    var eventDiv = jQuery(eventHtml.join(''));

    eventDiv.bind(this.eventTrigger, function() {
      if (calendar.eventCallback) {
        calendar.eventCallback(event);
      } else {
        calendar.defaultEventCallback(event);
      }      
    });

    eventDiv.bind('mouseover', function() {
      eventDiv.removeClass(cmc.eventMouseOutClass);
      eventDiv.addClass(cmc.eventMouseOverClass); 
    });

    eventDiv.bind('mouseout', function() {
      eventDiv.removeClass(cmc.eventMouseOverClass); 
      eventDiv.addClass(cmc.eventMouseOutClass); 
    });

    cell.append(eventDiv);
  }
};

cmc.CalendarContainer.prototype.createMoreMenu = function(id) {

  var calendar = this;

  var moreHtml = [];

  moreHtml.push('<select id="');
  moreHtml.push(id);
  moreHtml.push('">');
  moreHtml.push('</select>');

  var moreDiv = jQuery(moreHtml.join(''));

  moreDiv.bind('change', function() {
    if (calendar.eventCallback) {
      calendar.eventCallback(event);
    } else {
      calendar.defaultEventCallback(event);
    }       
  });

  return moreDiv;
}

cmc.CalendarContainer.prototype.createFittingSpan = function() {
  var span = jQuery('<span/>');
  span.addClass(cmc.contentCellClass);
  span.css({'visibility': 'hidden'});
  jQuery(document.body).append(span);
  this.fittingSpan = span;
}

cmc.CalendarContainer.prototype.overlayGData = function(startDate, endDate) {
  
  var calendar = this;

  var feedUri = calendar.getFeedUrl();
  
  // if it is a private account and doesn't have a valid token
  if (calendar.visibility == 'private' && !calendar.hasValidToken(feedUri)) {
    jQuery('#' + this.statusControlId).html('you must log in to access private calendar');
    return;
  }

  endDate.setDate(endDate.getDate() + 1);

  var startDateTime = new google.gdata.DateTime(startDate, true);
  var endDateTime = new google.gdata.DateTime(endDate, true);

  var query = new google.gdata.calendar.CalendarEventQuery(feedUri);

  query.setMinimumStartTime(startDateTime);
  query.setMaximumStartTime(endDateTime);

  query.setMaxResults(500);
  query.setOrderBy('starttime');
  query.setSortOrder('a');
  query.setSingleEvents(true);

  var callback = function(root) {
    
    var eventEntries = root.feed.getEntries();
     
      for (var i = 0; i < eventEntries.length; i++) {
        var event = eventEntries[i];
        for (var j = 0; j < event.getTimes().length; j++ ) {
          var status = event.getEventStatus();

          if (status == google.gdata.EventStatus.VALUE_CANCELED)
            continue;

          var when = event.getTimes()[j];
          var datetime = when.getStartTime();
          var date = datetime.getDate();
          
          var id = [];           
          id.push('content');
          id.push(date.getFullYear());
          id.push(cmc.padZero(date.getMonth() + 1));
          id.push(cmc.padZero(date.getDate()));
          id = id.join('');

          calendar.appendEvent(id, event);
        }
      }
      jQuery('#' + calendar.statusControlId).html('');
  }

  jQuery('#' + calendar.statusControlId).html(cmc.loadingLabel);
  calendar.calendarService.getEventsFeed(query, callback, cmc.handleError);
};

cmc.dayString = function(offset) {
  return cmc.DAYS[offset];
};

cmc.monthString = function(offset) {
  return cmc.MONTHS[offset];
};

cmc.getDaysInMonth = function(pivotDate) {
  var year = pivotDate.getFullYear();
  var month = pivotDate.getMonth();
  return 32 - (new Date(year, month, 32)).getDate();
};

cmc.getFirstDateOfWeek = function(pivotDate) {
  var dayOffset = pivotDate.getDay();
  return new Date(pivotDate.getFullYear(), pivotDate.getMonth(), 
      pivotDate.getDate() - dayOffset);
};

cmc.CalendarContainer.prototype.fitText = function(text, limit) {

  this.fittingSpan.html(text);

  var currentWidth = this.fittingSpan.width();

  while (currentWidth > limit) {
    text = text.replace(/[ .]+$/, '');    
    text = text.replace(/[^\n\r ]+$/, '...');
    this.fittingSpan.html(text);
    currentWidth = this.fittingSpan.width();
  }

  return text;
};


cmc.handleError = function (e) {
  google.accounts.user.logout();
  jQuery('#' + cmc.loginLinkId).html(cmc.loginLabel);
  //e.cause ? e.cause.statusText : e.message;
  jQuery('#' + this.statusControlId).html(e.cause.statusText);
};

cmc.getTokenInfo = function() {
  google.accounts.user.getInfo(function(data) {
    console.log(data.currentTarget.responseText);
    var target = eval(data.currentTarget.responseText);
    console.log(target);
  });
};

cmc.padZero = function(number) {
  if(number < 10) {
    number = 0 + '' + number;
  }      
  return number;
};

cmc.fixIE = function() {
  if (!Array.indexOf) {
    Array.prototype.indexOf = function(arg) {

      var index = -1;
      for (var i = 0; i < this.length; i++){
        var value = this[i];
        if (value == arg) {
          index = i;
          break;
        } 
      }
      return index;
    }
  }

  if (!window.console) {

    window.console = {};
    window.console.log = function(message) {
      var body = document.getElementsByTagName('body')[0];
      var messageDiv = document.createElement('div');
      messageDiv.innerHTML = message;
      body.insertBefore(messageDiv, body.lastChild);
    }
  } 

};