
var model={map:null,icon:null,latest:0,tweets:[],fade:1000,slide:500,now:0,iconset:'',ttl:0,max:0,infoWindow:null,scrollbarWidth:0,hideLeftContent:false,geocoder:null,tally:0,sponsor:1,version:'100',disableStreamSlide:false,alerts:[],defaults:{ttl:1,max:500,iconset:'original',hideLeftContent:false,disableStreamSlide:false},init:function(){$.ajaxSetup({'timeout':15000,'error':function(XMLHttpRequest,textStatus,errorThrown){view.setStatus('Update failed',3);return null;}});var latlng=new google.maps.LatLng(54.8,-3);var mapTypeControlOptions={style:google.maps.MapTypeControlStyle.DROPDOWN_MENU};var navigationControlOptions={style:google.maps.NavigationControlStyle.SMALL};mapOptions={center:latlng,navigationControlOptions:navigationControlOptions,mapTypeControlOptions:mapTypeControlOptions,streetViewControl:false,zoom:5};model.map=new google.maps.Map(document.getElementById('map'),mapOptions);model.now=(new Date().getTime()/1000);pixelOffset=new google.maps.Size(16,-16);model.infoWindow=new InfoBox({pixelOffset:pixelOffset});model.geocoder=new google.maps.Geocoder();model.iconset=model.defaultIfNull(model.getCookie('iconset'),model.defaults.iconset);view.setIconset(model.iconset);model.ttl=model.defaultIfNull(model.getCookie('ttl'),model.defaults.ttl);view.setTtl(model.ttl);model.max=model.defaultIfNull(model.getCookie('max'),model.defaults.max);view.setMax(model.max);model.hideLeftContent=model.defaultIfNull(model.getCookie('hideLeftContent'),model.defaults.hideLeftContent);view.setHideLeftContent(model.hideLeftContent);model.disableStreamSlide=model.defaultIfNull(model.getCookie('disableStreamSlide'),model.defaults.disableStreamSlide);view.setDisableStreamSlide(model.disableStreamSlide);model.saveCookies();var styledMapStyles=[{featureType:"landscape.man_made",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"poi",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"road",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"transit",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"administrative",elementType:"all",stylers:[{visibility:"off"}]},{featureType:"landscape",elementType:"all",stylers:[{saturation:0},{lightness:-60},{hue:"#ccff00"},{visibility:"simplified"}]},{featureType:"water",elementType:"all",stylers:[{saturation:0},{lightness:-50},{hue:"#0033ff"},{visibility:"simplified"}]}];var styledMapOptions={name:'Simple'};var styledMapType=new google.maps.StyledMapType(styledMapStyles,styledMapOptions);model.map.mapTypes.set('simple',styledMapType);model.map.setMapTypeId('simple');model.map.setOptions({mapTypeControlOptions:{mapTypeIds:['simple',google.maps.MapTypeId.TERRAIN,google.maps.MapTypeId.SATELLITE,google.maps.MapTypeId.HYBRID],style:google.maps.MapTypeControlStyle.DROPDOWN_MENU}});model.sponsor+=(model.random()%5);},defaultIfNull:function(val,def){return(val!==null)?val:def;},reset:function(){model.latest=0;model.tweets=[];},saveCookies:function(){model.setCookie('max',model.max);model.setCookie('ttl',model.ttl);model.setCookie('iconset',model.iconset);model.setCookie('hideLeftContent',model.hideLeftContent);model.setCookie('disableStreamSlide',model.disableStreamSlide);},setCookie:function(name,value){$.cookie(name,value);},getCookie:function(name){var val=$.cookie(name);if(val=='true')return true;if(val=='false')return false;return val;},createIconForTweet:function(tweet){iconUrl='./images/iconsets/'+model.iconset+'/'+model.ratingToIconIndex(tweet.rate)+'.png?refresh';return new google.maps.MarkerImage(iconUrl,new google.maps.Size(32,32),new google.maps.Point(0,0),new google.maps.Point(16,16),new google.maps.Size(32,32));},ratingToIconIndex:function(rate){if(rate>6)return'4';if(rate>4)return'3';if(rate>2)return'2';if(rate>0)return'1';return'0';},sortTweets:function(tweets){return tweets.sort(function(x,y){return x.created_at_time-y.created_at_time;});},random:function(){return new Date().getTime();},addTweet:function(tweet){model.tweets.push(tweet);},removeTweet:function(tweet){model.tweets=jQuery.grep(model.tweets,function(value){return value!=tweet;});},isFirstLoad:function(){return model.latest==0;},formatText:function(text){text=model.linkifyUrls(text);text=model.linkifyHashtags(text);text=model.linkifyUsernames(text);return text;},linkifyUrls:function(text){if(text==null)return;var urls=text.match(/http\S+/ig);if(urls){for(u=0;u<urls.length;u++){var url=urls[u];var t=(url.length>30)?url.substr(0,27)+'...':url;var a='<a class="url" href="'+url+'" target="_blank">'+t+'</a>';text=text.replace(url,a);}}
return text;},findPhotosInTweet:function(tweet){if(tweet.text==null)return;var tweetphoto=tweet.text.match('http://(www\.)?tweetphoto.com/[A-Za-z0-9]{5,8}');if(tweetphoto){tweet.picLinkUrl=tweetphoto[0];tweet.picThumbUrl='http://tweetphotoapi.com/api/tpapi.svc/imagefromurl?size=thumbnail&url='+tweetphoto[0];tweet.picImageUrl='http://tweetphotoapi.com/api/tpapi.svc/imagefromurl?size=medium&url='+tweetphoto[0];}
var plixi=tweet.text.match('http://(www\.)?plixi.com/p/[A-Za-z0-9]{5,8}');if(plixi){tweet.picLinkUrl=plixi[0];tweet.picThumbUrl='http://api.plixi.com/api/tpapi.svc/imagefromurl?size=thumbnail&url='+plixi[0];tweet.picImageUrl='http://api.plixi.com/api/tpapi.svc/imagefromurl?size=medium&url='+plixi[0];}
var twitpic=tweet.text.match('http://(www\.)?twitpic.com/([A-Za-z0-9]{5,7})');if(twitpic){tweet.picLinkUrl=twitpic[0];tweet.picThumbUrl='http://twitpic.com/show/thumb/'+twitpic[2];tweet.picImageUrl='http://twitpic.com/show/full/'+twitpic[2];}
var yfrog=tweet.text.match('http://(www\.)?yfrog.(com|us)/[A-Za-z0-9]{6,12}');if(yfrog){tweet.picLinkUrl=yfrog[0];tweet.picThumbUrl=yfrog[0]+':small';tweet.picImageUrl=yfrog[0]+':iphone';}},linkifyHashtags:function(text){if(text==null)return;var hashtags=text.match(/#[A-Z0-9]{2,}/ig);if(hashtags){for(h=0;h<hashtags.length;h++){var hashtag=hashtags[h];var a='<a class="hashtag" href="http://twitter.com/#!/search/'+escape(hashtag)+'" target="_blank">'+hashtag+'</a>';text=text.replace(hashtag,a);}}
return text;},linkifyUsernames:function(text){if(text==null)return;var usernames=text.match(/@([A-Z0-9_]{1,15})/ig);if(usernames){for(u=0;u<usernames.length;u++){var username=usernames[u];var t=username.replace('@','');var a='@<a class="username" href="http://twitter.com/#!/'+escape(t)+'" target="_blank">'+t+'</a>';text=text.replace(username,a);}}
return text;},relativeTime:function(time){var seconds=model.now-time;if(seconds<60)return'less than a minute';var minutes=Math.floor(seconds/60);if(minutes<60)return minutes+' minute'+(minutes==1?'':'s');var hours=Math.floor(minutes/60);if(hours<24)return hours+' hour'+(hours==1?'':'s');var days=Math.floor(hours/24);return days+' day'+(days==1?'':'s');},saveAlert:function(alert){model.alerts.push(alert);},hasViewedAlert:function(alert){if(alert==null)return true;return $.inArray(alert,model.alerts)>-1;},base58decode:function(code){var alphabet='123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ';var num=code.length;var decoded=0;var multi=1;for(var i=(num-1);i>=0;i--){decoded=decoded+multi*alphabet.indexOf(code[i]);multi=multi*alphabet.length;}
return decoded;}};var view={init:function(){$.panelify();$('select[name=ttl]').change(controller.ttlChanged);$('select[name=max]').change(controller.maxChanged);$('select[name=iconset]').change(controller.iconsetChanged);$('input[name=hideLeftContent]').change(controller.hideLeftContentChanged);$('input[name=disableStreamSlide]').change(controller.disableStreamSlideChanged);},getTtl:function(){return $('select[name=ttl]').val();},setTtl:function(val){$('select[name=ttl]').val(val);},getMax:function(){return $('select[name=max]').val();},setMax:function(val){$('select[name=max]').val(val);},getIconset:function(){return $('select[name=iconset]').val();},setIconset:function(val){$('select[name=iconset]').val(val);$.each(model.tweets,function(i,tweet){if(tweet.home_marker)tweet.home_marker.setIcon(model.createIconForTweet(tweet));});view.updateKey();},getHideLeftContent:function(){return $('input[name=hideLeftContent]').is(':checked');},setHideLeftContent:function(val){$('input[name=hideLeftContent]').attr('checked',val);$('#left').toggle(!val);$('#map').css('left',val?'10px':'270px');view.redrawMap();},getDisableStreamSlide:function(){return $('input[name=disableStreamSlide]').is(':checked');},setDisableStreamSlide:function(val){$('input[name=disableStreamSlide]').attr('checked',val);},updateKey:function(){$('#key img').each(function(i,img){$(img).attr('src','./images/iconsets/'+model.iconset+'/'+(4-i)+'.png');});},setStatus:function(text,hold){if(text)$('#status').html(text);if($('#status:hidden').length>0)$('#status').fadeIn(model.fade);if(hold>0)$('#status').oneTime(hold+'s',function(){view.hideStatus();});},hideStatus:function(){$('#status').fadeOut(model.fade,function(){$('#status').html('');});},clearTweets:function(){$('#tweets').empty();},removeMarker:function(marker){marker.setMap(null);},removeTweet:function(tweet){$('#tweets li[rel='+tweet.status_id+']').slideUp().remove();},addTweet:function(tweet){var html='<div class="tweet" id="'+tweet.status_id+'">';html+='<div class="profile-image"><a href="http://twitter.com/'+tweet.from_user+'" target="_blank"><img alt="'+tweet.from_user+'" src="http://img.tweetimag.es/i/'+tweet.from_user+'_m" /></a></div>'
if(tweet.home_marker)html+='<div class="show">&nbsp;</div>';html+='<div class="from-user"><a href="http://twitter.com/'+tweet.from_user+'" target="_blank">'+tweet.from_user+'</a></div>';html+='<div class="text">'+model.formatText(tweet.text)+'</div>';if(tweet.picThumbUrl)html+='<div class="photo"><a href="'+tweet.picLinkUrl+'" target="_blank"><img alt="*" src="'+tweet.picThumbUrl+'" /></a></div>';html+='<div class="meta">'+tweet.created_at_time+'</div>';html+='</div>';var li=$('<li>'+html+'</li>');li.find('.show').click(function(){google.maps.event.trigger(tweet.home_marker,'click');});li.find('.photo a').click(function(){$('#photo .photo img').attr('src',tweet.picImageUrl);$('#photo .photo a').attr('href',tweet.picLinkUrl);$.panelify('show','#photo');return false;});$('#tweets').prepend(li);if(!model.disableStreamSlide&&!model.isFirstLoad())$('#tweets li:first').hide().slideDown(model.slide);},addMarker:function(tweet){if(tweet.home_located>0){tweet.home_location=new google.maps.LatLng(tweet.home_latitude,tweet.home_longitude);var icon=model.createIconForTweet(tweet);tweet.home_marker=new google.maps.Marker({position:tweet.home_location,icon:icon,map:model.map});google.maps.event.addListener(tweet.home_marker,'click',function(){var html='<div class="tweet">';html+='<div class="profile-image"><a href="http://twitter.com/'+tweet.from_user+'" target="_blank"><img src="http://img.tweetimag.es/i/'+tweet.from_user+'_n" /></a></div>';html+='<div class="from-user"><a href="http://twitter.com/'+tweet.from_user+'" target="_blank">'+tweet.from_user+'</a></div>';html+='<div class="text">'+model.formatText(tweet.text)+'</div>';if(tweet.picThumbUrl)html+='<div class="photo"><a href="'+tweet.picLinkUrl+'" target="_blank"><img alt="*" src="'+tweet.picThumbUrl+'" /></a></div>';html+='<div class="meta">'+model.relativeTime(tweet.created_at_time)+' ago via Twitter</div>';html+='</div>';model.infoWindow.setContent(html);model.infoWindow.open(model.map,tweet.home_marker);});}},setTweetsWidth:function(){var tweetsWidth=$('#tweets').width()-model.scrollbarWidth;$('#tweets').css('width',tweetsWidth);},redrawMap:function(){google.maps.event.trigger(model.map,'resize');},addSponsor:function(){var html='<div class="sponsor"><a href="#sponsor">Advertise on this site! Click for details.</a></div>';var li=$('<li>'+html+'</li>');li.find('a').click(function(){$.panelify('show','#sponsor');return false;});$('#tweets').prepend(li);model.sponsor+=1;},showAlert:function(message){$('#alert .message').html(message);$.panelify('show','#alert');}}
var controller={init:function(){view.init();model.init();model.scrollbarWidth=controller.calculateScrollbarWidth();view.setTweetsWidth();$(document).oneTime('2s',controller.updateTweets).everyTime('60s',controller.updateTweets);$(document).everyTime('300s',controller.updateSystem);controller.initSearch();},initSearch:function(){$('#search-query').focus(function(){if($(this).hasClass('hint')){$(this).removeClass('hint').val('');}}).blur(function(){if($(this).val().replace(' ','')==''){$(this).addClass('hint').val('Search for a location...');}}).blur();$('#search').submit(function(){model.geocoder.geocode({'address':$('#search-query').val()},function(results,status){if(status==google.maps.GeocoderStatus.OK){searchLocation=results[0].geometry.location;model.map.setCenter(searchLocation);model.map.setZoom(7);if(model.searchMarker){model.searchMarker.setMap(null);}
model.searchMarker=new google.maps.Marker({map:model.map,position:searchLocation});}else{view.showAlert('Sorry, we can\'t find that location.');}});return false;});},calculateScrollbarWidth:function(){var parent=$('<div style="width:50px;height:50px;overflow:auto"><div /></div>').appendTo('body');var child=parent.children();var width=child.innerWidth()-child.height(100).innerWidth();parent.remove();return width;},ttlChanged:function(){model.ttl=view.getTtl();model.saveCookies();controller.reset();},maxChanged:function(){model.max=view.getMax();model.saveCookies();controller.reset();},iconsetChanged:function(){model.iconset=view.getIconset();model.saveCookies();view.setIconset(model.iconset);},hideLeftContentChanged:function(){model.hideLeftContent=view.getHideLeftContent();model.saveCookies();view.setHideLeftContent(model.hideLeftContent);},disableStreamSlideChanged:function(){model.disableStreamSlide=view.getDisableStreamSlide();model.saveCookies();},updateTweets:function(){view.setStatus('Updating tweets...');var since_time=Math.floor(model.now-(model.ttl*3600));$.getJSON('./app/json.php?since_id='+model.latest+'&since_time='+since_time,function(data){if(data){if(data.tweets&&data.tweets.length>0){model.sortTweets(data.tweets);$.each(data.tweets,function(i,tweet){model.findPhotosInTweet(tweet);view.addMarker(tweet);view.addTweet(tweet);model.addTweet(tweet);model.tally+=1;if(model.tally%10==0)view.addSponsor();});view.setStatus(data.tweets.length+' new tweet'+((data.tweets.length==1)?'':'s'),10);model.latest=data.latest;}
else{view.setStatus('No new tweets found',3);}
model.now=data.now;}
controller.removeOldTweets();controller.updateTimes();});},updateSystem:function(){$.getJSON('./json/system?now='+model.now+'&version='+model.version,function(data){if(data){if(data.alert){if(!model.hasViewedAlert(data.alert)){model.saveAlert(data.alert);view.showAlert(data.alert);}}
switch(data.command){case'refresh':window.location='/';break;}}});},reset:function(){controller.removeAllMarkers();model.reset();view.clearTweets();controller.update();},removeAllMarkers:function(){$.each(model.tweets,function(i,tweet){if(tweet.home_marker)view.removeMarker(tweet.home_marker);});},removeOldTweets:function(){while(model.tweets.length>model.max){tweet=model.tweets.shift();controller.removeTweet(tweet);}
$.each(model.tweets,function(i,tweet){if(tweet.created_at_time<(model.now-(model.ttl*3600))){controller.removeTweet(tweet);}});},removeTweet:function(tweet){view.removeTweet(tweet);if(tweet.home_marker)view.removeMarker(tweet.home_marker);model.removeTweet(tweet);},updateTimes:function(){$.each(model.tweets,function(i,tweet){var meta=model.relativeTime(tweet.created_at_time)+' ago via Twitter';$('#'+tweet.status_id+' .meta').html(meta);});}}
$(document).ready(controller.init);
