﻿// Global Variables
var _datafile = {};                 // data file location & parameters
var _ui = {};                       // ui elements
var _playlist_data = {};            // data set for current song
var _currPlaylist = new Array(); 	// working playlist of songs
var _baseURLs = {};                 // base urls
var _updateInterval = 30;           // update interval in seconds for fetching new songs
var _sessionTimeLimit = 2;          // how long to keep songs on page in hours
var _sessionCommentTimeLimit = 5;   // update interval in minutes for getting comment updates
var _session = {};                  // keep track of session stats
var _adframe = 'paste_adframe'; 			// id of the top ad iframe
var _updatedList = new Array(); 	// Array of updated song objects
var _counter = 0;

// Global Vars for Storing Styles
var _styleCookieName = "kexp_playlist";
var _styleCookieDuration = 30;

// *********************************************************************
// 100 - Main Driver
// *********************************************************************
window.onload = function() {
    try {

        // Debugging tools
        _ui.Debug = $('debug');  	// which div to display debug info
        _ui.DebugFlag = false;      // change to false if you don't want debug visable

        // set data location and any parameters for single song service
        _datafile.url = '/s/s.aspx';
        _datafile.params = 'x=1';

        // set data location and any parameters for playlist service
        _datafile.url_playlist = '/playlist/playlistservice.aspx';
        _datafile.params_playlist = '';

        // set accss to ui objects & other static info
        _ui.Tracks = $('tracks'); 		// tell me where current tracks are
        _ui.NewTracks = $('newtracks'); 	// tell me where to put new tracks
        _ui.ShowInfo = $('show'); 		// tell me where to put Show & DJ info
        _ui.PlayList = $('showblock');     // tell me where the whole playlist block is

        // hide XML first
        _ui.PlayList.hide();

        // URLs used by this data center
        _baseURLs.page = 'playlist.aspx';
        _baseURLs.djProfile = '/aspnet_client/get_dj_archive.aspx?djs=';
        _baseURLs.djEmail = '/about/email.asp?email=dj';
        _baseURLs.buyImg = '/images/btn_buy.gif';
        _baseURLs.djImg = '/s/r.aspx?t=1&id=';

        // Record when the user first logged in
        _session.Start = new Date();

        // record the number of calls for data
        _playlist_data.callcount = 0;

        // default date for the currently displayed playlist is now
        _playlist_data.date = new Date();

        // keep track of the number of tracks on the page for when 
        // we need to drop them from the bottom of the stack
        _ui.TrackDropCount = 0;

        // get any query string from the URL
        _ui.qs = document.URL.toQueryParams();

        // update the styles on the current page
        updateStyles();

        // update the form as well
        updateForm();

        // initial scrub of UI on page
		runOnceStyles();

		$('tracks').show();
		$('showblock').show();
		
        // fix the escaped HTML characters in Tracks
        var children = _ui.Tracks.childElements();

        // clean the html in all child nodes
        HTMLparse(children);

        if (_ui.qs.t == null) {
            // get new data from indicated url page & update target div
            // create an object to search and hold song tracks
            oGetSong();

			$('nextLink').hide();
			$('nextLink2').hide();
			
            // wait how ever long as defined in _updateInterval and do it again
            new PeriodicalExecuter(oGetSong.bindAsEventListener(oGetSong), _updateInterval);

        } else {

            // query string request

            // validate the requested date & time
            // returns false if the requested date is the same as now
            var isValid = checkDate(_ui.qs.month, _ui.qs.day, _ui.qs.year, _ui.qs.hour);

            if (isValid) {

                // update form
                updateInputForm(document.getElementById("month"), _ui.qs.month);
                updateInputForm(document.getElementById("day"), _ui.qs.day);
                updateInputForm(document.getElementById("year"), _ui.qs.year);
                updateInputForm(document.getElementById("hour"), _ui.qs.hour);

                // save the display list's date
                _playlist_data.date = new Date(_ui.qs.year - 0, _ui.qs.month - 0 - 1, _ui.qs.day - 0, _ui.qs.hour - 0, 0, 0);

                // write the show info
                writeShow();

                // display next link on form
                $('nextLink').show();
                $('nextLink2').show();

            } else {
                getPage(_baseURLs.page);
            }
        }

        // show after reformating data
        _ui.PlayList.setStyle({ display: 'block' });

        // get styles from cookie if found
        //set_style_from_cookie();

    } catch (e) {
        if (_ui.DebugFlag) {
            debugUpdate('window.onload', e);
        }
    }
}


    // *****************************************************************
    function updateStyles() {
        try {
            // clear styles for all
            clearStyles();

			// style odd tracks
            $$('div#tracks ul > li:nth-child(odd)').each(function(s) {
                var n = s.down('dl');
				if (n.hasClassName('airbreak'))
					s.addClassName('airbreak_odd');		
				else
					s.addClassName('odd');
            });

            // style even tracks
            $$('div#tracks ul > li:nth-child(even)').each(function(s) {
				var n = s.down('dl');
				
				if (n.hasClassName('airbreak'))
					s.addClassName('airbreak_even');		
				else
					s.addClassName('even');
				
            });
					
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('updateStyles',e);
			}		
        }
    }
    // *****************************************************************
    function clearStyles() {

		try {
			// clear all styles for tracks
	        $$('div#tracks ul > li').each(function(s) {
	            s.removeClassName('even');
	            s.removeClassName('odd');
	            s.removeClassName('first');
				s.removeClassName('airbreak_even');
	            s.removeClassName('airbreak_odd');
	            s.removeClassName('airbreak_first');
	        });

	        // clear the style for top track
	        $$('div#tracks ul > li:first-child').each(function(s) {
	            s.removeClassName('even');
	            s.removeClassName('odd');
	            s.removeClassName('first');
				s.removeClassName('airbreak_even');
	            s.removeClassName('airbreak_odd');
	            s.removeClassName('airbreak_first');
	        });

	        // clear style for new track
	        $$('div#newtracks ul > li').each(function(s) {
	            s.removeClassName('even');
	            s.removeClassName('odd');
	            s.removeClassName('first');
				s.removeClassName('airbreak_even');
	            s.removeClassName('airbreak_odd');
	            s.removeClassName('airbreak_first');
	        });
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('clearStyles',e);
			}		
		}
    }
    // *****************************************************************
    function updateForm() {
        
       try {
            // find the form we need to update
            var curDateTime = new Date();

            // get current hour
            var hour = curDateTime.getHours();

            // get current date
            var month = curDateTime.getMonth() + 1;
            var year = curDateTime.getYear();
            var day = curDateTime.getDate();

            // convert date by casting
            if (day < 10) day = "" + day;
            if (month < 10) month = "" + month;
            if (year < 1000) year += 1900;

            // IDEA: it would be good if we checked to see if the values are different 
            // first before updating
            updateInputForm(document.getElementById("month"), month);
            updateInputForm(document.getElementById("day"), day);
            updateInputForm(document.getElementById("year"), year);
            updateInputForm(document.getElementById("hour"), hour);
			
			// save the date & time
            
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('updateForm',e);
			}								
        }
    }
    // *****************************************************************
    function updateInputForm(element, value) {

        try {
			// update the form
			for (var i = 0; i < element.options.length; i++) {
                if (element.options[i].value == value) {
                    element.options[i].selected = true;
                    break
                }
            }
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('updateInputForm',e);
			}		
        }
    }
	
    // *****************************************************************
    function runOnceStyles() {
		var cl = 0;
		// updates the styles of the on-page data during the window's first load
        try {
			if(_counter === 0){
			//console.log("************ Running runOnceStyles " + _counter++ + " times");

            // clean up styles based on exsistance of a DJ comment
            $$('div#tracks dl > dd.djcomments').each(function(s) {

                if (s.innerHTML.length <= 0) {

                    // fix dj comment styles
                    s.addClassName('hide');
                    s.previous(0).addClassName('hide');

                    s.removeClassName('djcomments');
                    s.previous(0).removeClassName('djcomments');

                    var dl = s.next(3).childElements();
                    dl[0].addClassName('noComment');
                } else {
                    var dl = s.next(3).childElements();
                    dl[0].addClassName('isComment');	
					var str = new String(s.textContent);
					s.textContent = makeLink(str);
                }
            });
		
			// update DJ Comment label
			$$('div#tracks dl > dt.djcomments').each(function(s) {
				
				getShowFromPage();
				//s.innerHTML = (_playlist_data.showDJ != null) ? _playlist_data.showDJ : 'KEXP DJ';  
				s.innerHTML = (_playlist_data.showDJ.empty()) ? 'KEXP DJ' :  _playlist_data.showDJ;  
				s.innerHTML +=  ' says. . . ';
            });
			
            // fix styles for label
            $$('div#tracks dl > dd.label').each(function(s) {
                if (s.innerHTML.length > 0) {
                    s.addClassName('Plabel')
                } else {
                    s.removeClassName('Plabel')
                }
            });

            //fix content for buy
            //$$('div#tracks dl > dd.buy').each(function(s) {
            $$('div#tracks ul.playlist dl.play dd.song dl > dd.buy').each(function(s) {

                //if (s.innerHTML != "" || s.innerHTML != 0) {
                if (s.innerHTML == "1" && s.previous(5).innerHTML != "KEXP Events Calendar") {
					if(s.previous(1).innerHTML == "Live at KEXP Volume Five"){
						s.innerHTML = '<a href="/cd/" onClick="javascript:urchinTracker(\'/livevol5\');" title="Buy Live Volume 5 Now!"><img border="0" src=\"' + _baseURLs.buyImg + '\" alt="Buy Live Volume 5!" /></a>';
					} else {

						//var artist = (s.previous(5).innerHTML.empty()) ? "Unknown Artist" : new String(s.previous(5).innerHTML); 
						var artist = new String(s.previous(5).innerHTML); 
						var title = new String(s.previous(3).innerHTML);
						var album = new String(s.previous(1).innerHTML);

						var buyHTMLcode = '<img onmouseout="delayhidemenu()" onmouseover="dropdownmenuEX(this, event, menu1, \'140px\', '
										+ '\'' + escapeHTMLFix(artist) + '\', '
										+ '\'' + escapeHTMLFix(album) + '\', '
										+ '\'' + escapeHTMLFix(title) + '\')"'
										+ ' src=\"' + _baseURLs.buyImg + '\" alt="Buy!" />';

						s.innerHTML = buyHTMLcode;
					}
                } else {
                    s.innerHTML = "";
                } 
            });

			//$$('div#tracks dl > dd.releaseyear').each(function(s) {
			$$('div#tracks ul.playlist li dl.play dl > dd.releaseyear').each(function(s) {
				if ((s.innerHTML !== "")&&(s.innerHTML.indexOf('Released:') === -1 )) s.innerHTML = "Released: " + s.innerHTML;
			});
			$$('div#tracks dl > dd.label').each(function(s) {
				if ((s.innerHTML !== "")&&(s.innerHTML.indexOf('(') === -1)) s.innerHTML = "(" + s.innerHTML + ")";
			});
			
			// create alternate styles
			updateStyles();

            // style new tracks
            if ($$('div#newtracks ul')[0].innerHTML.length > 0) {
			
                $$('div#newtracks ul > li').each(function(s) {
                    s.removeClassName('odd');
					
					var n = s.down('dl');
					if (n.hasClassName('airbreak')) {
						s.removeClassName('airbreak_odd');
						s.addClassName('airbreak_first');		
					} else {
						s.addClassName('first');
					}
                });
                                
            } else {
                
                // or style top track
                $$('div#tracks ul > li:first-child').each(function(s) {
                    s.removeClassName('odd');
					
					var n = s.down('dl');
					if (n.hasClassName('airbreak')) {
						s.removeClassName('airbreak_odd');
						s.addClassName('airbreak_first');		
					} else {
						s.addClassName('first');
					}
                });
            }
            			
			// get first track info and update title of page
			if ((_ui.qs.t == null) && ($$('div#tracks ul > li > dl')[0].innerHTML.length > 0)) {			
				
				var time = $$('dd.time')[0].innerHTML;
				var song = $$('dd.songtitle')[0].innerHTML;
				var artist = ($$('dd.artist')[0].innerHTML.empty()) ? "Unknown Artist" : $$('dd.artist')[0].innerHTML;
				var album = $$('dd.album')[0].innerHTML;
				
				// Update Title
				document.title = 'KEXP.ORG NOW PLAYING: ' 
					/*+  time + ' - ' +*/ + artist + ' - \"' + song + '\" - ' + album;
				
			}			
			_counter++; }		
		} catch (e) { 
			if (_ui.DebugFlag) {
				debugUpdate('runOnceStyles',e);
			}		
        }
    
    }	
	//******************************************************************
	function getShowFromPage() {
			
		// Grab show info from page
		//<s>
		//<i>1</i>
		//<t>6AM - 10AM</t>
		//<n>Variety Mix</n>
		//<nf>The Afternoon Show is Fond of You</nf>
		//<d>Cheryl Waters</d>
		//<di>283</di>
		//</s>
		
		try {
			// get the dj show node from page
			var baseNode = $('show').childElements();
			var showNode = baseNode[0].childElements();	
			var hasDJData = false;
			
			if (showNode != null  && baseNode[0].innerHTML != '') {

				_playlist_data.showID = new String(showNode[0].innerHTML);
				_playlist_data.showTime = new String(showNode[1].innerHTML);
				_playlist_data.showName = new String(showNode[2].innerHTML);
				_playlist_data.showFriendlyName = new String(showNode[3].innerHTML);
				_playlist_data.showDJ = new String(showNode[4].innerHTML);
				_playlist_data.showDJID = new String(showNode[5].innerHTML);  
				
				hasDJData = true;
			}
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('getShowFromPage',e);
			}
			hasDJData = false;
		}
		
		return hasDJData;
	}
	
    // *****************************************************************
    function HTMLparse(element) {

        try {
            // recursive parsing - go thru each node regardless of how deep the nesting
            // and fix escaped html

            element.each(function(node) {

                if ((node.innerHTML.length > 0) &&
                    (node.nodeName == 'dd' || node.nodeName == 'DD') &&
                    (node.innerHTML != null  || node.innerHTML != '')) {

                    if (node.hasClassName('song')) {
                        var childNode = node.childElements();
                        HTMLparse(childNode);
                    } else {
                        if ((node.hasClassName('djcomments') || node.hasClassName('artist') ||
                         node.hasClassName('songtitle') || node.hasClassName('album'))) {

                            // if its a comment, artist, song title, or album fix the html
                            var strHTML = tracksHTMLFix(node);
                            node.innerHTML = strHTML;

                            // DEBUGGING
                            // alert('Now fixing node :: ' + node.nodeName + " :: " + node.innerHTML);
                            return;
                        }
                    }
                } else {

                    var childNode = node.childElements();
                    if (childNode != null  || childNode.innerHTML != null  || childNode.innerHTML.length > 0) {
                        HTMLparse(childNode);
                    } else {
                        return;
                    }

                }
            });

        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('HTMLCleanup',e);
			}		
        }
        
    }
    // *****************************************************************
    function tracksHTMLFix(extendedElement) {

        try {

            if (extendedElement.innerText) {
                // for IE
                var strHTML = unescapeHTMLFix(extendedElement.innerText);    
            } else {
                // everything else
                 var strHTML = unescapeHTMLFix(extendedElement.innerHTML);
            }

            return strHTML;
    			
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('tracksHTMLFix',e);
			}		
        }    
    }	

    // *****************************************************************
	// 200 - Playlist Data Fetch & Format Functions
    // *****************************************************************
    var oGetSong = function getNewSong() {

		// request new song data from XML service
	
		try {
	        // set options
	        var oOptions = {
	            method: 'GET',
	            parameters: _datafile.params,
	            onSuccess: parseAjaxResponse,
	            onFailure: function() {
					if (_ui.DebugFlag) {
						debugUpdate('oGetSong',e);
					}
	            }
	        }

	        // update the page
	        new Ajax.Request(_datafile.url, oOptions);	
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('oGetSong',e);
			}
		}
    }
    // *****************************************************************
    function parseAjaxResponse(transport){

		// once data is in hand, begin parsing the response object, in this case
		// we are expecting XML formatted data
	
        try {
            
            if ((transport.responseXML == null || transport.responseXML.childNodes[0] == null) &&
                transport.responseText != null  ) {
                transport.responseXML = toXML(transport.responseText);
            }
            
            // store the xml data
            var response = transport.responseXML;

            // get the root of the xml
            var docRoot = response.getElementsByTagName('k')[0];

            // parse the data from xml
            parseSongData(docRoot, 't');
            parseShowData(docRoot, 's');

            // update page
            oUpdate();

        } catch (e) {   
			if (_ui.DebugFlag) {
				debugUpdate('parseAjaxResponse',e);
			}
        }
    }
    // *****************************************************************
    function toXML(text) {
            
        try {
			
			//Internet Explorer
            var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.async = "true";
            xmlDoc.loadXML(text);
			
        } catch(e) {
		
            //Firefox, Mozilla, Opera, etc.
            try {
            
				parser = new DOMParser();
				var xmlDoc = parser.parseFromString(text, "text/xml");
            
			} catch(e) {
    			_ui.Debug.innerHTML += '<p>toXML: ' + e + ' -- ' + e.message + '</p>';
    			var xmlDoc = null;
			}
        }
        
        return xmlDoc;
    }	
	// *****************************************************************
    function parseSongData(parentnode, childTag) {
        
		// parse the XML tags for the song and store
		
		try {
	        _playlist_data.songID = new String(parseChildNodes(parentnode,childTag,'p',0));
	        _playlist_data.songartist = new String(parseChildNodes(parentnode,childTag,'r',0));
	        if (_playlist_data.songartist.empty()) { _playlist_data.songartist = "Unknown Artist" };
	        _playlist_data.songtitle = new String(parseChildNodes(parentnode,childTag,'s',0));
	        _playlist_data.songalbum = new String(parseChildNodes(parentnode,childTag,'a',0));
	        _playlist_data.songtime = new String(parseChildNodes(parentnode,childTag,'t',0));
	        _playlist_data.songcomment = new String(parseChildNodes(parentnode,childTag,'c',0));
	        _playlist_data.songbuy = new String(parseChildNodes(parentnode,childTag,'b',0));
	        _playlist_data.songlabel = new String(parseChildNodes(parentnode, childTag, 'l', 0));
	        _playlist_data.releaseyear = new String(parseChildNodes(parentnode, childTag, 'ry', 0));
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('parseSongData',e);
			}
		}
    }
    // *****************************************************************
    function parseShowData(parentnode, childnode, nodeSet) {
	
		// parse the data for the show and store in to vars
	
		try {
	        _playlist_data.showID = new String(parseChildNodes(parentnode,childnode,'i',1));
	        _playlist_data.showTime = new String(parseChildNodes(parentnode,childnode,'t',1));
	        _playlist_data.showName = new String(parseChildNodes(parentnode,childnode,'n',1));
	        _playlist_data.showFriendlyName = new String(parseChildNodes(parentnode,childnode,'nf',1));
	        _playlist_data.showDJ = new String(parseChildNodes(parentnode,childnode,'d',1));
	        _playlist_data.showDJID = new String(parseChildNodes(parentnode,childnode,'di',1));    
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('parseShowData',e);
			}		
		}
    }
    // *****************************************************************
    function parseChildNodes(node, childTag, childChildTag, nodeSet){
        
		// parse each node for data and return a string value	
		var results = [];
        
        try{
            var children = $A(
                node.getElementsByTagName(childTag)[nodeSet].getElementsByTagName(childChildTag)
            );

            results = children.collect(
                function(s){
					return s.firstChild.data;
                }
            );

        } catch (e) {
            // couldn't find data inside node
            results = [''];			
            var msg = e + node + ' ' + childTag + ' ' + childChildTag + ' ' + nodeSet + '</p>';
			
			if (_ui.DebugFlag) {
				debugUpdate('parseChildNodes',msg);
			}		
        }
        return results;
    }
	
    // *****************************************************************
    function writeShow() {

		// write DJ and Show to the page
		// NOTE:  rewrite this at some point to be faster
	
        try {
			
			var djURL = '';
			var djImg = '';
			var djLine = '';
			var showLine = '';
			var djreqLine = '<b><a href=\"' + _baseURLs.djEmail + '\">DJ Requests</a></b><br />';
			var hasDJData = false;
				
			// check if DJ & Show data exsists
            if ( _playlist_data.showDJ == undefined || _playlist_data.showDJ == null || _playlist_data.showDJ.length <= 0) {
				hasDJData = getShowFromPage();				
            } else {
				hasDJData = true;
			}
			
			if (hasDJData) {
			
				// apperently not all DJs have an ID
				if (_playlist_data.showDJID.empty()) {
					djImg = '';	
					djLine = '<span class=\"djname\"><b>' + _playlist_data.showDJ + '</b></span><br />';
				} else {
					djURL = _baseURLs.djProfile + _playlist_data.showDJID;				
					djImg = '<img src=\"' + _baseURLs.djImg + _playlist_data.showDJID + '\" class=\"djImg\" />';				
					djLine = '<span class=\"djname\"><a href=\"' + djURL + '\">' + _playlist_data.showDJ + '</a></span><br />';
				}
				
				showLine = '<span class=\"showname\">';
				showLine += (_playlist_data.showFriendlyName.empty()) ? _playlist_data.showName : _playlist_data.showFriendlyName;
				showLine += '</span><br />';
				djreqLine = '<b><a href=\"' + _baseURLs.djEmail + '\">DJ Requests</a></b><br />';
			}
			
			var date = '<span class=\"today\">' + getDateTimeDOWStr(_playlist_data.date) + '</span><br />';
			

            var DJShowHTML = '<div class=\"ShowDJInfo\">' + 
				djImg + date + 
				showLine + djLine + 
				djreqLine + '</div> <br />';
				
            _ui.ShowInfo.innerHTML = DJShowHTML;

			
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('writeShow',e);
			}
        }        
    }

    // *****************************************************************
    var oUpdate = function updatePage() {

		// update the current page with the new data
	
        try {
            // inside this subroutine for the first time
            if (_playlist_data.callcount === 0) {
                writeShow();
			}

            // track the number of calls
            _playlist_data.callcount++;

            // check to see if the new data is the same as latest data from current playlist
            // don't update if
            //   a) if the new song is already in the current playlist found in "newtracks"
            //   b) if the new song is already in the current playlist found in "tracks"
            //   c) if the new song is null
            if (_playlist_data.songID == null ||
                _ui.NewTracks.innerHTML.include(_playlist_data.songID) ||
                _ui.Tracks.innerHTML.include(_playlist_data.songID)) {

                // if a match is found do nothing

                // DEBUGGING: message updates
				if (_ui.DebugFlag) {
					
					var oDate = new Date();

	                var msg = '<p>NOTHING FOUND OR MATCH FOUND, DON\'T UPDATE :: Time '
								+ oDate.toLocaleTimeString() + ' :: Interval ' + _updateInterval + 'sec :: SongID '
	                            + _playlist_data.songID + ' :: Call# ' + _playlist_data.callcount
	                            + ' :: DropTracksTime ' + _sessionTimeLimit + 'hour'
	                            + '</p>';
								
					debugUpdate('oUpdate',msg);
				}
				
            } else {

				// copy current song to array of songs
				var index = _currPlaylist.length;
				var tempPlaylist = Object.clone(_playlist_data);
				_currPlaylist[index] = tempPlaylist;
			
				// update styles
				updateStyles();
				
				// insert new song
				writeSong();
				
				// Slide Down Window effect on new song
				Effect.BlindDown('newtracks');
				
				// move song to main track list
				setTimeout('moveTrack()', 30000);
								
				// update the show
				writeShow();

				// update the playlist form to current date and time
				updateForm();
				
				// drop off old songs at the bottom
				dropCheck();	
	
				// Update ad
				// updateAd(); disabled 2009-08-08
				
				// check for comment updates for songs
				getSongUpdate();

				// DEBUGGING: message updates
				if (_ui.DebugFlag) {
					
					var oDate = new Date();

					var msg = '<p>FOUND A NEW SONG! :: Time '
                                + oDate.toLocaleTimeString() + ' :: Interval ' + _updateInterval + 'sec :: SongID  '
                                + _playlist_data.songID + ' :: Call# ' + _playlist_data.callcount
                                + ' :: DropTracksTime ' + _sessionTimeLimit + 'hour'
                                + '</p>';
								
					debugUpdate('oUpdate',msg);
				}
            }
			
	        // keep track of the session times 
	        _session.End = new Date();
	        _session.Elapsed = _session.End.getTime() - _session.Start.getTime();
	        _session.HoursElapsed = Math.floor(_session.Elapsed / 1000 / 60 / 60);
	        _session.MinutesElapsed = Math.floor(_session.Elapsed / 1000 / 60);
	        _session.SecondsElapsed = Math.floor(_session.Elapsed / 1000);

		 	// DEBUGGING: message updates
			if (_ui.DebugFlag) {
				
				var oDate = new Date();

				var msg = '<div>Time Elapsed in Hours: ' + _session.HoursElapsed + '</div>';
		        msg += '<div>Time Elapsed in Minutes: ' + _session.MinutesElapsed + '</div>';
		        msg+= '<div>Time Elapsed in Seconds: ' + _session.SecondsElapsed + '</div>';
		        msg += '<div>Time Elapsed in Milliseconds: ' + _session.Elapsed + '</div>';
							
				debugUpdate('oUpdate',msg);
			}
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('oUpdate',e);
			}
        }
    }
    // *****************************************************************
    function writeSong() {
		
		// write the new song to the page
	
        try {
            // build html
            
			// <dl class="play">
			// <dt class="djcomments">DJ Comment</dt>
			// <dd class="djcomments">Sat 2/21 @Neumos, @KEXP 3PM</dd>
			// <dt class="playid">PlayID</dt>
			// <dd class="playid">1073281</dd>
			// <dt class="song">Song</dt>
			// <dd class="song">
			// </dd>
			// </dl>

            var playlistHTML = '<li class=\"first\"><dl class=\"play\">';
			
            // build dj comment block html
            if (_playlist_data.songcomment != '') {
                playlistHTML += '<dt class=\"djcomments\">';
				
				/*if (_playlist_data.showDJ == null || _playlist_data.showDJ == '')
					playlistHTML += 'KEXP DJ';
				else
					playlistHTML += _playlist_data.showDJ;*/
					
				playlistHTML = (_playlist_data.showDJ.empty()) ? "KEXP DJ" : _playlist_data.showDJ;

				_playlist_data.songcomment = unescapeHTMLFix(_playlist_data.songcomment)
				playlistHTML += ' says. . . </dt><dd class=\"djcomments\">' + makeLink(_playlist_data.songcomment) + '</dd>';				
				playlistHTML += '<dt class=\"playid\">PlayID</dt><dd class=\"playid\">' + _playlist_data.songID + '</dd>';					
                playlistHTML += '<dt class=\"song\">Song</dt><dd class=\"song\"><dl class=\"isComment\">';
            } else {	
				playlistHTML += '<dt class=\"hide\">DJ Comment</dt><dd class=\"hide\"/>';
				playlistHTML += '<dt class=\"playid\">PlayID</dt><dd class=\"playid\">' + _playlist_data.songID + '</dd>';					
                playlistHTML += '<dt class=\"song\">Song</dt><dd class=\"song\"><dl class=\"noComment\">';
            }
            
            // build song def data
            playlistHTML += '<dt class=\"time\">Time</dt><dd class=\"time\">' + _playlist_data.songtime + '</dd>'
			
            playlistHTML += '<dt class=\"artist\">Artist</dt><dd class=\"artist\">';
			playlistHTML += (_playlist_data.songartist.empty()) ? "Unknown Artist" : _playlist_data.songartist.unescapeHTML();
            playlistHTML += '</dd><dt class=\"songtitle\">Song Title</dt><dd class=\"songtitle\">' + _playlist_data.songtitle.unescapeHTML() + '</dd>';

            if (_playlist_data.songalbum != '') {
                playlistHTML += '<dt class=\"album\">Album</dt><dd class=\"album\">' + _playlist_data.songalbum.unescapeHTML() + '</dd>'
            }

			// NOTE: hot spot is off by a few pixles
			// CSS for 'buy' pop up menue needs to be tweeked
            if (_playlist_data.songbuy != '' || _playlist_data.songbuy != 0) {

			var buyHTMLcode = '<img onmouseout="delayhidemenu()" onmouseover="dropdownmenuEX(this, event, menu1, \'140px\', '
                                + '\'' + escapeHTMLFix(_playlist_data.songartist) + '\', '
                                + '\'' + escapeHTMLFix(_playlist_data.songalbum) + '\', '
                                + '\'' + escapeHTMLFix(_playlist_data.songtitle) + '\')\"'
                                + ' src="' + _baseURLs.buyImg + '" alt="Buy!" />';

                playlistHTML += '<dt class="buy">Buy</dt><dd class="buy">' + buyHTMLcode + '</dd>'
            }			
			
            if (_playlist_data.releaseyear != '') {
                playlistHTML += '<dt class=\"releaseyear\">Release Year</dt><dd class=\"releaseyear\">Released: ' + _playlist_data.releaseyear.unescapeHTML() + '</dd>'
            }

            if (_playlist_data.songlabel != '') {
                playlistHTML += '<dt class=\"label Plabel\">Label</dt><dd class=\"label\">(' + unescapeHTMLFix(_playlist_data.songlabel) + ')</dd>';
            }
            
            // closing tags
            playlistHTML += '</dd></dl></li>';          

			// insert html
			var datalist = _ui.NewTracks.childElements();
			datalist[0].insert({ 'top': playlistHTML });
			
			// Update Title
			document.title = 'KEXP.ORG NOW PLAYING: ' 
				//+  getTime(_playlist_data.date)
				+ _playlist_data.songartist + ' - \"' + _playlist_data.songtitle
				+ '\" - ' + _playlist_data.songalbum;

        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('writeSong',e);
			}
        }
        
    }
    // *****************************************************************
	function makeLink(str) {
		
		// If comment has a link, make it so
		// NOTE: for later featuer make sure that google analytics tracks
		// the click throughs		
		
		var w = new Array();
		w = str.split(' ');
		for (var i=0; i < w.length; i++) {
			var s = w[i];
			if ((s.indexOf("http://",0) == 0) || (s.indexOf("www.",0) == 0)) {
				
				if (s.indexOf("http://",0) == 0) { 
					s = s.substring(7);
				}
				
				w[i] = "<a target=\"new\" href='http://" + s + "'>" + s + "</a>";
			}
		}
		// alert(w.join(' '));
		return(w.join(' '));
	}	
    // *****************************************************************
    function moveTrack() {

        // once a new song is found, move the last new song to the primary
		// track list
    
        try {

            // save New Track's children and return them as an array of extended elements.

			// newtracks > ul > li > dl
			// get ul from newtracks
            var NewTrackChildren = _ui.NewTracks.childElements();   

			// get li
			listData = NewTrackChildren[0].childElements();

			// DEBUGGING: tell me what is inside the current track
			if (_ui.DebugFlag) {
				listData.each(function(node) {
					alert('movePreviousNewTrack :: ' + node.nodeName + ' :: ' + node.innerHTML + ':: ' + node.innerHTML.length);
				});
			}
				
            // make sure that newtracks list data isn't empty
			if (listData[0] != null) {

                // get children of Tracks
                var TracksChildren = _ui.Tracks.childElements();

                // create new list item & insert string as the FIRST CHILD of element
                TracksChildren[0].insert({ 'top': '<li class=\"first\">' + listData[0].innerHTML + '</li>'});

                // update new tracks div
                _ui.NewTracks.innerHTML = '<ul class=\"playlist\" />';

				// increase count of tracks
                _ui.TrackDropCount++;
				
            } else {
                // DEBUGGING: message updates
                // alert('msg from updatePage: html is empty - ' + strHTML);
                _ui.Debug.innerHTML += '<p>NO SONGS MOVED :: childNodes=' + _ui.NewTracks.childNodes.length + '</P>';
            }
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('movePreviousNewTrack',e);
			}
        }
    }
    // *****************************************************************
    function dropCheck() {

        // Add a song then drop a song after two hours
        try {

            // verify that the user has been on the page for the alloted time
            // change this as needed
            //  _session.SecondsElapsed
            //  _session.MinutesElapsed
            //  _session.HoursElapsed
            
            if (_session.HoursElapsed >= _sessionTimeLimit) {
            
                // Check to see if this is our first run through.
                // set up last track pointer & track drop counter if:
                // 1) LastTrack pointer is null
                // 2) and if the tags holding the tracks are not null nor empty
                if (_ui.LastTrack == null && _ui.Tracks.lastChild != null ) {
                    
                    if (_ui.Tracks.lastChild.lastChild != null ) {
                        // point last track to actual last track in the list
                        _ui.LastTrack = _ui.Tracks.lastChild.lastChild;

                        // set the track drop counter up for count down to zero
                        _ui.TrackDropCount = _ui.Tracks.lastChild.childNodes.length - 1;

                        // DEBUGGING
						if (_ui.DebugFlag) {
							var msg = '<P>FOUND TRACKS TO DROP :: ' + _ui.TrackDropCount + '</P>';
							debugUpdate('dropCheck',msg);
						}		
                    } else {

                        // DEBUGGING
						if (_ui.DebugFlag) {
							var msg = '<P>NO TRACKS TO LEFT!</P>';                    
							debugUpdate('dropCheck',msg);
						}		
                    }
                }

                if (_ui.LastTrack != null ) {
					dropLastTrack();
                } else {
					// DEBUGGING
					if (_ui.DebugFlag) {
						var msg = '<P>_ui.LastTrack is null</P>';                    
						debugUpdate('dropCheck',msg);
					}		
                }
            }
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('dropCheck',e);
			}		
        } 
    }
    // *****************************************************************
    function dropLastTrack() {

        try {
            // set the tag to empty
            _ui.LastTrack.innerHTML = '';

            // point to old track
            var oldTrack = _ui.LastTrack;
           
            // push to next track
            if (_ui.LastTrack.previousSibling != null ) {
                _ui.LastTrack = _ui.LastTrack.previousSibling;
            } else {
                _ui.LastTrack = null;
            }
            
            // remove it
            _ui.Tracks.lastChild.removeChild(oldTrack);

            // increment the drop count
            _ui.TrackDropCount--;

            // no more tracks to drop reset counter
            if (_ui.TrackDropCount < 0) {
                _ui.TrackDropCount = 0;
            }           
            
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('dropLastTrack',e);
			}		
        }
    }	
    // *****************************************************************
    function updateAd() {
        
       try {
			// get ad from iframe id
			var f = document.getElementById(_adframe);
			// reload
			f.src = f.src;
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('updateAd',e);
			}								
        }
    }
	// *****************************************************************
    function getSongUpdate() {
	
		// this polls the XML playlist service for updated information
	
		try {
		
			var oOptions = {
				method: 'GET',
				parameters: _datafile.params_playlist,
				onSuccess: updateSongs,
				onFailure: function() {
						if (_ui.DebugFlag) {
							debugUpdate('getSongUpdate',e);
						}
		            }
		    }
			
			new Ajax.Request(_datafile.url_playlist, oOptions);

		
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('getSongUpdate',e);
			}		
		}
	}
	// *****************************************************************
    function updateSongs(transport) {
	
		// once the data is in hand, parse the data, update the web page, 
		// and format the new content
	
		try {
					
			if ((transport.responseXML == null || transport.responseXML.childNodes[0] == null) &&
	                transport.responseText != null  ) {
	            transport.responseXML = toXML(transport.responseText);
	        }
			
			// store the xml data
			var response = transport.responseXML;

			// get the root of the xml
			var playlist = response.getElementsByTagName('playlist')[0];
			var plays = playlist.getElementsByTagName('plays')[0];

			// store a list of updated current songs			
			for (i = 0; i < plays.childNodes.length; i++) {
				var song = plays.childNodes[i];
				
				var p = song.getElementsByTagName('p')[0];   	// play id number
				var s = song.getElementsByTagName('s')[0];		// song title
				var a = song.getElementsByTagName('a')[0];		// album title
				var ry = song.getElementsByTagName('ry')[0];		// release year
				var r = song.getElementsByTagName('r')[0];		// artist
				var l = song.getElementsByTagName('l')[0];		// publisher label
				var t = song.getElementsByTagName('t')[0];		// time
				var c = song.getElementsByTagName('c')[0];		// comment
				var b = song.getElementsByTagName('b')[0];		// buy flag
				var u = song.getElementsByTagName('lu')[0];		// last updated
				
				if (song != null && song.textContent != "" && u != null && u.textContent != "") { 
					var num = parseInt(p.textContent);
					
					var tmp = {};
					
					tmp.update = u.textContent;
					tmp.comment = c.textContent;
					tmp.title = s.textContent;
					tmp.artist = r.textContent;
					tmp.album = a.textContent;
					tmp.release = ry.textContent;
					tmp.label = l.textContent;
					tmp.buy = b.textContent;
					tmp.time = t.textContent;
					
					// check if the item already exisits
					if (_updatedList[num] == null) {
					
						// flag to indicate that the item has been used to update page contgent
						// not used = 0; used = 1;			
						// item is new, add it to the list		
						tmp.used = 0;			
						_updatedList[num] = tmp;
					} else {
						// check the last update
						if (_updatedList[num].update != tmp.update) {
							// its an updated item
							tmp.used = 0				// reset used flag
							_updatedList[num] = tmp;	// update the content
							
						} // else leave it alone
					} // end if
				} // end if
			} // end if
			
			// update the html and reformat by redefining the class names
			$$('div#tracks dl > dd.playid').each(function(s){
				
				// go thru the nodes and check the content
				// if the item exsists in the list and if it hasn't been used then update
				var index = s.innerHTML * 1;
				
				if (_updatedList[index] != null && _updatedList[index].used == 0) {
					
					// update html in the parent node of this current node
					var parent = s.parentNode;
					
					// update parent content
					parent.outerHTML = songToHTML(_updatedList[index], index);

					// gotta put it in a div so that opacity works
					var grand = parent.parentNode;
					var tmpHTML = grand.innerHTML;
					var html = '<div>' + tmpHTML + '</div>';
					grand.setStyle({opacity: 1});
					grand.innerHTML = html;
					
					// fade in with new content
					new Effect.Opacity(
						grand,
						{ from: 0, to: 1, duration: 1, queue: 'front'}
					);

					// update the used flag to equal 1
					 _updatedList[index].used = 1;
					 
					 // after were done with special effects remove from div
					 grand.innerHTML = tmpHTML;
					
				} // end if
				
			}); 
					
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('updateSongs',e);
			}		
		}
	}
	// *****************************************************************
    function songToHTML(oSong, ID) {
		
		// write the new song to the page
		// assumes that oSong is an object with properties of a aired song	
        try {
            // build html
            var songHTML = '<dl class=\"play\">';
			
            // build dj comment block html
            if (oSong.comment != null && oSong.comment != '') {
                songHTML += '<dt class=\"djcomments\">';
				
				/* 2nd comment out if (_playlist_data.showDJ == null || _playlist_data.showDJ == '')
					songHTML += 'KEXP DJ';
				else
					songHTML += _playlist_data.showDJ; */
				songHTML += (_playlist_data.showDJ.empty()) ? "KEXP DJ" : "SongToHTML" + _playlist_data.showDJ;
				
				oSong.comment = unescapeHTMLFix(oSong.comment);
				songHTML += ' says. . .</dt><dd class=\"djcomments\">' + makeLink(oSong.comment) + '</dd>';				
				songHTML += '<dt class=\"playid\">PlayID</dt><dd class=\"playid\">' + ID + '</dd>';					
                songHTML += '<dt class=\"song\">Song</dt><dd class=\"song\"><dl class=\"isComment\">';
            } else {	
				songHTML += '<dt class=\"hide\">DJ Comment</dt><dd class=\"hide\"/>';
				songHTML += '<dt class=\"playid\">PlayID</dt><dd class=\"playid\">' + ID + '</dd>';					
                songHTML += '<dt class=\"song\">Song</dt><dd class=\"song\"><dl class=\"noComment\">';
            }
            
            // build song def data
            songHTML += '<dt class=\"time\">Time</dt><dd class=\"time\">' + oSong.time + '</dd>'
			
            songHTML += '<dt class=\"artist\">Artist</dt><dd class=\"artist\">';
			songHTML += (oSong.artist.empty()) ? "Unknown Artist" : oSong.artist.unescapeHTML();
            songHTML += '</dd><dt class=\"songtitle\">Song Title</dt><dd class=\"songtitle\">' + oSong.title.unescapeHTML() + '</dd>';

            if (oSong.album != '') {
                songHTML += '<dt class=\"album\">Album</dt><dd class=\"album\">' + oSong.album.unescapeHTML() + '</dd>'
            }

			// NOTE: hot spot is off by a few pixles
			// CSS for 'buy' pop up menue needs to be tweeked
            //if (oSong.buy != '' || oSong.buy != 0) {
            if (oSong.buy === 1) { 

				var buyHTMLcode = '<img onmouseout="delayhidemenu()" onmouseover="dropdownmenuEX(this, event, menu1, \'140px\', '
                                + '\'' + escapeHTMLFix(oSong.artist) + '\', '
                                + '\'' + escapeHTMLFix(oSong.album) + '\', '
                                + '\'' + escapeHTMLFix(oSong.title) + '\')\"'
                                + ' src="' + _baseURLs.buyImg + '" alt="Buy!" />';

                songHTML += '<dt class="buy">Buy</dt><dd class="buy">' + buyHTMLcode + '</dd>'
            }

            
			if (oSong.releaseyear != '') {
				songHTML += '<dt class=\"releaseyear\">Release Year</dt><dd class=\"releaseyear\">Released: ' + unescapeHTMLFix(oSong.releaseyear) + '</dd>';
			} else {
				songHTML += '<dt class=\"releaseyear\">Release Year</dt><dd class=\"releaseyear\" style=\"background-color: red;\">Not Released: ' + unescapeHTMLFix(oSong.releaseyear) + '</dd>';
			}
			
            if (oSong.songlabel != '') {
                songHTML += '<dt class=\"label Plabel\">Label</dt><dd class=\"label\">(' + unescapeHTMLFix(oSong.label) + ')</dd>';
            }

            // closing tags
            //songHTML += '</dd></dl>';     
            songHTML += '</dl>';     

			return songHTML;

        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('songToHTML',e);
			}
        }
        
    }

   // *****************************************************************
    function unescapeHTMLFix(html) {

        // the casting done from saving into and from a prototype extended String
        // and a document node, allows for the escaped HTML to be decoded
    
        try {

             var temp = document.createElement("div");
            temp.innerHTML = html;

            if (temp.innerText) {
                // for IE
                var strHTML = temp.innerText;
            } else {
                // everything else
                var strHTML = temp.textContent;
            }
            
            temp.removeChild(temp.firstChild)
            return strHTML;

        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('unescapeHTMLFix',e);
			}		
            return null;
        }
    }
	
	// *****************************************************************
    function escapeHTMLFix(html) {
	
		// this will escapeHTML
	
		try {
		
			var str = new String(html);
			str = str.escapeHTML();
			str = str.gsub(/'/, '%27');
		
			return str;
				
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('escapeHTMLFix',e);
			}		
			
			return html;
		}	
	}
	
	// *****************************************************************
    function getPage(fullPath) {
		
		try {
            // reload page URL
			window.location.href = fullPath;
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('getPage',e);
			}
		}
	}
	
	// *****************************************************************
    function debugUpdate (funcName, e) {
		_ui.Debug.setStyle({display: 'inline'});
		_ui.Debug.innerHTML = '<p>' + funcName + ' :: ' + e + '</p>';
	    alert(funcName + ' :: ' + e);
	}


