
/* - o_calendar.js - */
/*
#  Origami http://plone.org/products/origami/
#  Publishing tools based on Archetypes and AT Content Types
#  Copyright (c) 2007 Academic Technologies Northwestern University
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
"""JavaScript helper functions that implement the calendar
functionality.
"""
__author__  = 'Origami Team <http://nuamps.at.northwestern.edu/origami>'
__docformat__ = 'restructuredtext'
*/

var xmlrpc = importModule("xmlrpc");
// need xmlrpc request sent to proper url
var serviceURL = location.href.split('topicfolder_view')[0];
var aServer = null;

var current     = new Date();
var current_day = current.getDate();
var year        = current.getFullYear();
var month       = current.getMonth() + 1;
var chosenDates = [];
var titlesVisible = false;
var weekdays    = new Array('Su','Mo','Tu','We','Th','Fr','Sa');
var months      = new Array('',
                  'January',
                  'February',
                  'March',
                  'April',
                  'May',
                  'June',
                  'July',
                  'August',
                  'September',
                  'October',
                  'November',
                  'December');
// base_url_req supplies a prefix for location-specific searches
// e.g. if clicks on an event should go to the events folder
// as opposed to the current folder where the calendar is displayed
var base_url_req = './';
var idGen = 0;

Array.prototype.contains = function (element) 
  {
          for (var i = 0; i < this.length; i++) 
       {
              if (this[i] == element) 
          {
                      return true;
              }
          }
          return false;
  };

function is_today(day, m, y)
{
    return current_day == day &&
            current.getFullYear() == y &&
            current.getMonth() + 1 == m;
}

// strips the trailing :00 from the time string
function shortenLongTime(time)
{
    if (time != null)
    {
    	timeArray = time.split(':');
    	
    	return timeArray[0] + ':' + timeArray[1];
    }
    return '00:00';
}

function make_title_list(eventsItem)
    {
    	return [shortenLongTime(eventsItem['start']) + ' ' + eventsItem['title'], BR(null)]
    }

function make_title_link(eventsItem)
{
    return [BR(null), A({'href': eventsItem['url']}, eventsItem['title'])]
}

/**
 * Returns a formatted table cell dependent on what day
 * it is and what events fall on this day.
 */
function get_day(eventday)
{
    day = eventday['day'];
    
    if (chosenDates.contains(day))
    {
        chosen_prefix = 'chosen';
    }

    // don't display nonsensical day numbers
    if (day > 0)
    {
        var td_class = '';
        var td_name = '';
        
        // there are events on this day
        if (eventday['event'] == 1)
        {
            td_class = 'event';
            td_name = 'eventday';
            
            if (is_today(day, month, year) && !titlesVisible)
                td_class = 'todayevent';
        }
        // there are no events
        else if (is_today(day, month, year) && !titlesVisible)
            td_class = 'todaynoevent';
        
        if (td_class == '')
        {
        	// it is not today and there are no events
            return TD(null, day);
        }

        if (titlesVisible)
        {
            return TD({'class': td_class, 'name': td_name},
                      [day,
                       map(make_title_link, eventday['eventslist'])
                       ]
                      );
        }
        
        var link = day;
        
        if (eventday['event'] == 1)
        {
            idGen++;
            link = A({'href': base_url_req + '?yearmonth=' + year + month + '&day=' + day,
                      'onmouseover': 'swapIn("' + idGen + '", "event_info_box")',
                      'onmouseout': 'swapOut("' + idGen + '", "event_info_box")',
                      'title': shortenLongTime(eventday['eventslist'][0]['start']) + ' ' + eventday['eventslist'][0]['title']},
                     day, SPAN({'id': idGen},
                               map(make_title_list, eventday['eventslist'])
                              	)
                     )
        }
        
        return TD({'class': td_class, 'name': td_name}, link);
    }

    // empty cell for day before or after month
    return TD(null, '');
}

// return formatted row of formatted day cells
function week_display(week)
{
    days_in_week = map(get_day, week);
    
    return TR(null, days_in_week);
}

// return formatted weekday name header
function label_display(row)
{
    return TR({'class': 'weekdays'}, map(partial(TD, null), row));
}

function connectToServer(alternateURL)
{
    if (aServer == null)
    {
        if (alternateURL != null)
        {
            serviceURL = alternateURL;
        }
        try
        {
            aServer = new xmlrpc.ServiceProxy(serviceURL,
                                              ['getEventsForCalendar']);
        }
        catch(e) {alert(e);}
    }
}

var detailsInPosition = false;
/**
 * Draw the calendar as a table.
 */

