serviceUrl="http://routing.krak.dk/";
JSserviceUrl="http://tileclient.krak.dk/static/v3/";
var callbackTileClient;
var callbackAddressArray;
var sortFinishedCallback;
var callbackDescriptionElementId;

document.write('<script src="'+JSserviceUrl+'scriptaculous-js-1.8.2/prototype.js" type="text/javascript"></script>');
document.write('<script type="text/javascript" src="'+JSserviceUrl+'scriptaculous-js-1.8.2/scriptaculous.js?load=effects,controls"></script>');
document.write('<script src="'+JSserviceUrl+'Dropdown.js" type="text/javascript"></script>');



/*
 Method: showFastestRouteOnMap
 Displays the fastest route between the given start and destination on a tileclient map.
  
 Parameters:
 start - {String} Starting point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 destination - {String} Endpoint, as start.
 tileClient - {KrakMap.TileClient} An instance of the TileClient to draw the route on.
*/
function showFastestRouteOnMap(start, destination, tileClient)
{
    // Remembering the tileclient to use this way is not threadsafe, and can cause problems if more than one tileclient is in use simultaneously.
    callbackTileClient = tileClient;
    jsonpCall(serviceUrl + "FindRoute.aspx?jsonp=showRouteCallback&jsonperror=showErrorOnMap&type=fastest&start="+Url.encode(start)+"&destination="+Url.encode(destination));
}

/*
 Method: showShortestRouteOnMap
 Displays the shortest route between the given start and destination on a tileclient map.
  
 Parameters:
 start - {String} Starting point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 destination - {String} Endpoint, as start.
 tileClient - {KrakMap.TileClient} An instance of the TileClient to draw the route on.
*/
function showShortestRouteOnMap(start, destination, tileClient)
{
    callbackTileClient = tileClient;
    jsonpCall(serviceUrl + "FindRoute.aspx?jsonp=showRouteCallback&jsonperror=showErrorOnMap&type=shortest&start="+Url.encode(start)+"&destination="+Url.encode(destination));
}

/*
 Method: showFastestRouteInDescription
 Displays the fastest route between the given start and destination as an HTML description in a given element.
  
 Parameters:
 start - {String} Starting point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 destination - {String} Endpoint, as start.
 descriptionElementId - {String} The id of an HTML DOM element, tyically a div tag, to fill out with the description.
*/
function showFastestRouteInDescription(start, destination, descriptionElementId)
{
    callbackDescriptionElementId = descriptionElementId;
    jsonpCall(serviceUrl + "FindRoute.aspx?jsonp=showRouteDescription&jsonperror=showErrorInDesc&type=fastest&start="+Url.encode(start)+"&destination="+Url.encode(destination));
}

/*
 Method: showShortestRouteInDescription
 Displays the shortest route between the given start and destination as an HTML description in a given element.
  
 Parameters:
 start - {String} Starting point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 destination - {String} Endpoint, as start.
 descriptionElementId - {String} The id of an HTML DOM element, tyically a div tag, to fill out with the description.
*/
function showShortestRouteInDescription(start, destination, descriptionElementId)
{
    callbackDescriptionElementId = descriptionElementId;
    jsonpCall(serviceUrl + "FindRoute.aspx?jsonp=showRouteDescription&jsonperror=showErrorInDesc&type=shortest&start="+Url.encode(start)+"&destination="+Url.encode(destination));
}

/*
 Method: showFastestRouteOnMapAndDescription
 Displays the fastest route between the given start and destination both on the map and as an HTML description in a given element.
  
 Parameters:
 start - {String} Starting point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 destination - {String} Endpoint, as start.
 tileClient - {KrakMap.TileClient} An instance of the TileClient to draw the route on.
 descriptionElementId - {String} The id of an HTML DOM element, tyically a div tag, to fill out with the description.
*/
function showFastestRouteOnMapAndDescription(start, destination, tileClient, descriptionElementId)
{
    callbackTileClient = tileClient;
    callbackDescriptionElementId = descriptionElementId;
    jsonpCall(serviceUrl + "FindRoute.aspx?jsonp=showBoth&jsonperror=showErrorInDesc&type=fastest&start="+Url.encode(start)+"&destination="+Url.encode(destination));
}

