(function($) {

	$.fn.epgh = function(settings) {
		//FIXME: the array "displaychannels" is not needed any more, since it is read from the backend.
		var defaults = {
			displayChannels: new Array('p7','k1','s1','n24','147','ARD','ZDF','RTP','RT2','SUP','VOX','3ST','ARG','TM3','HOT','MTC','VIV','VH1','COG','DSF','ESD','NTV','CNN','B3R','HR3','MDR','NDR','RBB','SW3','WDR','DRS','OR1','OR2','TNT','TRT','162','161'),		    
			p7ChannelId: 'p7'
		}
		settings = $.extend({}, defaults, settings);

		return this.each( function () {
			var $this = $(this);

			// These channels do exist in Polopoly 
			var allExistingChannelIds = new Array('p7');
			
			// List of all Channels
			var allChannels;

			// List of ChannelDays
			var channelDays = new Array();

			// ScheduleItems for each channel
			var channelScheduleItems = new Array();

			// Instance of Carousel-Widget
			var epgCarouselInstance;

			// Pagesize / Offset
			var shownChannels = 7;			
			var startIndex = 0;			
			var endIndex = shownChannels;
			
			// flag is set when EPG-View initializes an AJAX-Call
			var reloading = false;
			
			// externalId of item which should be opened on load
			var openItem;
			
			// display date
			var date;
			
			/**
			 * Initialize EPG
			 */
			function init() {
			  reloading = true;
			  			    
				// loading layer                        
        $this.ajaxStart(function(){                                                       
          if (reloading) {
            $('#epg-loading').height($('.epg-body').height()); 
            $('#epg-loading').show();
          }
        });

        $this.ajaxStop(function(){                                                                 
          if (reloading) {
            renderChannelDays();
            
            if (openItem) {
              var item = $('#'+openItem.replace(/\./g,"\\."));
              if (item.size() == 1) {
                var startTime = $('.epgtime', item).html().split(':')[0];                
                scrollToHour(parseInt(startTime, 10) - 7);                  
                $('a', item).trigger('click');
              }
            }
            
            $('#epg-loading').hide();
            reloading = false;
          }
        });

        date = getEPGDateString(new Date());
				
				createDatepicker();
				
				//check for date parameter
				var specificDate = $("input[id='pdate']").attr('value');
				if (specificDate) {
				  date = specificDate;
				}
			
        // check if a specific item should be opened
        var specificItem = $("input[id='pitem']").attr('value');
        if (specificItem) {
          openItem = specificItem;
        }
								
				loadChannels();

				addEvents();

				// horizontal scrollbar
				$('.epg-programm').jScrollHorizontalPane({showArrows:true, scrollbarHeight:19, scrollbarMargin:0, arrowSize:19});

			}

			/**
			 * Load and render all channels + program data
			 */
			function loadChannels() {
				// Channelliste + Channeldays abholen
				jQuery.get('/epg?extId=np.epg.department', {}, function(xml) {

					allChannels = createEPGChannelsFromDepartmentXml(xml);

					renderChannelList();

					// create jCarousel widget for displaying channel thumbs
					$('#epg-carousel').jcarousel({
						vertical: true,
						scroll: 6,
						initCallback: carouselInit,                  
						itemFirstInCallback: carouselFirstItem
					});
				});                
			}

			/**
			 * Load program data
			 */
			function loadProgramData() {			  
			  // reset view
				$('#epg-content').html('');

        reloading = true;        			
        var uri = "/epg?pExtId=np.ct.import.day";
				uri += "&d=" + date + "&c=" + settings.p7ChannelId; // P7 immer mit abholen
        
				// channeldays				
				for(var i=startIndex; i<endIndex; i++) {
					if (allChannels[allExistingChannelIds[i]]) {                    						           						
						channelDays[allChannels[allExistingChannelIds[i]].channelId] = null;
					  uri += "&c=" + allChannels[allExistingChannelIds[i]].channelId;					  
					}
				}  
				
				// get all channeldays for current date
				jQuery.get(uri, {}, function(xml) {                   				  
				  var days = createEPGChannelDaysFromXml(xml);         
          for (var i=0; i<days.length; i++) {
            channelDays[days[i].channel.channelId] = days[i];
          }
        });  
				
				// scroll to current time
				if (!openItem) {
				  var now = new Date();
				  scrollToHour((now.getHours()-6));
				}
			}
			 
			/**
			 * Senderliste (Carousel-Widget) füllen
			 */
			function renderChannelList(maxRows) {
				var html = '';
				for (channelName in allChannels) {
					var channel = allChannels[channelName];
					if (channel.channelId != settings.p7ChannelId) {  
						allExistingChannelIds.push(channel.channelId);
						var imageUrl = "";
						if (channel.image && channel.image.url && channel.image.contentId) {
							imageUrl = "polopoly_fs/" + channel.image.contentId + "!" + channel.image.url;
						}
						html += '<li><img src="/' + imageUrl + '" width="57" height="26" alt="' + channel.name + '" /></li>';
					}
				}
				$('#epg-carousel').html(html);  
			}

			
			/**
			 * Render channeldays
			 * 
			 */
			function renderChannelDays() {                                  
			  if (startIndex != 0) {          
          // always render P7
          var highlightclass = 'silver';
          var channelday = channelDays[settings.p7ChannelId];
          if (channelday != undefined) {
            renderChannelDay(channelday, 'row_' + settings.p7ChannelId, highlightclass);
          }          
        }
			   
			  for(var i=startIndex; i<endIndex; i++) {                                           
          if (channelDays[allExistingChannelIds[i]]) {             
            var renderChannel = (i < shownChannels) ? true : false;
            var highlightclass = (i % 2 == 0) ? 'silver' : 'silvergrey';                             
            renderChannelDay(channelDays[allExistingChannelIds[i]],
                'row_' + allExistingChannelIds[i], highlightclass);                  
          } else {
            // there is no data, so render empty row
            renderEmptyChannelDay(allExistingChannelIds[i] == settings.p7ChannelId);
          }                                   
        }  			  
			}
			
			
			/**
			 * Leere Programmzeile als Platzhalter
			 */
			function renderEmptyChannelDay(isP7Row) {
			  var html = '<div class="programm-col"></div>';
			  if (isP7Row) {
          html += '<div class="spacer"></div>'; //only after P7 row
        }
        $('#epg-content').append(html);
			}

			/**
			 * Programmzeile füllen
			 */
			function renderChannelDay(channelday, id, highlightclass) {
				if (channelday == undefined) {
					debug("channelday for id '" + id + "' was empty, could not render");
					return;
				}
				var html = '<div id="'+id+'" class="programm-col '+highlightclass+'">';

				var channelId = channelday.channel.channelId;                              
				var firstItemRendered = false;
				
				for (var i=0; i<channelday.scheduleItems.length; i++) {				  				  				  
				  if (!firstItemRendered) {
				    var datesplit = channelday.scheduleItems[i].startDate.split(' ');  
		        var date = datesplit[0].split('-');		        		        
		        var time = datesplit[1].split(':');		        
		        if (parseInt(time[0], 10) < 6) {		          
              var end = (parseInt(time[0], 10) * 60) + parseInt(time[1], 10) + parseInt(channelday.scheduleItems[i].realDuration, 10);                                          
              if (end <= 360) {
                // Sendungsende vor 6h => nicht anzeigen
                continue;                
              } else {
                // Sendungsende nach 6h => teilweise anzeigen                               
                var newDuration = (parseInt(end,10) - 360);                
                channelday.scheduleItems[i].realDuration = newDuration;                
              }
		        } else {		          		         
		          // Sendungsbeginn nach 6h => nach rechts schieben		          		          
		          var offset = 3 * ((time[0] * 60) + parseInt(time[1], 10) - 360);		          		          		           
		          var offsetDiv = '<div class="epg-filler" style=" width: '+ offset +'px;"></div>';
		          html += offsetDiv;		          		         		          
		        }		        
				  }
				  
					channelScheduleItems[channelday.scheduleItems[i].contentId] = channelday.scheduleItems[i];
					html += renderScheduleItem(channelday.scheduleItems[i], firstItemRendered);
					firstItemRendered = true;
				}
				html += '</div>';
				if (channelId == settings.p7ChannelId) {
					html += '<div class="spacer"></div>'; //only after P7 row
				}

				
				$('#epg-content').append(html);

				attachContentLayer(id);
			}


			/**
			 * Render ScheduleItem
			 * 
			 * @param item
			 * @param checkItemEnding
			 * @return
			 */
			function renderScheduleItem(item, checkItemEnding) {             
				// Check if program is currently running
				var datesplit = item.startDate.split(' ');  
				var date = datesplit[0].split('-');
				var time = datesplit[1].split(':');

				// yyyy, mm, dd, hh, mm, ss
				var startDate = new Date(date[0], date[1]-1, date[2], time[0], time[1], 00);
				var start = startDate.getTime();                   
				var end = start + (parseInt(item.realDuration) * 60 * 1000);

				// Items nur bis 6h Folgetag anzeigen
				if (checkItemEnding) {
				  var endDate = new Date(end);				  
				  if (startDate.getHours() < 6 && endDate.getHours() >= 6) {				    				    
				    endDate.setHours(6);
				    endDate.setMinutes(0);
				    end = endDate.getTime();
				    // set new Duration
				    item.realDuration = (end - start) / (60 * 1000);				    
				  }				  
				} 
				
				var now = new Date().getTime();
				var running = (start <= now && now <= end); 
				
				//var title = item.program.title + ' ('+item.realDuration+'min)';          
				var title = '<span class="epgtime">' + datesplit[1] + '</span> ' + item.programTitle;
				var hovertitle = datesplit[1] + " - " + item.programTitle;
				var divId = item.externalId;
				
				/*
				 * Breitenberechnung: 
				 * 1h = 180px => 1min = 3px
				 * jedes Item hat 3px Rand links + 3px Rand rechts, sowie 1px Margin rechts                            
				 */ 
				var width = (item.realDuration * 3) - 7; // 
				// Spezialfall 2min Sendungslänge
				var pbLeftSpecial = "";
				var pbRightSpecial = "";
				if (item.realDuration == "2") {
				  pbLeftSpecial = " pb-left-2";	        
				}
				// Spezialfall 1min Sendungslänge
				if (item.realDuration == "1") {
          pbLeftSpecial = " pb-left-1";
          pbRightSpecial = " pb-right-1";
        }
				if (width < 0) width = 0;

				// Genre (currently not used)
				var genre = "";
				/*if (item.program.genres) {
					for (var i=0;i<item.program.genres.length;i++) {
						if (i > 0) genre += " ";
						genre += item.program.genres[i].name;
					}              
				}*/         

				// Tooltip über komplettes Element, Text nur bei Items breiter als 26px
				var html = '<div id="'+divId+'" class="programm-block '+genre+'" title="'+hovertitle+'">';
				html += '<span class="pb-left'+pbLeftSpecial+'"></span>';
				html += '<span class="pb-body" style="width:'+width+'px;"><a href="#" ';
				
				if (running) html += 'class="now" '; // currently running
				//html += 'title="'+hovertitle+'">'+title+'</a></span>';
				if (width < 26) {
					html += '>&nbsp;</a></span>';    
				} else {
					html += '>'+title+'</a></span>';
				}
				html += '<span class="pb-right'+pbRightSpecial+'"></span>';          
				html += '</div>';
				return html;
			}


			/**
			 * Get Content-Layer Data 
			 *          
			 */
			function getAndRenderContentLayerData(externalId, scrollheight) {  			
			  jQuery.get('/epg?extId=' + externalId, {}, function(xml) {                     
          var scheduleItem = createEPGScheduleItemFromXml(xml);
          renderContentLayerData(scheduleItem, scrollheight);          
        });			  
		  }
			

		  function adjustImageSize() {
		    var s = $('#epg-content-tab-image img').attr('src');
		    if (s == '/img/blank.gif') {	
		      $('#epg-content-tab-image img').width(148).height(1).css('visibility', 'hidden');
		      return;
		    }
		    
		    var maxheight = $('#epg-content-tab').height() - 30;		    
			  var h = $('#epg-content-tab-image img').height();					  			  
			  var w = $('#epg-content-tab-image img').width();			  
			  var r = (w > 0) ? (148 / w) : 0;			  
			  var scaledheight= r * h;			  			  
			  if (h <= maxheight && scaledheight < maxheight) {          
          $('#epg-content-tab-image img').width(148).height('auto').css('visibility', 'visible');          
        } else {
          $('#epg-content-tab-image img').width('auto').height(maxheight).css('visibility', 'visible');         
        }		
        
        // IE 6 needs to do it twice to get it right...
        if (/MSIE 6/i.test(navigator.userAgent)) {          
          h = $('#epg-content-tab-image img').height(); 
          w = $('#epg-content-tab-image img').width();        
          r = (w > 0) ? (148 / w) : 0;        
          scaledheight= r * h;
          if (h <= maxheight && scaledheight < maxheight) {
            $('#epg-content-tab-image img').width(148).height('auto').css('visibility', 'visible');          
          } else {
            $('#epg-content-tab-image img').width('auto').height(maxheight).css('visibility', 'visible');         
          }             
        }         
			}
			 
		  
      /**
       * Render Content-Layer Data 
       *          
       */			 
			function renderContentLayerData(scheduleItem, scrollheight) {			
			  var program = scheduleItem.program;			 
			  
        var title = (program.title != undefined) ? program.title : '';
				var episodeTitle = (program.episodeTitle != undefined) ? program.episodeTitle : '';
				var synopsis = (program.synopsis != undefined) ? program.synopsis : '';
				var imgurl = "/img/blank.gif";
				if (program.image && program.image.url && program.image.contentId) {
					imgurl = "/polopoly_fs/" + program.image.contentId + "!" + program.image.url;
				}
				
				$('#epg-content-scroll-pane h4').html(episodeTitle);
				$('#epg-content-scroll-pane p').html(synopsis);
				$('#epg-content-tab-info h4.epg-title').html(title);
				$('#epg-content-tab-image img').load(adjustImageSize);
				$('#epg-content-tab-image img').attr('src', imgurl);				

				// Datum/Uhrzeit
				// TODO: Datum, Sendungsende				
				var datesplit = scheduleItem.startDate.split(' ');  
				$('#epg-content-tab-info h5').html(datesplit[1] + ' Uhr');
				
				if (program.moreLink) {
				  $('#epg-content-tab-link').attr('href', program.moreLink).show();
				} else {
				  $('#epg-content-tab-link').attr('href', '#').hide();
				}
	
				if (program.icons) {
				  var iconHtml = "";				  
				  for (var i=0; i<program.icons.length; i++) {				                
            if (program.icons[i].linkUrl && program.icons[i].iconSrc) {
              iconHtml += '<a href="'+program.icons[i].linkUrl+'"><img src="'+program.icons[i].iconSrc+'" alt=""/></a>';
            }
				  }
				  $('#epg-content-tab-icons').html(iconHtml);
				} else {
				  $('#epg-content-tab-icons').html("");
				}
				
				// (re-)init scrollpane				
				if ($('#epg-content-scroll-pane').parent('.jScrollPaneContainer').size() > 0) {
	        $('#epg-content-scroll-pane').jScrollPaneRemove();
	        $('#epg-content-scroll-pane').jScrollPane({showArrows:true, fixedHeight:scrollheight});
				} else {
				  $('#epg-content-scroll-pane').jScrollPane({showArrows:true, fixedHeight:scrollheight});  
				}
								
				if ($.browser.safari) {				  
				  adjustImageSize();  
				}				
			}


			/**
			 * show and hide program info
			 * 
			 * @return
			 */
			function attachContentLayer(id) {			 
				$('#'+id+" .programm-block").click(function() {				  
					var pbid = $(this).attr("id");
					$('div.programm-block').not($(this)).removeClass("tab tab2");					
					if ($(this).hasClass("tab") || $(this).hasClass("tab2")) {
						// hide layer					  
					  $(this).removeClass("tab tab2");            
						$("#epg-content-tab").hide();
						emptyContentLayer();
					} else {
					  // show layer
					  if (/MSIE 6/i.test(navigator.userAgent)) {          
					    $('#epg-content-tab-image img').width(148).height(1).css('visibility', 'hidden');					    
					  } else {
					    $('#epg-content-tab-image img').width('auto').height('auto').css('visibility', 'hidden');
					  }
					  
					  // determine which row was clicked
					  var rowindex = $('#epg-program-content .programm-col').index($(this).parent());

            // set height and position of layer
					  var openToTop = false;
					  var tabTop;
						var tabHeight;						
						
            if (rowindex == 0) {
              // P7
              tabTop = 115;
              tabHeight = 152;              
            } else { 
              if (shownChannels == 7 && rowindex == 3) {
                openToTop = true;
                tabTop = 84;
                tabHeight = 117;
              } else if (shownChannels == 7 && rowindex == 4) {
                openToTop = true;
                tabTop = 117;
                tabHeight = 119;
              } else {
                tabTop = 138 + (rowindex * 35);
                if (rowindex >= (shownChannels - 4)) {
                  // open to top
                  openToTop = true;
                  tabTop = tabTop - 171;
                }
                tabHeight = 129;
              }              
            }
            
            if (openToTop) {
              $(this).addClass("tab2");
            } else {
              $(this).addClass("tab");              
            }
            
            $("#epg-content-tab").css({'top': tabTop + 'px', 'height': tabHeight + 'px'});                       
						$("#epg-content-tab").show();
												
						getAndRenderContentLayerData(pbid, (tabHeight - 40));      
					}
					return false;
				});    
			}


			 /**
			  * Reset/Empty all values in Content-Layer
			  */
			 function emptyContentLayer() {
         $('#epg-content-scroll-pane h4').html("");
         $('#epg-content-scroll-pane p').html("");
         $('#epg-content-tab-info h4.epg-title').html("");
         $('#epg-content-tab-image img').attr('src', "/img/blank.gif");  
         $('#epg-content-tab-info h5').html("");
         $('#epg-content-tab-link').attr('href', '#').hide();
         $('#epg-content-tab-icons').html("");
			 }			 
			 
			/**
			 * Register Click-Events:
			 *  - Pagesize-Links
			 *  - Layer Close-Button
			 *  - Time-Select
			 */
			function addEvents() {            
				$('.channel-show a').click(function() {
					$('.channel-show a').removeClass('active');
					$(this).addClass('active');
					changePagesize($(this).html());    
					return false;
				});    

				$("a.close").click(function() {
					var pbid = $(".programm-block a").parent().parent().attr("id");
					$('div.programm-block').not("#" + pbid).removeClass("tab tab2");    
					$("#epg-content-tab").hide();
					emptyContentLayer();
					return false;
				});

				$('#div_time_Container .ddn-item').click(function() {
					scrollToHour($('#time').val());
					return false;
				});

				$('#div_genre_Container .ddn-item').click(function() {
					highlightGenre($('#genre').val());
					return false;
				});
			}

			/**
			 * used to update the view after a switch from another view (e.g. vertical)
			 */
			function updateView(dateToShow) {
				if (!dateToShow) dateToShow = $("#epgh-datepicker").datepicker('getDate');
				if (!dateToShow) dateToShow = new Date();

				debug("updating horizontal view for date '"+dateToShow.toDateString()+"'");
				
				// reload program on horizontal view
				loadProgramData(getEPGDateString(dateToShow));
			}
			
			/**
			 * Datepicker-Widget
			 */
			function createDatepicker() {
				// datepicker     
				$("#epgh-datepicker").datepicker({ 
					firstDay: 1,
					prevText: '&lsaquo;', 
					nextText: '&rsaquo;',
					showAnim: 'slideDown',
					monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
					dayNames: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
					positionLeft: 22,
					additionalTop: 2,
					closeIcon: '/img/epg/datepicker_close.gif',
					altField: '#epgh-currentDate',
					dateFormat: 'D, dd.mm.yy',
					onSelect: function(dateText, inst) {
				    if (typeof simTracker != 'undefined') {
				      // track date change request
				      simTracker.track(); 
				    }
					  var dateSelected = jQuery.datepicker._getDate(inst);
					  // hide program info
					  $('#epg-content-tab').hide();
					  // reload program on horizontal view
					  date = getEPGDateString(dateSelected);
					  loadProgramData();
					}
				});
			}
			
			/**
			 * Changes the amount of displayed channels
			 * 
			 * @param size
			 * @return
			 */
			function changePagesize(size) {  
				shownChannels = size;
				endIndex = size;

				// reset view
				$('#epg-content').html('');
		    				
				// Resizing logic
				var baseheight = 315;
				var unitheight = 245;
				var body_add = 7;    
				var f = parseInt(size) / 7;

				// resize main content
				$('.epg .epg-body').css('height', (baseheight + (unitheight * (f-1)) + body_add) + 'px');  
				$('.epg .epg-programm').css('height', (baseheight + (unitheight * (f-1))) + 'px');
				$('.epg-body > .jScrollPaneContainer').css('height', (baseheight + (unitheight * (f-1))) + 'px');

				// resize carousel
				var pagesize = size - 1;  
				var baseheight_carousel_container = 246;
				var baseheight_carousel_clip = 203;  
				$('.jcarousel-container-vertical').css('height', (baseheight_carousel_container + (unitheight * (f-1))) + 'px');
				$('.jcarousel-clip-vertical').css('height', (baseheight_carousel_clip + (unitheight * (f-1))) + 'px');

				epgCarouselInstance.scroll(1, false);
				epgCarouselInstance.options.scroll = pagesize;
				epgCarouselInstance.options.start = 1;
				epgCarouselInstance.options.offset = 1;
				
        // render the desired amount of channels          
        loadProgramData();    
			}


			/**         
			 * Genre selector and highlighting
			 */
			function highlightGenre(genre) {
				//debug("Highlighting: " + genre);
				$('div.programm-block').each( function() { 
					$(this).removeClass("genre");
					if (genre != '' && !$(this).hasClass(genre) ) {
						$(this).addClass("genre"); 
					}
				});
			}


			/**
			 * Scroll view to selected time
			 */
			function scrollToHour(hour) {
				$('.epg-programm')[0].scrollTo(hour * 180);        
			}


			/**
			 * Callback-Function Carousel-Plugin init
			 * 
			 * @param carousel
			 * @param state
			 * @return
			 */
			function carouselInit(carousel, state) {
				epgCarouselInstance = carousel;
			}

			/**
			 * Callback-Function: navigation in channel carousel widget
			 */
			function carouselFirstItem(carousel, item, idx, state) {          
				// reset view
				$('#epg-content').html('');

				// show other channels (amount depending on current pagesize)
				startIndex = idx;
				endIndex = idx + (shownChannels - 1);
				loadProgramData();
			}

			// Init EPG-View
			init();

		});
	}

// ################ epg-vertical ################	
	
	/**
	 * plugin for all functions needed for the epg vertical view
	 */
	$.fn.epgv = function(settings) {
		//TODO: remove this and use the defaults of the epgh-module
		var defaults = {
			displayChannels: new Array('p7','ARD','ZDF', 'tv11', 'kabel1'), 
			p7ChannelId: 'p7',
			channelsToRender: 3
		}
		settings = $.extend({}, defaults, settings);

		return this.each( function () {
			var $this = $(this);

			/** contains the instance of the carousel for all channels */
			var epgvCarousel;
			
			/** contains all channels retrieved from polopoly */
			var allChannels;
			
			/**
			 * Initialize EPG vertical view
			 */
			function init() {
				// TODO loading layer                        
				/*
	            $this.ajaxStart(function(){                                           
	                debug('ajax start');                
	            });

	            $this.ajaxStop(function(){                                           
	                debug('ajax stop');          
	            });
				 */

				createDatepicker();
				
				fillAllChannelCarousel();

			}

			/**
			 * gets all channels from department, renders the channelList and initializes the carousel
			 */
			function fillAllChannelCarousel() {
				// Channelliste + Channeldays abholen
				jQuery.get('/epg?extId=np.epg.department', {}, function(xml) {
					allChannels = createEPGChannelsFromDepartmentXml(xml);
					renderChannelList();

					// create jCarousel widget for displaying channel thumbs
					$('#myhcarousel').jcarousel({
						scroll: settings.channelsToRender,
						initCallback: carouselInit,
						itemFirstInCallback: carouselFirstItem
					});

					updateView(new Date());
					scrollToHour(new Date().getHours());
					
				});
			}
			
			/**
			 * used to update all elements after a switch from horizontal view
			 */
			function updateView(dateToShow) {
				if (!dateToShow) {
					//FIXME: vor some dubious reasons, this doesnt always get the date from the datepicker :/
					dateToShow = $("#epgv-datepicker").datepicker('getDate');
				}
				if (dateToShow) {
					debug("updating vertical view for date '"+dateToShow.toDateString()+"'");
				} else {
					debug("due to some bug, we cannot render the selected date. using 'now'.");
					dateToShow = new Date();
				}
				
				//rerender p7 channel day
				getAndRenderP7Channel(dateToShow);

				//TODO: rerender all other channels too? or should we set the index of the carousel to 1 instead?
				getAndRenderChannels(0, dateToShow);
			}
			
			/**
			 * Datepicker-Widget
			 */
			function createDatepicker() {
				// datepicker     
				$("#epgv-datepicker").datepicker({ 
					firstDay: 1,
					prevText: '&lt;', 
					nextText: '&gt;',
					showAnim: 'slideDown',
					monthNames: ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
					dayNames: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
					positionLeft: 22,
					additionalTop: 2,
					closeIcon: '/img/epg/datepicker_close.gif',
					altField: '#epgv-currentDate',
					dateFormat: 'D, dd.mm.yy',
					onSelect: function(dateText, inst) { 
					  var dateSelected = jQuery.datepicker._getDate(inst);
					  //rerender p7 channel day
					  getAndRenderP7Channel(dateSelected);
					  //TODO: rerender all other channels too? or should we set the index of the carousel to 1 instead?
					  getAndRenderChannels(0, dateSelected);
					}
				});
			}
			
			/**         
			 * Genre selector and highlighting
			 */
			function highlightGenre(genre) {
				//debug("Highlighting: " + genre);
				$('div.programm-block').each( function() { 
					$(this).removeClass("genre");
					if (genre != '' && !$(this).hasClass(genre) ) {
						$(this).addClass("genre"); 
					}
				});
			}

			/**
			 * scroll the vertical view to the current hour as default
			 */
			function scrollToHour(hour) {
				$('#epgv-program')[0].scrollTo(hour*120);			
			}

			/**
			 * Callback-Function Carousel-Plugin init
			 * 
			 * @param carousel
			 * @param state
			 * @return
			 */
			function carouselInit(carousel, state) {
				epgvCarousel = carousel;
			}        

			/**
			 * callback function called by the carousel plugin once it rolls
			 */
			function carouselFirstItem(carousel, item, idx, state) {
				var dateToShow = $("#epgv-datepicker").datepicker('getDate');				

				//debug("carousel callback called, for idx '"+idx+"' state '"+state+"' date to render '"+dateToShow+"'");
				
				getAndRenderChannels(idx-1, dateToShow);
			}
			
			/**
			 * retrieves the channelDays and renders them according to the index set by param
			 * The index corresponds to the index given in the first query of allChannels
			 * (the p7 channel is not rendered here!)
			 */
			function getAndRenderChannels(index, date) {
				// we are to render the channels index to index+channelsToRender, but not more than we got displayChannels
				var renderedChannels = 0;
				for (var i = index; i < settings.displayChannels.length; i++) {                
					//var channel = allChannels[settings.displayChannels[i]];
					var channel = allChannels[settings.displayChannels[i]];
					var parentDivSelector = "";
					if (i == index) {
						parentDivSelector = '.programm-col-first';					
					} else if (i == (index + 1)) {
						parentDivSelector = '.programm-col-center';
					} else if (i == (index + 2)) {
						parentDivSelector = '.programm-col-end';
					}
					
					if (channel && channel.channelId != settings.p7ChannelId) {
						getAndRenderChannel(channel.channelId, date, parentDivSelector, false);
						renderedChannels++;
						if (renderedChannels > settings.channelsToRender) {
							// break out of the function, since we dont want to render any more channeldays
							return;
						}
					}
				}
			}
			
			/**
			 * used to render the p7 channel for a given date
			 * 
			 */
			function getAndRenderP7Channel(date) {
				return getAndRenderChannel(settings.p7ChannelId, date, '.programm-row-pro7', true)
			}
			
			/**
			 * gets the channelday data per ajax and renders it to its according position
			 */
			function getAndRenderChannel(channelId, date, parentDivSelector, forP7) {
				var epgDate = getEPGDateString(date);
				var extid = "np.ct.import.day." + channelId + "." + epgDate; 
				jQuery.get('/epg?extId=' + extid, {}, function(xml) {
					var channelDay = createEPGChannelDayFromXml(xml);
					renderChannelDay(channelDay, parentDivSelector, forP7);
					addEvents();
				});
			}
			
			/**
			 * render the channelDay given for the vertical view
			 * @param channelDay contains the data
			 * @param column tells which column the channelDay is to be rendered.
			 */
			function renderChannelDay(channelDay, parentDivSelector, forP7) {
				if (!parentDivSelector) return;
				var html = "";
				if (channelDay != undefined) {
					for (var i = 0; i < channelDay.scheduleItems.length; i++) {
						html += renderScheduleItem(channelDay.scheduleItems[i], forP7);     
					}
				} else {
//					//TODO: this is for debugging only!
//					debug("the channelday given was null [parentDivSelector='"+parentDivSelector+"']. Rendering dummy program");
//					html += '<div id="dummy" class="programm-block" style="height: 30px">';
//					html += '  <div class="pb-top"/>';	
//					html += '  <div class="pb-body">dummy</div>';
//					html += '  <div class="pb-bottom"/>';
				}
				$(parentDivSelector).html(html);
			}
			
			/**
			 * render a whole programBlock vor the vertical view.
			 * @param item contains the data for the item to render
			 * @param forP7 if true, the item rendered contains additional info for displaying it in the p7-column
			 */
			function renderScheduleItem(item, forP7) {
				var height = item.realDuration * 2;
				var time = item.startDate.split(' ')[1];
				var title = item.program.title;
				var divId = item.program.externalId;
				
				//TODO: what is the corresponding attribute from item?
				var subTitle = 'subTitle';
				
				//TODO: what is the corresponding attribute from item?
				var optionalInfo = 'optionalInfo';
				
				//TODO: how should we format the time correctly? "x h, y min"? "x:yy" ?
				var duration = item.duration + " min";
				
				//TODO: get that info from program.images? the first image? which is the correct one?
				var programImageSrc = '/img/temp/logo-sendung.jpg';

				//TODO: check the requirements
				var toolTip = time + " " + title;
				
				var html = '';
				html += '<div id="'+divId+'" class="programm-block" >';	
				html += '  <div class="pb-top"></div>';
				
				// if the item is too small, display tooltip instead of the text inside
				if (height <= 20) {
					html += '  <div class="pb-body" style="height:'+height+'px; overflow: hidden;" title="'+toolTip+'">';
				} else {
					html += '  <div class="pb-body" style="height:'+height+'px; overflow: hidden;">';
				}
				
				// only display the image for detailed, big items whose image is known 
				if (forP7 && height > 60 && programImageSrc) {
					html += '    <div class="pb-image">';
					html += '      <img height="31" width="59" alt="'+title+'" src="'+programImageSrc+'"/>';
					html += '    </div>';
				}
				
				// small items wont have any text
				if (height > 20) {
					html += '    <div class="pb-info">';
					if (forP7) html += '      <p class="time">'+time+' ';
					html += '        <a href="#">'+title+' ('+duration+')</a>';
					if (forP7) html += '      </p>';
					if (forP7 && subTitle) {
						html += '      <p>'+subTitle+'</p>';
					}
					if (forP7 && optionalInfo) {
						html += '      <p class="optional">'+optionalInfo+'</p>';
					}
					html += '    </div>';
				}
				html += '  </div>';
				html += '  <div class="pb-bottom"></div>';
				html += '</div>';				
				return html;				
			}
			
			/**
			 * retrieves the information for a program, renders the html and shows the detail window
			 */
			function showVerticalDetailView(externalId) {
				$('#vertical-detail').html('');
				jQuery.get('/epg?extId=' + externalId, {}, function(xml) {        	 
					var program = createEPGProgramFromXml(xml);
					renderProgram(program);
				});
			}
			
			/**
			 * renders a program for the vertical info window 
			 */
			function renderProgram(program)  {
				if (program != undefined) {
					var title = (program.title != undefined)?program.title:"";
					var synopsis = (program.synopsis != undefined)?program.synopsis:"";
					var programImgSrc = '/img/epg/dummy-simpsons.jpg';
					var html = "";
					html += '<div class="vd-colLeft">';
					if (programImgSrc) {
						html += '  <div class="vd-image">';
						html += '    <img src="'+programImgSrc+'" width="160" height="90" alt="" />';
						html += '  </div>';
					}
					html += '  <div class="vd-icons">';
					html += '    <a href="#"><img src="/img/icons/icon_info.gif" width="14" height="13" alt="" /></a>';
					html += '    <a href="#"><img src="/img/icons/icon_rss.gif" width="14" height="13" alt="" /></a>';
					html += '  </div>';
					html += '  <div class="vd-links">';
					html += '    <p><a href="#">&gt; Bilder, Infos und mehr</a></p>';
					html += '    <p><a href="#">&gt; Sendung merken</a></p>';
					html += '  </div>';
					html += '</div>';
					html += '<div class="vd-colRight">';
					html += '  <div class="vd-info">';
					html += '    <div class="vd-programm">';
					html += '      <a href="#" class="close"><img src="/img/epg/close-tab.gif" width="20" height="19" alt="" style="float:right;" /></a>';
					html += '      <h4>'+title+'</h4>';
					//TODO: this information is only available for schedule items
					//html += '      <p>03.11.2008 // 20:15 - 20:45</p>';
					html += '    </div>';
					html += '    <div class="vd-content" id="epgv-content-scroll-pane">';
					html += '      <p>'+synopsis+'</p>';
					html += '    </div>';
					html += '  </div>';
					html += '</div>';
					
					$('#vertical-detail').html(html);
					// register function for hiding vertical info
					$("#vertical-detail a.close").click(function () {
					  $("#vertical-detail").hide();
					  return false;
					});
					$('#vertical-detail').show();
				} else {
					debug("program info not found");
				}
			}		
			
			
			/**
			 * assigns the events to dynamically created items (like programm-blocks)
			 */
			function addEvents() {
				// register onclick function for programm-block links
				$(".epg-body-vertical .programm-block a").click(function(e) {
					var parent = $(this).parent().parent().parent().parent(); 
					var pbid = parent.attr("id");
					$('div.programm-block').not("#" + pbid).removeClass("tab");
					if (parent.hasClass("tab")) {
						parent.removeClass("tab");
						$("#vertical-detail").hide();
					} else {
						parent.addClass("tab"); 
						// position the vertical info into the middle of the epg-body-vertical
						var parent = $('.epg-body-vertical');
						var verticalLeft = parent.position().left + ((parent.width()-500)/2);
						var verticalTop = parent.position().top + ((parent.height()-200)/2);
						$("#vertical-detail").css({ left: verticalLeft + 'px', top: verticalTop + 'px'});
						showVerticalDetailView(pbid);
					}
					return false;
				});

				$('#div_time_Container .ddn-item').click(function() {
					scrollToHour($('#time').val());
					return false;
				});

				$('#div_genre_Container .ddn-item').click(function() {
					highlightGenre($('#genre').val());
					return false;
				});

			}
			
			/**
			 * render the channel list 
			 * @param allChannels
			 */
			function renderChannelList() {
				var html = '';    
				for ( var i = 0; i < settings.displayChannels.length; i++) {                
					var channel = allChannels[settings.displayChannels[i]];
					if (channel && channel.channelId != settings.p7ChannelId) {
						var imgSrc = "";
						if (channel.image && channel.image.url && channel.image.contentId) {
							imgSrc = "/polopoly_fs/" + channel.image.contentId + "!" + channel.image.url;
						} else {
							// if we didnt find an image, display a dummy
							imgSrc = "/img/epg/c_kabel1.gif";
						}

						var channelName = "";
						if (channel && channel.name) {
							channelName = channel.name
						} else {
							channelName = '(no info)';
						}
						html += '<li><img src="' + imgSrc + '" width="57" height="26" alt="'+ channelName +'" title="'+channelName+'" /></li>';
						//debug("rendered channel '"+channel.name+"'");
					}
				}
				$('#myhcarousel').html(html);  
			}
			
			// Init vertical EPG-View
			init();        
		});
	}
})(jQuery);