function drawNewCalendar(m, y, calendarClass, calendarId, eventDatesList, showTitles)
{
    detailsInPosition = false;
    connectToServer();
    month = m;
    year = y;
    chosenDates = eventDatesList;
    titlesVisible = showTitles;
    
    if (month == 0 || year == 0)
    {
        month = current.getMonth() + 1;
        year = current.getFullYear();
    }

    var monthName   = months[month];
    // calculate previous and next month/year
    last_m = month - 1 == 0 ? 12 : month - 1;
    last_y = last_m == 12 ? year - 1 : year;
    next_m = month + 1 == 13 ? 1 : month + 1;
    next_y = next_m == 1 ? year + 1 : year;
    args = last_m + ", " + last_y + ", '" + calendarClass + "', '" + calendarId + "', [], " + showTitles
    
    last_month = ''
    next_month = ''
    
   if (chosenDates.length == 0)
    {
	    // generate navigation tags
	    last_month = A({'onclick': 'drawNewCalendar(' + args + ')',
	                    'href': 'javascript://',
	                    'id': 'calendar-previous'}, '<<');
	    args = next_m + ", " + next_y + ", '" + calendarClass + "', '" + calendarId + "', [], " + showTitles
	    next_month = A({'onclick': 'drawNewCalendar(' + args + ')',
	                    'href': 'javascript://',
	                    'id': 'calendar-next'}, '>>')
    }
    
    this_month = SPAN({'id': 'calendar-month-month'}, monthName)
    thead = [TR(null,
                [TH(null, last_month),
                 TH({'colspan': 5}, this_month, ' ' + year),
                 TH(null, next_month)
                 ]
                ),
             label_display(weekdays)
             ];
    var weeks = aServer.getEventsForCalendar(month, year);

    var weeks_rows = map(week_display, weeks);
    while (weeks_rows.length < 6)
    {
        weeks_rows.push(TR(null, TD(null, '\u00a0'), TD(null, '\u00a0'), TD(null, '\u00a0'),
                                 TD(null, '\u00a0'), TD(null, '\u00a0'), TD(null, '\u00a0')));
    }
    // generate the calendar body
    var newTable = TABLE({'class': calendarClass, 'id': calendarId,
                          'cellpadding': 0, 'cellspacing': 0},
                         THEAD(null, thead),
                         TBODY(null, weeks_rows)
                         );

    var table = getElement(calendarId);
    swapDOM(table, newTable);
    //moveDetailsIntoPosition('maincal');
}

function dLog(text)
{
    var dbg = document.getElementById('debugger');
    //dbg.innerHTML += text + '<br />';
}

/**
 * find the coordinates of an element
 */
function findPos(obj)
{
	var curleft = curtop = 0;
	if (obj.offsetParent) {
	    dLog('found offsetparent');
		curleft = obj.offsetLeft
		dLog('curleft: ' + curleft);
		curtop = obj.offsetTop
		dLog('curtop: ' + curtop);
		while (obj = obj.offsetParent) {
                    dLog('new parent: ' + obj.attributes);
                    dLog('parent offsetLeft: ' + obj.offsetLeft);
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
		dLog('curleft final: ' + curleft);
		dLog('curtop final: ' + curtop);
	}
	return [curleft,curtop];
}

function findPosX(obj)
  {
    var curleft = 0;
    if(obj.offsetParent)
        while(1) 
        {
          curleft += obj.offsetLeft;
          if(!obj.offsetParent)
            break;
          obj = obj.offsetParent;
        }
    else if(obj.x)
        curleft += obj.x;
    return curleft;
  }

  function findPosY(obj)
  {
    var curtop = 0;
    if(obj.offsetParent)
        while(1)
        {
          curtop += obj.offsetTop;
          if(!obj.offsetParent)
            break;
          obj = obj.offsetParent;
        }
    else if(obj.y)
        curtop += obj.y;
    dLog('findy: ' + curtop);
    return curtop;
  }

if(typeof(window.external) != 'undefined'){

//yes, this is evil browser sniffing, but only IE has this bug

document.getElementsByName = function(name, tag){
    if(!tag){
        tag = '*';
    }
    var elems = document.getElementsByTagName(tag);
    var res = []
    for(var i=0;i<elems.length;i++){
        att = elems[i].getAttribute('name');
        if(att == name) {
            res.push(elems[i]);
        }
    }
    return res;
}

}

/**
 * move the details section of each cell to the proper location
 */
function moveDetailsIntoPosition(calendarId)
{
    if (detailsInPosition == false)
    {
        var dbg = document.getElementById('debugger');
        dLog('calId: ' + calendarId);
        var calendar = document.getElementById(calendarId);
        dLog('cal: ' + calendar);
        // get the coordinates of the top left corner
        //var calendar_pos = findPos(calendar);
        var calendar_pos = [findPosX(calendar), findPosY(calendar)];
        var eventdays = document.getElementsByName('eventday');
        dLog('eventdays[0]: ' + eventdays[0]);
        for (i=0; i<eventdays.length; i++)
        {
            var details = eventdays[i].childNodes[0].childNodes[1];
            details.style.top = calendar_pos[1] + calendar.offsetHeight + 'px';
            details.style.left = calendar_pos[0] + 'px';
            dLog('details left: ' + details.style.left);
            dLog('details top: ' + details.style.top);
        }
        detailsInPosition = true;
    }
}

function swapIn(sourceId, destId)
{
    var src = getElement(sourceId);
    var dst = getElement(destId);
    dst.innerHTML = src.innerHTML;
    dst.style.display = 'block';
}

function swapOut(sourceId, destId)
{
    var dst = getElement(destId);
    dst.style.display = 'none';
    dst.innerHTML = '';
}