/*
 Method: showShortestRouteOnMapAndDescription
 Displays the shortest route between the given start and destination both on the map and as an HTML description in a given element.
  
 Parameters:
 start - {String} Starting point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 destination - {String} Endpoint, as start.
 tileClient - {KrakMap.TileClient} An instance of the TileClient to draw the route on.
 descriptionElementId - {String} The id of an HTML DOM element, typically a div tag, to fill out with the description.
*/
function showShortestRouteOnMapAndDescription(start, destination, tileClient, descriptionElementId)
{
    callbackTileClient = tileClient;
    callbackDescriptionElementId = descriptionElementId;
    jsonpCall(serviceUrl + "FindRoute.aspx?jsonp=showBoth&jsonperror=showErrorInDesc&type=shortest&start="+Url.encode(start)+"&destination="+Url.encode(destination));
}

/*
 Method: searchAddress
 Parses and searches for matching addresses. Useful for e.g. presenting dropdown choices based on partial input. It uses JSONP to callback a given function with an array of potential addresses.
  
 Parameters:
 address - {String} A textual reprentation of an address (typically incomplete), e.g. "Sydmarken 44".
 callbackName - {String} The name of the JavaScript callback function, or a pointer to a non-anonymous function, which will be called with the answer as parameter.
*/
function searchAddress(address, callbackName)
{
    if (typeof callbackName == 'function')
        callbackName = getFunctionName(callbackName);
    jsonpCall(serviceUrl + "ParseAddress.aspx?jsonp=" + callbackName + "&address=" + Url.encode(address));
}

/*
 Method: searchAndGeocodeAddress
 Parses, searches and geocodes matching addresses. As searchAddress, but all resulting addresses additionally contain coordinates. The callback function will be called with an array of potential addresses. This method is considerably slower than searchAddress, and should only be used if the coordinates are necessary (for, say, a visual representation of the choices).

 Parameters:
 address - {String/Function} A textual reprentation of an address. This can be incomplete (e.g. "Sydmarken 44"), or complete with road name, number and postal code to geocode a known existing address.
 callbackName - {String/Function} The name of the JavaScript callback function, or a pointer to a non-anonymous function, which will be called with the answer.
*/
function searchAndGeocodeAddress(address, callbackName)
{
    if (typeof callbackName == 'function')
        callbackName = getFunctionName(callbackName);
    jsonpCall(serviceUrl + "ParseAddress.aspx?jsonp=" + callbackName + "&address=" + Url.encode(address) + "&geocode=true");
}

/*
 Method: showIsochroneArea
 Displays the area reachable within a given number of minutes on a given tileclient map.
  
 Parameters:
 address - {String} Starting point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 minutes - {Double} A number of minutes.
 tileClient - {KrakMap.TileClient} An instance of the TileClient to draw the resulting polygon on.
*/
function showIsochroneArea(address, minutes, tileClient)
{
    callbackTileClient = tileClient;
    jsonpCall(serviceUrl + "Isochrone.aspx?jsonp=showIsochroneCallback&jsonperror=showErrorOnMap&address=" + Url.encode(address) + "&minutes=" + minutes);
}

/*
 Method: sortOnDistance
 Sorts a given array of geocoded Address objects based on distance (as the crow flies) to a given origin point.

 Parameters:
 origin - {String} Origin point, either on the form "724898.0, 6177166.0", or a textual reprentation of an address, e.g. "Sydmarken 44a, 2860 Søborg". If a partial address is given, a best-guess parsing will be performed.
 potentialAddresses - {Address[]} An array of geocoded addresses, as returned by the parse methods in this API. (Typically, this array will come from a static file with previously generated geocoded addresses; see the ParseBulk utility).
 callback - {Function} A JavaScript function to be called once the sort is complete. The sorted array will be passed as parameter.
*/
function sortOnDistance(origin, potentialAddresses, callback)
{
    callbackAddressArray = potentialAddresses;
    sortFinishedCallback = callback;
    jsonpCall(serviceUrl + "ParseAddress.aspx?jsonp=findNearestAddressCallback&address=" + Url.encode(origin) + "&geocode=true");
}

