<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs 
	title="Portland TriMet Real-Time Bus Arrival" 
	title_url="http://trimet.org/transittracker/stopidnumbers.htm" 
	author="Dave Sohigian" author_email="gadget@sohigian.com" 
	description="Display real time data for Portland OR's bus system (TriMet). You can choose up to 10 stops (by ID) and data is retrieved via an XML API from TriMet. You can also display a google map of stop and bus (real-time) locations! Works for Max and Bus stops, but not Streetcar. Comments welcome! " 
	author_location="Portland, OR, USA" 
	author_photo="http://farm1.static.flickr.com/60/162462311_ddfcd4d54f_s.jpg" 
	author_aboutme="Based in Portland, OR, Dave works in software marketing. See more at http://dave.sohigian.com" 
	author_link="http://dave.sohigian.com" 
	width="300" 
	height="400" 
	thumbnail="http://farm5.static.flickr.com/4044/4328112795_7f73211a74_o.png" 
	screenshot="http://farm5.static.flickr.com/4045/4328850000_262ed43260_o.png" 
	scrolling="false" 
	singleton="false">
<Require feature="dynamic-height"/>
<Require feature="analytics"/>
</ModulePrefs>
<UserPref required="false" name="stoparray" display_name="Stop ID" datatype="list" />
<UserPref name="refreshMins" datatype="enum" display_name="Refresh every" default_value="2">
  <EnumValue value="1" display_value="1 minute"/>
  <EnumValue value="2" display_value="2 minutes"/>
  <EnumValue value="5" display_value="5 minutes"/>
  <EnumValue value="10" display_value="10 minutes"/>
  <EnumValue value="60" display_value="60 minutes"/>
</UserPref>
<UserPref name="displayTime" display_name="Display Header?" datatype="enum" default_value="false">
  <EnumValue value="true" display_value="Yes"/>
  <EnumValue value="false" display_value="No"/>
</UserPref>
<UserPref name="fontsize" display_name="Font Size" datatype="enum" default_value="10">
  <EnumValue value="18" display_value="Large"/>
  <EnumValue value="15" display_value="Medium"/>
  <EnumValue value="12" display_value="Small"/>
  <EnumValue value="10" display_value="Very Small"/>
  <EnumValue value="8" display_value="Tiny"/>
</UserPref>

<Content type="html">

