// scheduler 1.0
if(window.glow) glow.ready(function(){
var setDate = Scheduler.util.date.setISO8601;
var getDate = Scheduler.util.date.toISO8601String;
var cloneDate = Scheduler.util.date.clone;
var today;
var currentDayInView;
var daysViewStart = null;
var daysViewEnd = null;
var currentlySelectedDayElement;
var daysLinkClass = "today";
var returnCallbackForDate = function(date) {
var d = cloneDate( date );
if(Scheduler.debug) console.log("Return callback for date ", date);
return function(evt) {
var el = glow.dom.get(evt.source);
if( el[0].tagName != "LI" && el.parent()[0].tagName == "LI" ) {
el = el.parent();
}
el.addClass(daysLinkClass);
if(currentlySelectedDayElement) currentlySelectedDayElement.removeClass(daysLinkClass);
currentlySelectedDayElement = el;
setDayInView(d);
}
}
var setDaysView = function(start, end) {
daysViewStart = cloneDate(start);
daysViewEnd = cloneDate(end);
}
var setDaysUI = function(dateString, numDaysInAdvance) {
currentlySelectedDayElement = null;
var selector = "#epg-container" + " " + ".days" + " ol";
var daysUIContainer = glow.dom.get(selector);
daysUIContainer.empty();
var currentDate;
if(dateString.constructor == Date) {
currentDate = cloneDate(dateString);
} else {
currentDate = setDate( dateString );
}
if(Scheduler.debug) console.log("Current date: %o", currentDate);
var lastWeekStart = Scheduler.util.date.clone(currentDate);
lastWeekStart.setDate( currentDate.getDate() - numDaysInAdvance);
var nextWeekStart = Scheduler.util.date.clone(currentDate);
nextWeekStart.setDate( currentDate.getDate() + numDaysInAdvance);
var lastWeekEl = glow.dom.create("<li class=\"last-week\">&lt;&lt; Last week | </li>");
if(currentDate.getTime() <= daysViewStart.getTime()) {
} else if( currentDate.getTime() <= today.getTime()) {
} else {
daysUIContainer.append( lastWeekEl );
glow.events.addListener(  lastWeekEl,
"click",
function(evt) {
setDaysUI( lastWeekStart, numDaysInAdvance );
setDayInView(lastWeekStart);
});
}
for(var i = 0; i < numDaysInAdvance; i++) {
var el;
var day =  Scheduler.util.date.getDay(currentDate.getDay(), 3);
var date = currentDate.getDate();
if( currentDate.getTime() == today.getTime() ) {
day = "Today";
} else {
day = day + " " + date;
}
if( currentDate.getTime() <= daysViewEnd.getTime()) {
var classes = "day";
el = glow.dom.create("<li class=\"" + classes + "\"><span>" + day + "</span> | </li>");
daysUIContainer.append( el );
glow.events.addListener(  el,
"click",
returnCallbackForDate( currentDate )
);
}
currentDate.setDate( currentDate.getDate() + 1);
}
var nextWeekEl = glow.dom.create("<li class=\"next-week\">Next week &gt;&gt;</li>");
if(currentDate.getTime() > daysViewEnd.getTime()) {
} else {
daysUIContainer.append( nextWeekEl );
glow.events.addListener(  nextWeekEl,
"click",
function(evt) {
setDaysUI( nextWeekStart, numDaysInAdvance );
setDayInView(nextWeekStart);
});
}
}
var getFirstDayInUI = function(className) {
var selector = "#epg-container" + " " + ".days" + " " + "li.day";
var firstDay = glow.dom.get(selector).slice(0,1);
return firstDay;
}
var setToday = function(date) {
today = cloneDate(date);
}
var setDayInView = function(date) {
if(Scheduler.debug) console.warn("Set day in view: ", date)
if(date.constructor != Date) {
date = setDate(date);
}
Scheduler.util.feed.cancelAll();
epg.showChannelsAsLoading();
var callback  = "?jsoncallback={callback}";
currentDayInView = cloneDate(date);
if(!currentlySelectedDayElement) {
currentlySelectedDayElement = getFirstDayInUI();
currentlySelectedDayElement.addClass(daysLinkClass);
}
var getTimeBoundaries = function(date) {
var startDate = cloneDate(date);
startDate.setHours(4);
var endDate = new Date(startDate);
endDate.setDate( startDate.getDate() + 1);
return {start:startDate, end:endDate};
}
var ensureTwoDigit = function(value) {
if( Number(value) && (value < 10) ) {
return "0" + value;
} else {
return value;
}
}
var createDataLoadedCallback = function(id, epg, serviceName) {
return function(feed) {
var broadcasts = Scheduler.util.aps.simplifyFeed( feed.data.broadcasts, serviceName);
epg.updateChannelData(id, broadcasts);
}
}
var createDataErrorCallback = function(id, epg) {
return function(feed) {
epg.noChannelData(id);
}
}
var day = getTimeBoundaries( date );
epg.setDayTimeBoundaries( day.start, day.end );
var dateInfo = {  year:   date.getFullYear(),
month:  ensureTwoDigit( date.getMonth() + 1 ),
day:    ensureTwoDigit( date.getDate() )
}
var timeViewStart = Scheduler.util.date.clone( date );
timeViewStart.setHours(10);
var timeViewEnd = Scheduler.util.date.clone( date );
timeViewEnd.setHours(16);
epg.setTimeView( timeViewStart, timeViewEnd );
if(channelConfig && channelConfig.length > 0) {
for(var i = 0; i < channelConfig.length; i++) {
var channel = channelConfig[i];
if(channel.data) {
epg.registerChannel( channel );
var feedURL = glow.lang.interpolate( channel.data, dateInfo) + callback;
if(Scheduler.debug) console.log("Feed URL: %o, with data: %o", feedURL, channel.data, dateInfo);
var feed = Scheduler.util.feed.loadFeed( feedURL,
{ success: createDataLoadedCallback(channel.id, epg, channel.label),
error: createDataErrorCallback(channel.id, epg)
});
}
}
}
}
var channelConfig = [
{ id:     "bbcone", label:  "BBC One",
acceptedService: {service:"bbcone", outlet:"london"},
data:   "/feeds/wrapped/bbcone/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "bbctwo", label:  "BBC Two",
acceptedService: {service:"bbctwo", outlet:"england"},
data:   "/feeds/wrapped/bbctwo/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "bbcthree", label:  "BBC Three",
data:   "/feeds/wrapped/bbcthree/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "hd", label:  "BBC HD",
data:   "/feeds/wrapped/bbchd/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "freeview1", label:  "Freeview 1",
data:   "/feeds/wrapped/freeview1/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "freeview2", label:  "Freeview 2",
data:   "/feeds/wrapped/freeview2/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "freeview3", label:  "Freeview 3",
data:   "/feeds/wrapped/freeview3/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "sat1", label:  "Satellite/Cable 1",
data:   "/feeds/wrapped/satelliteandcable1/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "sat2", label:  "Satellite/Cable 2",
data:   "/feeds/wrapped/satelliteandcable2/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "sat3", label:  "Satellite/Cable 3",
data:   "/feeds/wrapped/satelliteandcable3/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "sat4", label:  "Satellite/Cable 4",
data:   "/feeds/wrapped/satelliteandcable4/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "sat5", label:  "Satellite/Cable 5",
data:   "/feeds/wrapped/satelliteandcable5/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"},
{ id:     "sat6", label:  "Satellite/Cable 6",
data:   "/feeds/wrapped/satelliteandcable6/programmes/genres/sport/olympics/schedules/{year}/{month}/{day}.json"}
];
var epg = Scheduler.create("#epg-container");
var startDayForView;
var dateToday = new Date();
if(dateToday.getHours() < 4) {
dateToday.setDate( dateToday.getDate() -  1);
}
dateToday.setHours(1);
dateToday.setMinutes(0);
dateToday.setSeconds(0);
dateToday.setMilliseconds(0);
setToday( dateToday );
var olympicsStart = setDate( "2008-08-06");
var olympicsEnd = setDate("2008-08-24");
setDaysView( olympicsStart, olympicsEnd );
if( dateToday.getTime() < olympicsStart.getTime() ) {
startDayForView = olympicsStart;
} else if ( dateToday.getTime() > olympicsEnd.getTime() ) {
  startDayForView = olympicsEnd;
} else {
startDayForView = dateToday;
}
setDaysUI( startDayForView, 7 );
setDayInView( startDayForView );
});
window.Scheduler = {
debug: false,
create: function(domSelector, args) {
var debug = Scheduler.debug;
if(!domSelector) throw new Exception();
var _showChannelsAsLoading = function() {
for(id in channels) {
if(debug) console.log("Loading message ... ", id)
_displayLoadingMessage(id);
}
}
var _displayLoadingMessage = function(id) {
var selector = base + " " + ".channelrow" + "#" + ns + id + " ol";
var list = glow.dom.get(selector);
if(debug) console.log("Display loading message for ", list, templ.loading, selector);
list.empty();
list.append( templ.loading.clone() );
}
var _displayErrorMessage = function(id) {
var selector = base + " " + ".channelrow" + "#" + ns + id + " ol";
var list = glow.dom.get(selector);
list.empty();
list.append( templ.error.clone() );
}
var _renderAllViews = function() {
if(debug) console.log("Rendering all channels");
for(id in channels) {
if(debug) console.info("Rendering ... ", id)
_renderView(id);
}
}
var _renderView = function(id) {
if(timeView && channels[id] && channels[id].data) {
var filteredBroadcasts = _filterBroadcastsByTime(timeView.start, timeView.end, channels[id].data, true);
var broadcastsInView = _padWithEmptyBroadcasts(timeView.start, timeView.end, filteredBroadcasts);
if(debug) console.log("Broadcasts in view: ", broadcastsInView);
var selector = base + " " + ".channelrow" + "#" + ns + id + " ol";
var list = glow.dom.get(selector);
if(debug) console.log("Render base element: ", selector, list);
list.empty();
var TOTAL_BROADCAST_DURATION = 0;
for(var i = 0; i < broadcastsInView.length; i++) {
var b = broadcastsInView[i];
var bDuration = b.duration;
var durationCheck = (b.end.getTime() - b.start.getTime()) / 1000;
if(bDuration != durationCheck) {
if(debug) console.log("Duration check failed (given: %o vs actual: %o). Using: %o", bDuration, durationCheck, durationCheck);
bDuration = durationCheck;
}
if(debug) console.log("Start/end conditions: ", i, broadcastsInView.length - 1, b.start, b.end, timeView.end, (b.end > timeView.end) );
if( b.start.getTime() < timeView.start.getTime() && b.end.getTime() > timeView.end.getTime()) {
bDuration = ( timeView.end.getTime() - timeView.start.getTime() ) / 1000;
if(debug) console.log("Programme spans view. Altering duration to : ", bDuration);
} else if( (i == 0) && (b.start < timeView.start) ) {
bDuration = ((b.duration * 1000) - (timeView.start.getTime() - b.start.getTime())) / 1000;
} else if( (i == (broadcastsInView.length - 1)) && (b.end > timeView.end) ) {
bDuration = ((b.duration * 1000) - (b.end.getTime() - timeView.end.getTime())) / 1000;
if(debug) console.log("Programme ends after view. Altering duration to : ", bDuration);
}
if(bDuration <= 0) {
bDuration = 60;
}
var width = Math.floor( pxPerMin * (bDuration / 60) );
bEpisode = "";
if(!b.isEmpty) bEpisode = b.episode.title;
TOTAL_BROADCAST_DURATION += bDuration;
var el = function() {
if(b.isEmpty === true) {
return _createEmptyProgElementFromBroadcast(b);
} else {
return _createProgElementFromBroadcast(b, width);
}
}();
el.css("width", width + "px");
list.append( el );
}
}
}
var _renderHoursUI = function(start, end) {
if(earlierLinkListenerIds.length > 0) {
for(var i = 0; i < earlierLinkListenerIds.length; i++) {
glow.events.removeListener(earlierLinkListenerIds[i]);
}
}
if(laterLinkListenerIds.length > 0) {
for(var i = 0; i < laterLinkListenerIds.length; i++) {
glow.events.removeListener(laterLinkListenerIds[i]);
}
}
var hoursSelector = base + " " + ".head";
var hoursUIContainers = glow.dom.get(hoursSelector);
var createTimeViewCallbackWithOffset = function(hoursOffset) {
var newStartDate = _cloneDate( start );
newStartDate.setHours( start.getHours() + hoursOffset );
var newEndDate = _cloneDate( end );
newEndDate.setHours( end.getHours() + hoursOffset );
return function(evt) {
if(evt.source.tagName == "LI") {
evt.stopPropagation();
_setTimeView( newStartDate, newEndDate, true );
}
}
}
var getOffset = function(date, hoursOffset) {
var newDate = _cloneDate(date);
return newDate.setHours( date.getHours() + hoursOffset );
}
hoursUIContainers.each( function(i) {
var hoursUIContainer = glow.dom.get(this);
var timeElements = hoursUIContainer.get("li");
var currentHour = _cloneDate( start );
timeElements.each( function(i) {
if(this.className == "time" || this.className == "timeend") {
var convertedHour = Scheduler.util.date.to12Hour(currentHour);
this.innerHTML = convertedHour.hour + convertedHour.period;
currentHour.setHours( currentHour.getHours() + 1);
}
});
var earlierLink = hoursUIContainer.get(".earlier");
var laterLink   = hoursUIContainer.get(".later");
if(dayView.start <= getOffset(start, -6)) {
earlierLink.removeClass("disabled");
var earlierLinkListenerId = glow.events.addListener(  earlierLink,
"click",
createTimeViewCallbackWithOffset(-6) );
earlierLinkListenerIds.push(earlierLinkListenerId);
} else {
earlierLink.addClass("disabled");
}
if(dayView.end >= getOffset(end, 6)) {
laterLink.removeClass("disabled");
var laterLinkListenerId = glow.events.addListener(  laterLink,
"click",
createTimeViewCallbackWithOffset(6) );
laterLinkListenerIds.push(laterLinkListenerId);
} else {
laterLink.addClass("disabled");
}
});
}
var _createProgElementFromBroadcast = function(broadcast, widthHint) {
var pxPerChar = 9;
var ellipsisCharWidth = 2;
var charsToDisplay = (widthHint / pxPerChar) - ellipsisCharWidth;
var startTime = Scheduler.util.date.to12Hour(broadcast.start);
var endTime   = Scheduler.util.date.to12Hour(broadcast.end)
var data = {
progName: widthHint ? Scheduler.util.text.truncate(broadcast.episode.display_titles.title, charsToDisplay) : broadcast.episode.display_titles.title,
progSub:  widthHint ? Scheduler.util.text.truncate(broadcast.episode.title, charsToDisplay) : broadcast.episode.title,
progTime: broadcast.start,
progDayMonth: Scheduler.util.date.getDay(broadcast.start.getDay()) + " " + broadcast.start.getDate(),
progFullTitle:  broadcast.episode.title,
progFullBrand:  broadcast.episode.display_titles.title || "",
progService:    broadcast.service,
progStartTime:  startTime,
progEndTime:    endTime,
progSummary:    broadcast.episode.short_synopsis,
progEpisodePID: broadcast.episode.pid };
var el = glow.dom.create( glow.lang.interpolate(templ.prog, data) );
return el;
}
var _createEmptyProgElementFromBroadcast = function(broadcast) {
var el = glow.dom.create( templ.prog );
el.empty();
el.addClass(ns + "empty");
return el;
}
var _filterBroadcastsByTime = function(start, end, data, insertEmptyBroadcasts) {
var broadcastsInView = [];
if(debug) console.info("View:: ", start, end)
var numBroadcasts = data.length;
for(var i = 0; i < numBroadcasts; i++) {
var inView = false;
var isAcceptedOutlet = true;
var broadcast = data[i];
var broadcastStart = broadcast.start;
var broadcastEnd   = broadcast.end;
if(broadcastStart >= start && broadcastEnd <= end) {
if(debug) console.log("In view: ", broadcast, broadcastStart, broadcastEnd, Number(broadcastStart), Number(broadcastEnd));
inView = true;
} else if( broadcastStart < start && broadcastEnd <= end && broadcastEnd > start ) {
if(debug) console.log("In view [starts before]: ", broadcast, broadcastStart, broadcastEnd);
inView = true;
} else if( broadcastStart >= start && broadcastEnd > end && broadcastStart < end ) {
if(debug) console.log("In view [end after]: ", broadcast, broadcastStart, broadcastEnd, start, end);
inView = true;
} else if( broadcastStart < start && broadcastEnd > end ) {
if(debug) console.log("In view [spans view]: ", broadcast, broadcastStart, broadcastEnd);
inView = true;
} else {
if(debug) console.log("Out of view: ", broadcast, broadcastStart, broadcastEnd);
}
isAcceptedService = _checkIsAcceptedService(broadcast);
if(isAcceptedService && inView) broadcastsInView.push(broadcast);
}
return broadcastsInView;
}
var _checkIsAcceptedService = function(broadcast) {
var serviceKey;
var serviceOutletKey;
var isAccepted = true;
if(broadcast.source && broadcast.source.service && broadcast.source.service.key) {
serviceKey = broadcast.source.service.key;
}
if(acceptedServiceMap[serviceKey]) {
serviceOutletKey = acceptedServiceMap[serviceKey];
isAccepted = false;
if(broadcast.source && broadcast.source.service && broadcast.source.service.outlets) {
var outlets = broadcast.source.service.outlets;
for(var i = 0; i < outlets.length; i++) {
var outlet = outlets[i];
if(outlet.key && outlet.key == serviceOutletKey) {
isAccepted = true;
break;
}
}
}
}
return isAccepted;
}
var _padWithEmptyBroadcasts = function(start, end, broadcasts) {
var paddedBroadcastList = [];
if(debug) console.log("broadcasts for padding ", broadcasts)
for(var i = 0; i < broadcasts.length; i++) {
var b = broadcasts[i];
if(i==0 && b.start.getTime() > start.getTime()) {
paddedBroadcastList.push( _createEmptyBroadcastObject(start, b.start) );
}
paddedBroadcastList.push( b );
if( i != broadcasts.length-1) {
var bNext = broadcasts[i+1];
if( b.end.getTime() <= end.getTime() && b.end.getTime() != bNext.start.getTime() ) {
paddedBroadcastList.push( _createEmptyBroadcastObject(b.end, bNext.start) );
}
} else {
if( b.end.getTime() < end.getTime() ) {
paddedBroadcastList.push( _createEmptyBroadcastObject(b.end, end) );
}
}
}
if(broadcasts.length == 0) {
if(debug) console.log("Empty broadcast list");
var hoursIncrement = 1;
var progStart = _cloneDate( start );
var progEnd   = _cloneDate( start );
progEnd.setHours( progStart.getHours() + hoursIncrement );
var howManyProgs;
if( end.getDate() > start.getDate() ) {
howManyProgs = 6;
} else {
howManyProgs = end.getHours() - start.getHours() / hoursIncrement;
}
if(debug) console.log(howManyProgs);
for( var i = 0; i < howManyProgs; i++) {
paddedBroadcastList.push( _createEmptyBroadcastObject(progStart, progEnd) );
progStart.setHours( progStart.getHours() + 1);
progEnd.setHours( progEnd.getHours() + 1 );
}
}
return paddedBroadcastList;
}
var _doesBroadcastOverlap = function(b1, b2) {
var b1s = b1.start.getTime();
var b1e = b1.end.getTime();
var b2s = b2.start.getTime();
var b2e = b2.end.getTime();
if( (b1s >= b2s) && (b1s <= b2e) && (b1s < b2e) && (b1e > b2s) ) {
if(debug) console.log("Scenario A", b1.episode.pid, b2.episode.pid);
return true;
}
if( (b1s <= b2s) && (b1e <  b2e) && (b1s < b2e) && (b1e > b2s) ) {
if(debug) console.log("Scenario B", b1.episode.pid, b2.episode.pid);
return true;
}
if( (b1s >  b2s) && (b1e >= b2e) && (b1s < b2e) && (b1e > b2s) ) {
if(debug) console.log("Scenario C", b1.episode.pid, b2.episode.pid);
return true;
}
if( (b1s <= b2s) && (b1e >= b2e) && (b1s < b2e) && (b1e > b2s) ) {
if(debug) console.log("Scenario D", b1.episode.pid, b2.episode.pid);
return true;
}
return false;
}
var _checkForBroadcastOverlaps = function(broadcasts) {
var nonOverlappingBroadcasts = [];
for(var i=0; i < broadcasts.length; i++) {
if( i != (broadcasts.length - 1 )) {
var b1 = broadcasts[i];
var b2 = broadcasts[i+1];
if(_doesBroadcastOverlap(b1, b2)) {
if(debug) console.warn("Broadcasts overlap: ", b1, b2);
} else {
nonOverlappingBroadcasts.push(b2);
}
} else {
}
}
return nonOverlappingBroadcasts;
}
var _setTimeView = function(start, end, shouldRender) {
if(start && end) {
var shouldRender = shouldRender ? true : false;
var s = _cloneDate(start);
var e = _cloneDate(end);
timeView = { start:s, end:e };
_renderHoursUI(s, e);
if(shouldRender) _renderAllViews();
}
}
var _setDayTimeBoundaries = function(start, end) {
if(start && end) {
var s = _cloneDate(start);
var e = _cloneDate(end);
dayView = {start:s, end:e};
}
}
var _getTimeView = function() {
return timeView;
}
var _createEmptyBroadcastObject = function(start, end) {
var duration = (end.getTime() - start.getTime()) / 1000;
return {  start: _cloneDate(start),
end: _cloneDate(end),
duration: duration,
isEmpty:true
}
}
var _getTemplBySelector = function(s, mode) {
var el = glow.dom.get(s);
if(el.length > 0 && mode == "raw") {
return el.html();
} else if(el.length > 0) {
return glow.dom.create( el.html() );
} else {
return null;
}
}
var _elementForInteraction = function(el) {
var el = glow.dom.get(el);
var candidate = null;
if( el[0].tagName != "LI" && el.parent()[0].tagName == "LI" ) {
el = el.parent();
}
if( el[0].tagName == "LI" &&
el.hasClass( "prog" ) &&
!el.hasClass( ns + "empty" ) ) {
candidate = el;
}
return candidate;
}
var _openSummary = function(el, xy) {
var listEl    = glow.dom.get(el);
var summaryContent = el.get("." + ns + "prog-detail");
if(summaryContent.length > 0) {
var bodyWidth = glow.dom.get("body").width();
var diff = (bodyWidth - containerWidth) / 2;
var boxWidth = popupBoxWidth;
var listElWidth = listEl.width();
var listElHeight = listEl.height();
var listElOffset = listEl.offset();
var positionX = listElOffset.x - diff + 20;
if( (positionX + boxWidth) > containerWidth ) {
var a = containerWidth - positionX;
var b = boxWidth - a;
positionX -= b;
positionX -= 20;
}
var positionY = listElOffset.y + 5;
summaryContent.css("position", "absolute");
summaryContent.css("top", positionY + "px");
summaryContent.css("left", positionX + "px");
summaryContent.css("display", "block");
return summaryContent;
} else {
return null;
}
}
var _initialise = function() {
if(debug) console.info("Initialise new EPG...");
serviceNameBoxWidth = glow.dom.get(base + " " + ".channel").css("width").slice(0, -2);
glow.events.addListener( base + " " + ".schedule",
interactionEventType,
function(evt) {
var el = _elementForInteraction(evt.source);
if( glow.dom.get(evt.source).parent().hasClass(ns + "prog-detail") ) return;
if( el ) {
if(currentlyHighlightedElement) currentlyHighlightedElement.removeClass("hili");
if(currentlyOpenElement) currentlyOpenElement.css("display", "none");
currentlyHighlightedElement = el;
el.addClass("hili");
currentlyOpenElement = _openSummary(el, {x:evt.pageX, y:evt.pageY} );
} else {
if(currentlyHighlightedElement) currentlyHighlightedElement.removeClass("hili");
if(currentlyOpenElement) currentlyOpenElement.css("display", "none");
}
})
}
var _cloneDate = Scheduler.util.date.clone;
var args = args || {};
var viewWidth = 660;
var viewHours = 6;
var viewMins = viewHours * 60;
var pxPerMin = (viewWidth / viewMins) ;
var serviceNameBoxWidth = 0;
var popupBoxWidth = 216;
var containerWidth = glow.dom.get(".centerbody").width();
var acceptedServiceMap = {}
var channels  = {};
var timeView  = null;
var dayView = null;
var earlierLinkListenerIds = [];
var laterLinkListenerIds = [];
var base      = domSelector;
var ns        = args.namespace || "epg-";
var interactionEventType = "mouseover";
var currentlyHighlightedElement = null;
var currentlyOpenElement = null;
var templ = {};
templ.loading     = _getTemplBySelector(base + " " + "#" + ns + "templ-loading");
templ.error       = _getTemplBySelector(base + " " + "#" + ns + "templ-error")
templ.prog        = _getTemplBySelector( base + " " + "#" + ns + "templ-prog", "raw");
templ.progDetail  = _getTemplBySelector( base + " " + "#" + ns + "templ-prog-detail" );
var self = this;
_initialise();
return {
setTimeView: function(start, end, shouldRender) {
if(shouldRender) {
_setTimeView(start, end, true);
} else {
_setTimeView(start, end, false);
}
},
setDayTimeBoundaries: function(start, end) {
_setDayTimeBoundaries(start, end);
},
registerChannel: function(obj) {
if(obj && obj.id ) {
channels[obj.id] = {id: obj.id};
if(obj.acceptedService) acceptedServiceMap[obj.acceptedService.service] = obj.acceptedService.outlet;
_displayLoadingMessage(obj.id);
}
},
updateChannelData: function(id, data){
if(Scheduler.debug) console.log("Updating channel data: ", id, data);
if(id && channels[id]) {
channels[id].data = data;
_renderView(id);
}
},
noChannelData: function(id) {
if(id && channels[id]) {
_displayErrorMessage(id);
}
},
showChannelsAsLoading: function() {
_showChannelsAsLoading();
}
}
}
};
Scheduler.util = Scheduler.util || {};
Scheduler.util.date = function() {
return {
clone: function(date) {
return new Date( date.getTime() );
},
getDay: function(dayOfWeek, truncate) {
var days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var day = days[dayOfWeek];
if(truncate) {
return day.slice(0, truncate);
} else {
return day;
}
},
to12Hour : function(date) {
var hour = date.getHours();
var result = { hour: null, min: Scheduler.util.text.zeroPad(date.getMinutes()), period: null };
if(hour > 12) {
result.period = "pm";
result.hour   = hour - 12;
} else if (hour == 12) {
result.period = "pm";
result.hour   = 12;
} else if (hour == 0) {
result.period = "am";
result.hour   = 12;
} else {
result.period = "am";
result.hour   = hour;
}
result.toString = function() {
return result.hour + "." + result.min + result.period;
}
return result;
},
setISO8601 : function (string) {
var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
"(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
"(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
var d = string.match(new RegExp(regexp));
var offset = 0;
var date = new Date(d[1], 0, 1);
if (d[3]) { date.setMonth(d[3] - 1); }
if (d[5]) { date.setDate(d[5]); }
if (d[7]) { date.setHours(d[7]); }
if (d[8]) { date.setMinutes(d[8]); }
if (d[10]) { date.setSeconds(d[10]); }
var colons = null;
if(d[6]) colons = d[6].match(/:/g);
if (d[12] && colons && colons.length == 3) {
date.setMilliseconds(Number("0." + d[12]) * 1000);
} else if (d[12] && colons && colons.length == 2){
offset = (Number(d[12]) * 60);
offset *= ((d[11] == '-') ? 1 : -1);
} else if (d[14]) {
offset = (Number(d[16]) * 60) + Number(d[17]);
offset *= ((d[15] == '-') ? 1 : -1);
}
offset -= date.getTimezoneOffset();
time = (Number(date) + (offset * 60 * 1000));
var dateObj = new Date();
dateObj.setTime(Number(time));
return dateObj;
},
toISO8601String : function (format, offset, inputDate) {
if (!format) { var format = 6; }
if (!offset) {
var offset = 'Z';
var date = inputDate;
} else {
var d = offset.match(/([-+])([0-9]{2}):([0-9]{2})/);
var offsetnum = (Number(d[2]) * 60) + Number(d[3]);
offsetnum *= ((d[1] == '-') ? -1 : 1);
var date = new Date(Number(Number(inputDate) + (offsetnum * 60000)));
}
var zeropad = function (num) { return ((num < 10) ? '0' : '') + num; }
var str = "";
str += date.getUTCFullYear();
if (format > 1) { str += "-" + zeropad(date.getUTCMonth() + 1); }
if (format > 2) { str += "-" + zeropad(date.getUTCDate()); }
if (format > 3) {
str += "T" + zeropad(date.getUTCHours()) +
":" + zeropad(date.getUTCMinutes());
}
if (format > 5) {
var secs = Number(date.getUTCSeconds() + "." +
((date.getUTCMilliseconds() < 100) ? '0' : '') +
zeropad(date.getUTCMilliseconds()));
str += ":" + zeropad(secs);
} else if (format > 4) { str += ":" + zeropad(date.getUTCSeconds()); }
if (format > 3) { str += offset; }
return str;
}
}
}();
Scheduler.util.aps = function() {
return {
simplifyFeed: function(broadcasts, service) {
var service = service || null;
var processed = [];
var returnDataForProg = function(progObj) {
var extracted = { type: null, title: null, pid: null };
if(progObj.type)            extracted.type  = progObj.type;
if(progObj.pid)             extracted.pid   = progObj.pid;
if(progObj.title)           extracted.title = progObj.title;
return progObj;
}
var len = broadcasts.length;
for(var i = 0; i < len; i++) {
var b = broadcasts[i];
var types = { episode: {}, series: {}, brand: {} };
if(b.programme) {
var firstLevel = returnDataForProg(b.programme);
types[firstLevel.type] = firstLevel;
}
if(b.programme && b.programme.programme) {
var secondLevel = returnDataForProg(b.programme.programme);
types[secondLevel.type] = secondLevel;
}
if(b.programme && b.programme.programme && b.programme.programme.programme) {
var thirdLevel = returnDataForProg(b.programme.programme.programme);
types[thirdLevel.type] = thirdLevel;
}
var o = { start:    Scheduler.util.date.setISO8601(b.start),
end:      Scheduler.util.date.setISO8601(b.end),
duration: b.duration,
episode:  types["episode"],
series:   types["series"],
brand:    types["brand"],
service:  service,
source:   b
}
processed.push( o );
}
return processed;
}
}
}();
Scheduler.util.feed = function() {
var _createFeedLoader = function(source, success, error) {
var feed = {  source: source,
isLoaded: false,
data: null
}
var timeoutId = window.setTimeout( function() {
if(!feed.isLoaded) {
delete _feeds[source];
error(feed);
}
}, _timeout );
glow.net.loadScript(  source,
function(data) {
if(_feeds[source]) {
delete _feeds[source];
feed.data = data;
feed.isLoaded = true;
success(feed);
}
});
feed.cancel = function() {
if( _feeds[source] ) {
window.clearTimeout( timeoutId );
delete _feeds[source];
}
}
return feed;
}
var _loadFeed = function(source, args) {
var success = args["success"] || function() {};
var error = args["error"] || function () {};
if( _feeds[source] ) {
} else {
_feeds[source] = _createFeedLoader( source, success, error );
}
return _feeds[source];
}
var _feeds = {};
var _timeout = 30 * 1000;
return {
loadFeed: function(source, args) {
return _loadFeed(source, args);
},
setTimeout: function( timeInSecs ) {
_timeout = timeInSecs * 1000;
},
cancelAll: function() {
for(i in _feeds) {
_feeds[i].cancel();
}
}
}
}();
Scheduler.util.text = {
truncate: function(str, to, delim) {
if(str == null || to < 1) return "";
var delim = delim || "&hellip;";
var result = str;
if(str.length > to) {
result = str.slice(0, to) + delim;
}
return result;
},
zeroPad: function (num) {
return ((num < 10) ? '0' : '') + num;
}
}