/*
 Method: createAddressAutocomplete
 Turns a given input field into an autocompleting address search box. It does not include any functionality when selecting a complete address; it only fills out the text of the input field.
 An additional div element with the class "addressautocomplete" will automatically be generated to show the potential addresses as a dropdown.

 Parameters:
 id - {String} DOM ID name of an input field.
*/
function createAddressAutocomplete(id)
{
    initAddressAutocompleter();
    var choices = new Element('div', {'id': id + '_choices' });
    choices.addClassName('addressautocomplete');
    choices.setStyle({zIndex : 100 });
    $(id).insert({'after': choices});
    new AddressAutocompleter(id, id + "_choices", {});
}

/*
 Method: showObject
 A debug helper function to show the fields of an object. Very useful to see the actual data and field names of a JSON object.
 
 Parameters:
 obj - {Object} The object to display in an alert box.
*/
function showObject(obj)
{
    var result = "";
    for (var prop in obj)
    {
        if (typeof(obj[prop]) != 'function')
            result += typeof obj + "." + prop + " = " + obj[prop] + " (" + typeof(obj[prop])+")\n";
    }
    alert(result);
}

// --- End of typical public methods. Below are various internal helper functions. ---

/*
 Method: showErrorOnMap
 Displays an errormessage on top of the tileClient, mainly to handle error messages returned from routing.krak.dk
 
 Parameters:
 message - {String} The errormessage to display over map.
*/
function showErrorOnMap(message)
{
     var errorMessage = new Element('div', {'id': 'krakErrorMessage',
    'onclick':'Effect.BlindUp("krakErrorMessage", { duration: 1.0 }); return false'
    });
    errorMessage.onclick = function() { Effect.BlindUp('krakErrorMessage', { duration: 1.0 }); return false; };
    errorMessage.setStyle({position : 'absolute'});
    errorMessage.update('<h1>Fejl</h1><p>' + message + '</p>');
    $(callbackTileClient.tc.settings.mapContainer).insert({'top': errorMessage});
    Effect.BlindDown('krakErrorMessage', { duration: 1.0 });
}

/*
 Method: showErrorInDesc
 Displays an errormessage at the top of the placeholder for the routedescription, mainly to handle error messages returned from routing.krak.dk
 
 Parameters:
 message - {String} The errormessage to display before/instead of routedescription.
*/
function showErrorInDesc(message)
{
    var errorMessage = new Element('div', {'id': 'krakErrorMessage',
    'onclick':'Effect.BlindUp("krakErrorMessage", { duration: 1.0 }); return false'
    });
    errorMessage.onclick = function() { Effect.BlindUp('krakErrorMessage', { duration: 1.0 }); return false; };
    errorMessage.setStyle({position : 'relative'});
    errorMessage.update('<h1>Fejl</h1><p>' + message + '</p>');
    $(callbackDescriptionElementId).insert({'top': errorMessage});
    Effect.BlindDown('krakErrorMessage', { duration: 1.0 });
}

function showRouteCallback(o)
{
    callbackTileClient.removeDrawing();
    callbackTileClient.draw(o.Geometry.Route);
}

function showBoth(o)
{
    callbackTileClient.removeDrawing();
    callbackTileClient.draw(o.Geometry.Route);
    showRouteDescription(o);
}

function showIsochroneCallback(o)
{
    // Should we remove existing drawing?
    callbackTileClient.draw(o.IsochronePolygon);
}

function jsonpCall(url)
{
    var script = document.createElement("script");
    script.setAttribute("src", url);
    script.setAttribute("type", "text/javascript");                
    document.body.appendChild(script);
}