<![CDATA[
<script src="http://maps.google.com/maps?file=js" type="text/javascript"></script>
<style>
.arrivals {
	font-size:10px;
	color:black;
	}
.gadget {
	background-color:#3b5a95;
	color:white;
	font-weight:bold;
}
.header {
	border-bottom: medium solid #ff3300;
	background: url('http://www.trimet.org/images/transittrack_head.gif') no-repeat;
	padding:0 0 20px 200px;
	font-size:11px;
}

.stopbox {
	border: thin solid black;
	font-size:11px;
}
.stopbox a {
	color:white;
	text-decoration:none;
}
.google_map {
	display:none;
	position:absolute;
	border:5px solid red;
	z-index:100;
	left:15px;
	top:20px;
	width:90%;
	height:85%;

}
.google_map_caption {
	display:none;
	z-index:100;
	position:absolute;
	background-color:red;
	height:15px;
	top:2px;
	width:90%;
	left:15px;
	padding:2px 5px;
	color:white;
	font-size:12px;
}
.footer {
	background-color:#263757;
	color:white;
	font-size:10px;
	padding:3px;
	text-align:center;
	border: thin solid red;
}
.footer a {
	color:white;
}
.add_stops_warning {
	display:none;
}
.promote_gadget{
	display:none;
	position:absolute;
	border:5px solid red;
	z-index:101;
	left:10px;
	top:10px;
	width:90%;
	height:300px;
	background-color:#FFF;
	font-size:12px;
	padding:10px;	
}
</style>
<div>
<div id="content_div"></div>
<div id="no_stops" class="add_stops_warning">You need to add stops before you can use this gadget (you can add up to three). To add a stop, click on the small drop down at the top of the gadget (see green arrow in image below):
<img src="http://farm5.static.flickr.com/4061/4330058271_bd7ec5a727_o.png" width="184" height="153" alt="muni-settings" />
Choose "Edit Settings" (see blue box in image above) and add your stops in the box that appears. You can use the link to the Trimet site (below) to identify stop ID's.
</div>
<div class="footer">
	To find stop ID's, go to 
		<a href="http://trimet.org/transittracker/stopidnumbers.htm" target="_blank" >
			Trimet Website
		</a>
	<br/>
	Like this Gadget? <a href="#" onclick='showPromote();return false;'>Help promote it, or send feedback!</span>
</div>
<div onclick='hidemap()' id="mapHeader" class="google_map_caption">[click here to close]</div>
<div class="google_map" id="map" />
</div>
<div class="promote_gadget" id="promoteGadget">
	<h2>Promote/Feedback</h2>
	Thanks for your interest in this gadget. If you would like to help promote the gadget, use any of the links below. Use the link at the bottom to send feedback to the author.	
	<ul>
	<li><a target="_blank" href="http://bit.ly/trimet">Leave a comment/review on iGoogle</a></li>
	<li><a href="http://twitter.com/home?status=Live%20in%20Portland%20and%20use%20public%20transit?%20Check%20out%20this%20real-time%20bus%20tracker%20gadget%20-%20http://bit.ly/trimet%20@dsohigian" target="_blank">Promote on Twitter</a></li>

	<li><a href="http://www.facebook.com/sharer.php?u=http://bit.ly/trimet" target="blank">Share on Facebook</a></li>

	<li>Write a blog post: <a target="_blank" href="http://blog.sohigian.com/2010/02/06/trimet-bus-tracking-google-gadget">See example post</a></li>

	<li>Post to a forum (use this URL): http://bit.ly/trimet</li>
	
	<li><A HREF="mailto:dsohigian@gmail.com?Subject=Great%20way%20to%20track%20Trimet%20buses&Body=Hi%2C%0A%0AI%20wanted%20to%20let%20you%20know%20about%20a%20cool%20way%20to%20track%20Trimet%20buses%20using%20a%20iGoogle%20gadget.%20If%20you%20go%20to%20http%3A//bit.ly/trimet%20you%20can%20get%20a%20gadget%20that%20can%20display%20real-time%20info%20for%20up%20to%2010%20Trimet%20stops.%20It%27s%20easy%20to%20use%20and%20gets%20it%20data%20straight%20from%20Trimet.%0A%0AThanks%2C%0A">Email to friends</A></li>

	<li><a href="http://blog.sohigian.com/contact/" target="_blank">Send feedback to author</a></li>

	</ul>
	<div style="color:red;background-color:yellow;" onclick="hidePromote()"><strong>Click here to close this message.</strong></div>
</div>
<script type="text/javascript">

function showPromote(){
document.getElementById("promoteGadget").style.display = 'block';
document.getElementById("content_div").style.height = '350px';
_IG_AdjustIFrameHeight();

}
function hidePromote(){
document.getElementById("promoteGadget").style.display = 'none';
document.getElementById("content_div").style.height = '';
_IG_AdjustIFrameHeight();

}

function formatDate(d){
	//format the date for the header
	var curr_hour = d.getHours();
	(curr_hour < 12)? a_p = "AM":a_p = "PM";
	if(curr_hour == 0){curr_hour = 12};
	if(curr_hour > 12){curr_hour = curr_hour - 12};

	var curr_min = d.getMinutes();

	curr_min = curr_min + "";

	if (curr_min.length == 1)
	{
		curr_min = "0" + curr_min;
	}
		d = curr_hour + ":" + curr_min + " " + a_p; //can also display seconds d.getSeconds()
		return d;
	}

function showmap(lat,lng,element,text){
	//show the map overlay
	document.getElementById("map").style.display = 'block';
	document.getElementById("mapHeader").style.display = 'block';
	document.getElementById("mapHeader").innerHTML = text + '[click here to close]';
	var map = new GMap(document.getElementById("map"));
	var point;
    	point = new GLatLng(lat,lng);
    	map.setCenter(point, 15);
	map.addControl(new GSmallMapControl());
	map.addControl(new GMapTypeControl());
	// Create our "bus" marker icon
	var busIcon = new GIcon();
	busIcon.image = "http://chart.apis.google.com/chart?chst=d_map_pin_icon&chld=bus|996600";
	busIcon.shadow = "http://chart.apis.google.com/chart?chst=d_map_pin_shadow";
	busIcon.iconAnchor = new GPoint(1, 0);
	//busIcon.infoWindowAnchor = new GPoint(5, 1);
	//map.openInfoWindow(map.getCenter(), document.createTextNode(text));
	// Set up our GMarkerOptions object literal
	markerOptions = { icon:busIcon };	
	//create a marker for the location
    	map.addOverlay(new GMarker(point,markerOptions));
		
	
}

function hidemap(){
	document.getElementById("map").style.display = 'none';
	document.getElementById("mapHeader").style.display = 'none';
	
}

function makeCachedRequest(url, callback, params, refreshInterval) {
	var ts = new Date().getTime();
  	var sep = "?";
  	if (refreshInterval && refreshInterval > 0) {
    		ts = Math.floor(ts / (refreshInterval * 1000));
  	}
  	if (url.indexOf("?") > -1) {
    		sep = "&";
  	}
  	url = [ url, sep, "nocache=", ts ].join("");
	
 	gadgets.io.makeRequest(url, callback, params);
}

function arrivalPredictionRequest() {
	//Sets up and makes call to Trimet arrival web service
	var params = {};
      	params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.DOM;
	// Stops Set by User
	var stopIDs = prefs.getArray("stoparray");
	//create the url with the list of IDs
	var url = "http://developer.trimet.org/ws/V1/arrivals?locIDs=";
	url += stopIDs[0];
	for (var i = 1; i < stopIDs.length ; i++) {
		url += "," + stopIDs[i];
	}
	url += "&appID=674BB8A05BFF40EC10E0CACBF";
	makeCachedRequest(url, displayTracker, params,refreshRate);
}



function displayTracker(obj) {
	//displays results of web service call
	var html = "";
	var domdata = obj.data;
	var stopIDs = prefs.getArray("stoparray");
	//Display the Header
	var html = "<div class='gadget'>";
	var currentTime = new Date(parseInt(domdata.getElementsByTagName("resultSet").item(0).getAttribute("queryTime")));
	var formattedCurrentTime = formatDate(currentTime);
	if(prefs.getString("displayTime")=="true"){
  		html += "<div class='header'>Current Time: " + formattedCurrentTime + "</div>";
		
	}
	
	for (var i = 0; i < stopIDs.length ; i++) {
		if (stopIDs[i] != "") {
			//function to find all the data associated with that stop
			html += getArrivals(stopIDs[i],domdata,currentTime);
		};
	}
	 	
	_gel('content_div').innerHTML = html;
	_IG_AdjustIFrameHeight();
}

function getArrivals(stopID,response,currentTime) {
	//Sets up arrival block for each stop
	var html = "";
	// Get a list of the <arrival> element nodes in the file
	var itemList = response.getElementsByTagName("arrival");
	var locationList = response.getElementsByTagName("location");
	// Loop through all <location> nodes
	for (var i = 0; i < locationList.length ; i++) {
		currentLocation = locationList.item(i);
		if (currentLocation.getAttribute("locid")==stopID){
			//display the information for specific stop
			//this is the "header" for each stop and arrival information will follow
			html += displayStop(stopID,currentLocation);
		}
	}
	
	var lineColor = 0;
	// Loop through all <arrival> nodes
	for (var i = 0; i < itemList.length ; i++) {
		var arrivalTag = itemList.item(i)
		var locid = arrivalTag.getAttribute("locid")
		if (locid==stopID) {
			html += displayArrival(stopID,lineColor,currentTime,arrivalTag);
			lineColor ++;
		}

	}
	return html;
}

function displayStop(stopID,currentLocation) {
	stopHTML = "";
	lat = currentLocation.getAttribute("lat");
	lng = currentLocation.getAttribute("lng");
	mapCaption = "Location of Stop ID " + stopID;
	stopHTML += "<div class='stopbox' ";
	stopHTML += "><a style='" + fontSizeStyle(0) + "'";         
	stopHTML += "target='_blank' href='http://www.trimet.org/go/cgi-bin/cstops.pl?action=entry&Loc=";
	stopHTML += stopID + "'>Stop ID: " + stopID;
	stopHTML += " " + currentLocation.getAttribute("desc");
	stopHTML += " " + currentLocation.getAttribute("dir");
	stopHTML += "</a>";
	stopHTML += googleMapLink(lng,lat,mapCaption);
	stopHTML += "</div>";
	return stopHTML;
}


function displayArrival(stopID,lineColor,currentTime,currentArrival){

	//For each Arrival, pull the following Data and add to the HTML
	var shortSign = currentArrival.getAttribute("shortSign");
	var estimated = currentArrival.getAttribute("estimated");
	estimated = new Date(parseInt(estimated));
	formattedEstimated = formatDate(estimated);
	var scheduled = currentArrival.getAttribute("scheduled");
	scheduled = new Date(parseInt(scheduled));
	formattedScheduled  = formatDate(scheduled);
	var route = currentArrival.getAttribute("route");
	var dir = currentArrival.getAttribute("dir");	
	var status = currentArrival.getAttribute("status");
	var mapLink = "";
	var arrivalHTML = "";
	
	//if there is a current estimate, then display the map link
	if (currentArrival.getAttribute("status")!="scheduled"){
		var blockPosition = currentArrival.getElementsByTagName("blockPosition")[0];
		var lng = blockPosition.getAttribute("lng");
		var lat = blockPosition.getAttribute("lat");
		var caption = "Current location of " + shortSign + " ";
		mapLink += googleMapLink(lng,lat,caption);
	};
	
	//used for the schedule popup - need to be a three character long route with leading zeros
	var popBuffer = "000";
	popBuffer = popBuffer.substring(route.length - 1,2);
	
	// Displays arrival information	
	arrivalHTML += "<div class='arrivals' style='background-color:";
	//odd-even row color style
	((lineColor % 2) == 0)? arrivalHTML+="#fff7bf;" : arrivalHTML+="white;";
	arrivalHTML += fontSizeStyle(0);
	arrivalHTML += " line-height:" + (prefs.getInt("fontsize")+ 2 ) + "px;"
	arrivalHTML += "'><a style='text-decoration:none' href='http://www.trimet.org/schedule/r" + popBuffer + route + "pop.htm' target='_blank'>";
	arrivalHTML += shortSign;
	arrivalHTML += "</a>&emsp;";
	
	arrivalHTML += formatCountdown(scheduled,estimated,currentTime);
	arrivalHTML += mapLink + "</div>";

	return arrivalHTML


}

function fontSizeStyle (mod){
	var fontSize = "font-size:" + (prefs.getInt("fontsize")+ mod) + "px;"; 
	return fontSize;
}


function googleMapLink (lng,lat,mapCaption) {
	//creates image and link to open google map with current lng/lat of stop or bus
	var mapHTML = ""
	//mapHTML += "<img src='http://farm5.static.flickr.com/4066/4311399651_7d8ea50888_o.png'"
	mapHTML += "<span onclick='showmap(" + lat + "," + lng + ",this,\"" + mapCaption + "\")'/>";
	mapHTML += "[map]</span>";
	return mapHTML
}

function formatCountdown(scheduledTime, estimatedTime, currentTime){
	//DPS - Should be able to shorten this down quite a bit
	//DPS - The basis of this section is to find the countdown
	//DPS - then if it is a number, calculate and format
	
	var countdown = estimatedTime - currentTime;
	var isEstimateNA = false;
	if (isNaN(countdown))
  	{
  		countdown = scheduledTime - currentTime;
  		isEstimateNA = true;
  		if (isNaN(countdown))
    		{
    		countdown="N/A";
    		}
  	}

	if (countdown!="N/A")
  	{ 
  		//countdown converted to minutes
  		countdown = Math.round(countdown/60000,0);
  		if (countdown == 0)
    		{ 
      			countdown = "Due";
    		} 
    		else 
    		{
      			if (countdown >=60) {countdown = Math.round(countdown/60) + " hours"} else {countdown += " min"};
      			if (isEstimateNA) { countdown += " *scheduled"};
    		};
  	}
	var countdownHTML = "<span style='color:red'>" + countdown + "&nbsp;</span>";
	
	return countdownHTML;
}


var prefs = new _IG_Prefs(__MODULE_ID__);
var refreshRate = Math.ceil(prefs.getInt("refreshMins"));
if(refreshRate <= 0){refreshRate = 1};


var stopsNumber = prefs.getArray("stoparray").length
if (stopsNumber > 0 && stopsNumber < 11){
	gadgets.util.registerOnLoadHandler(arrivalPredictionRequest(refreshRate));
	setInterval ( "arrivalPredictionRequest(refreshRate)", refreshRate * 60000);
} else if (prefs.getArray("stoparray").length > 10) {
	displayWarning("You may only have a maximum of 10 stops");
} else {
	document.getElementById("no_stops").style.display = 'inline';
	_IG_AdjustIFrameHeight();
}

</script>

 <script>
  _IG_Analytics("UA-747105-6", "/trimet-tracker-maps");
</script>
]]>
</Content>
</Module> 