// *********************************************************************
// Playlist Data Fetch & Format Functions
// *********************************************************************
	
	// *****************************************************************
	function previousList(path) {
		
		// take user back 1 hour from currently displayed list
		
		try {
		
			// use date object to generate valid date by casting.
			// if the date generated is invalid try catch will deal with the error
			var tmpDate = _playlist_data.date;
			var h = _playlist_data.date.getHours() - 1;
			tmpDate.setHours(h);
		
			h = tmpDate.getHours();
			var d = tmpDate.getDate();
			var m = tmpDate.getMonth()+1;
			var y = tmpDate.getFullYear();
			
			// build paramiters
			path = path + '?' + 't=1' + '&year=' + y + '&month=' + m + '&day=' + d + '&hour=' + h;				
			
			getPage(path);			
		
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('previousList',e);
			}
		}
	}

	// *****************************************************************
	function nextList(path) {
	
		// take user forward 1 hour from currently displayed list	
	
		try {
		
			// use date object to generate valid date by casting.
			// if the date generated is invalid try catch will deal with the error
			var tmpDate = _playlist_data.date;
			var h = _playlist_data.date.getHours() + 1;
			tmpDate.setHours(h);
		
			h = tmpDate.getHours();
			var d = tmpDate.getDate();
			var m = tmpDate.getMonth()+1;
			var y = tmpDate.getFullYear();
			
			// build paramiters
			var now = getCurrentDate();
			
			if ( h != now.hour) {
				path = path + '?' + 't=1' + '&year=' + y + '&month=' + m + '&day=' + d + '&hour=' + h;								
			}
			
			getPage(path);			
		
		} catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('nextList',e);
			}
		}
	}

    // *****************************************************************
    function getListByDateForm(path) {
		
		// get the date and time from the form and load that playlist
	
        try {

            // get and validate year
            var sel = document.getElementById("year");
            var y = sel.options[sel.selectedIndex].value;

            // get and validate month
            sel = document.getElementById("month");
            var m = sel.options[sel.selectedIndex].value;

            // get and validate day
            sel = document.getElementById("day");
            var d = sel.options[sel.selectedIndex].value;

            // get and validate hour
            sel = document.getElementById("hour");
            var h = sel.options[sel.selectedIndex].value;

			var url = path
			
			// if date checks out modify query string
			if (checkDate(m,d,y,h)) {
				// build paramiters
				url = path + '?' + 't=1' + '&year=' + y + '&month=' + m + '&day=' + d + '&hour=' + h;				
			} 
			
			getPage(url);
				
        } catch (e) {
			if (_ui.DebugFlag) {
				debugUpdate('getListByDateForm',e);
			}
        }   
    } 	