function findNearestAddressCallback(addresses)
{
    if (addresses != null && addresses.length > 0)
    {
        for (i=0; i< callbackAddressArray.length; i++)
        {
            callbackAddressArray[i].distaceToOrigin = Math.sqrt(
            (callbackAddressArray[i].Coord.X - addresses[0].Coord.X) *
            (callbackAddressArray[i].Coord.X - addresses[0].Coord.X) + 
            
            (callbackAddressArray[i].Coord.Y - addresses[0].Coord.Y) *
            (callbackAddressArray[i].Coord.Y - addresses[0].Coord.Y));
        }
        
        callbackAddressArray.sort(function(a, b)
            {
                if (a.distaceToOrigin > b.distaceToOrigin) return 1;
                if (a.distaceToOrigin < b.distaceToOrigin) return -1;
                return 0;
            });
        sortFinishedCallback(callbackAddressArray);
     }
}



/*summary: Creates and places the routedescription as a HTML fragment into a specified DOM Element*/
/*param (routeJSON): Full JSON route response*/
function showRouteDescription(routeJSON){
 
   var domElementId = callbackDescriptionElementId;
   var _description = routeJSON.Instructions;
   var direction,aggtime,_aggdist,_row,_rowclass;
   var _descdivcont = "<div id='DescriptionContainer'>"; //<h1>Rutebeskrivelse: </h1>
   _aggdist = 0;
   aggtime = 0;
   _row = 0;
   _descdivcont += "<div><table cellpadding='0' cellspacing='0'><thead><tr><th>&nbsp;</th><th>Afstand:</th><th>Beskrivelse:</th><th>Rute:</th><th>Tid:</th></tr></thead><tbody>";
  
	for(direction in _description){
      if(isNaN(parseFloat(_aggdist)))
	_aggdist = 0;  //silly operation due to IE6
 	_row ++;
       //modulus:
      if((_row % 2)==0){_rowclass = "Even"}else{_rowclass = "Odd"};
      if(_description[direction].TurnDirectionPhrase != null){
        _descdivcont += "<tr class='"+ _rowclass +"' id='GeometryIndex_"+ _description[direction].GeometryMultilineIndex +"'>";
        aggtime += _description[direction].Time;
        if(_description[direction].TurnDirection >= 0){
            _descdivcont += "<td><img src='" + getRouteIcon(_description[direction].TurnDirection, _description[direction].RoadType) + "' alt=''></td>";
        }
        else
        {
           _descdivcont += "<td>&nbsp;</td>"
        }

        _descdivcont += "<td>" + Math.round(_aggdist*10)/10 + "</td><td>" + _description[direction].TurnDirectionPhrase + " ca. " + formulateDistance(_description[direction].Length) + "</td><td>" + _description[direction].RouteNumbers + "&nbsp;</td><td>" + getAggTimeFormat(aggtime) +"</td></tr>"};
        _aggdist += _description[direction].Length;
    }

   _descdivcont += "</tbody></table></div>";
   
   _descdivcont += "<h2>Afstand: " + routeJSON.Summary.TotalDistance + " km | Tid: " + getTimeFormat(routeJSON.Summary.TotalTime) + "</h2></div>";
   
   document.getElementById(domElementId).innerHTML = _descdivcont;
}

/*summary: Formulates a more readable output for the description segment*/
/*param(distance): Distance output from jsonp for each description segment*/
function formulateDistance(distance)
{
    var _tempDist;

    if(Math.ceil(distance*1000)/1000 >= 1)
    {
        _tempDist = Math.round(distance*10)/10 + "km";
    }else{
        _tempDist = Math.round(distance*100)*10 + "m";
    }
    return _tempDist;
}

 
/*summary: Selects the proper icon based on angle(degrees) of turns in routedescription. Returns string containing URL of image*/
/*param (direction): direction(degrees) from route each part in routedescription*/
/*param (roadType): type of road from route each part in routedescription */
function getRouteIcon(direction,roadType)
{
    var _dirgif, _dir;
    _dir = "http://tileclient.krak.dk/static/v3/img/route/090709/"
    if (1 == roadType)
    {
        _dirgif = _dir + "iconRuteMotorvej.gif";
    }
    else if (13 == roadType)
    {
        _dirgif = _dir + "iconRuteFaerge.gif";
    }
    else
    {
        if (0 < direction){_dirgif = ""};
 
        //slight left
        if (23 <= direction && 67 >= direction){ _dirgif = _dir + "iconRutePilTv.gif"};
        //left
        if (68 <= direction && 112 >= direction){ _dirgif = _dir + "iconRutePilTv.gif"};
        // sharp left
        if (113 <= direction && 157 >= direction){ _dirgif = _dir + "iconRutePilTv.gif"};
        // uturn
        if (158 <= direction && 202 >= direction){ _dirgif = _dir + "iconRuteUvend.gif"};
        // sharp right
        if (203 <= direction && 247 >= direction){ _dirgif = _dir + "iconRutePilTh.gif"};
        //right
        if (248 <= direction && 292 >= direction){ _dirgif = _dir + "iconRutePilTh.gif"};
        //slight right
        if (293 <= direction && 337 >= direction){ _dirgif = _dir + "iconRutePilTh.gif"};
        //straight ahead
        if ((direction >= 0 && direction <= 22) || (direction >= 338 && direction <= 360))
        {
           _dirgif = _dir + "iconRutePilLige.gif";
        }
        if (direction > 360)
        { // Roundabout
           _dirgif = _dir + "iconRuteRundkoersel.gif";
        }
    }
    return _dirgif;
}
 
 
/*summary: Formatting total time from summary in routedescription, returns total time in hh:mm:ss - format as string */
/*param (rawtime): Total time in "PThhHmmMssS"-format as string */
function getTimeFormat(rawtime)
{
    var _format;
    var _temp = rawtime.split("PT")[1].split("M")[0].split("H")
    var _temps = Math.round((rawtime.split("PT")[1].split("M")[1].split("S")[0])/60);
    var _tempm = (parseInt(_temp[1]) + _temps)
    
    if(rawtime.match("H")){
         if(parseInt(_temp[0]) > 9){
            _format = _temp[0];
        }else{
            _format = "0" + _temp[0];
        } 
        if(_tempm > 9){
           _format += ":" + _tempm;
        }else{
            _format += ":0" + _tempm;
        }
        _format = _temp[0] + ":" + _tempm;
    
    }else{
        if(parseInt(_temp) > 9){
           _format = "00:" + _temp;
        }else{
           _format = "00:0" + _temp;
        }
    }
    return _format;
}
 
/*summary: Formatting Aggregated time from each routepart in routedescription, returns agrregated time in hh:mm:ss - format as string */
/*param (aggtime): Aggregated time in seconds as string */
function getAggTimeFormat(aggtime)
{
    var _format,_tempm,_temph;
    _format = Math.round(aggtime);
    if(_format < 10){
        _format = "00:0" + _format;
    }else if(_format < 60){
        _format = "00:" + _format;
    }else{
        _temph = Math.floor(_format/60);
        _tempm = Math.round((_format/60 - _temph)*60);
        _format = _temph + ":"; 
        if(_tempm < 10){
            _format += "0" + _tempm;
        }else{
            _format += _tempm;
        }
    }
    return _format;
}






function getFunctionName(fn)
{
  var m = fn.toString().match(/^\s*function\s+([^\s\(]+)/);
  return m ? m[1] : "";
}

/**
*
*  URL encode / decode
*  http://www.webtoolkit.info/
*
**/
 
var Url = {
 
	// public method for url encoding
	encode : function (string) {
		return escape(this._utf8_encode(string));
	},
 
	// public method for url decoding
	decode : function (string) {
		return this._utf8_decode(unescape(string));
	},
 
	// private method for UTF-8 encoding
	_utf8_encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";
 
		for (var n = 0; n < string.length; n++) {
 
			var c = string.charCodeAt(n);
 
			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}
 
		}
 
		return utftext;
	},
 
	// private method for UTF-8 decoding
	_utf8_decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;
 
		while ( i < utftext.length ) {
 
			c = utftext.charCodeAt(i);
 
			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}
 
		}
 
		return string;
	}
 
}
