/*======================================================================*\
|| #################################################################### ||
|| # Dom & Liz's Visual Route Planner                                   ||
|| # ---------------------------------------------------------------- # ||
|| # Copyright ©2008 Dominic Pezzuto All Rights Reserved.               ||
|| # This file may not be redistributed in whole or significant part. # ||
|| # http://yardsales.lizndom.com     -    yardsales@lizndom.com        ||
|| #################################################################### ||
\*======================================================================*/

var locationList = new Array()
var routeList = new Array()
var routeReceived = 0
var lastRouteReceived = null
var count = 0
var globalID = 1

var finalList = new Array()
var numFormElements = 0

var outstandingLoadRequests = 0
var outstandingGeocoderRequests = 0
var formLoaded = false

var DEFAULT_ADDRESS = "Type address here"
var DEFAULT_DESCRIPTION = "<Type optional description here>"

var geocoder = new GClientGeocoder();
var map = null
var undoButton = null;

// ====== set up marker mouseover tooltip div ======
var tooltip = null 

var totalLoadCalls = 0

var baseIcon = new GIcon();
baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
baseIcon.iconSize = new GSize(20, 34);
baseIcon.shadowSize = new GSize(37, 34);
baseIcon.iconAnchor = new GPoint(9, 34);
baseIcon.infoWindowAnchor = new GPoint(9, 2);
baseIcon.infoShadowAnchor = new GPoint(18, 25);

var polylines = new Array()
var hasHome = false

var MAP_WIDTH  = 900;
var MAP_HEIGHT = 500;
var MAP_WIDTH_DELTA = 100;
var MAP_HEIGHT_DELTA = 100;
var MIN_MAP_WIDTH = 800; //-1 to disable limit
var MIN_MAP_HEIGHT = 300; //-1 to disable limit

var bounds = new GLatLngBounds();

//Mouse variables
var mouseX = 0; //The current x-coordinate of the mouse cursor in relation to the entire screen
var mouseY = 0; //The current y-coordinate of the mouse cursor in relation to the entire screen
var mouseDX = 0; //The difference between the current x-coord of the mouse, and the x-coord of the mouse when last checked
var mouseDY = 0; //The difference between the current y-coord of the mouse, and the x-coord of the mouse when last checked
var resizeBoxCurrentlyBeingHeld = false; //Is the left mouse-button currently being held?
var resizeBoxCurrentlyMousedOver = false;
var mapCurrentlyMousedOver = false;
var doResize = true;

//Mouse event functions
document.onmouseup = function(){ resizeBoxCurrentlyBeingHeld = false; } //When the left mouse button is released

var MARKER_RED   = 10;
var MARKER_GREEN = 55;

//124 = blue
//200 = pink    
//216 = white
//46  = beige
//36  = yellow    
//215 = gray
//104 = teal
//23  = orange
//182 = purple
var MARKER_COLORS = new Array( 124, 200, 216, 46, 36, 215, 104, 23, 182 )
var MARKER_COUNTER = 0;

var formPartOne = ""
var formPartTwo = ""

var formButtons = ""
var actionA = "getFormInfo(); validateAddresses();"
var actionB = "addNewLocation()";
formButtons += "<input type=button id='Validate Addresses' value=\"Validate Addresses\" onclick = \"" + actionA + "\"></input>\n"
formButtons += "<input type=button id='Add New Location' value=\"+1 Location\" onclick = \"" + actionB + "\"></input><br><br>\n"

var totalMouseMovement = 0
var MAP_RESIZE_CHECK_INTERVAL = 1//200

var VALIDATE_ADDRESS_DELAY =  250
var bannerHTML = ""
var buttonsHTML = ""
var resultsHTML = ""
var resultsWrapHTML = ""

var printWindow;
var markerList = new Array();

function Location(address, description)
{
 this.address = address
 this.description = description
 this.geocode = null
 this.index = null
 this.zipcode = null;
}

function load() {
  if (GBrowserIsCompatible()) {
      addMap();
  }
  else
  {
      alert("Unfortunately, this site is not compatible with your browser.")
  }
}

//Takes two Location objects
function getRouteNoSteps(location1, location2){
    getRouteGen(location1, location2, 0)
}

//Takes two Location objects
function getRouteWithSteps(location1, location2){
    getRouteGen(location1, location2, 1)
}

//Takes two Location objects, and 0/1
function getRouteGen(location1, location2, getSteps)
{            
    var gdir = new GDirections()
    gdir.id = globalID
    gdir.origin = location1
    gdir.destination = location2            
    globalID += 1
    if (getSteps == 1)
    {
        gdir.load( "from: " + location1.address + " to: " + location2.address, {getSteps:true, getPolyline:true} )
    }
    else
    {
        gdir.load( "from: " + location1.address + " to: " + location2.address )
    }
    outstandingLoadRequests += 1
    totalLoadCalls += 1
    GEvent.addListener(gdir, "load", function(){onGDirectionsLoad(gdir);} );
    GEvent.addListener(gdir, "error", function(){handleErrors(gdir);} );
}

function onGDirectionsLoad(gDirObject){
    gDirObject.distance = gDirObject.getDistance().meters
    //alert(gDirObject.distance)

    pline = gDirObject.getPolyline()
    polylines.push( pline )
    map.addOverlay( pline )
    routeList.push( gDirObject )
    routeReceived = 1
    outstandingLoadRequests -= 1
    updateDirectionDisplay()
}

function handleErrors(gdir){
   //alert("error")
   if (gdir.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
     alert("No corresponding geographic location could be found for one of the specified addresses. This may be due to the fact that the address is relatively new, or it may be incorrect.\nError code: " + gdir.getStatus().code);
   else if (gdir.getStatus().code == G_GEO_SERVER_ERROR)
     alert("A geocoding or directions request could not be successfully processed, yet the exact reason for the failure is not known.\n Error code: " + gdir.getStatus().code);
   else if (gdir.getStatus().code == G_GEO_MISSING_QUERY)
     alert("The HTTP q parameter was either missing or had no value. For geocoder requests, this means that an empty address was specified as input. For directions requests, this means that no query was specified in the input.\n Error code: " + gdir.getStatus().code);	     
   else if (gdir.getStatus().code == G_GEO_BAD_KEY)
     alert("The given key is either invalid or does not match the domain for which it was given. \n Error code: " + gdir.getStatus().code);
   else if (gdir.getStatus().code == G_GEO_BAD_REQUEST)
     alert("A directions request could not be successfully parsed.\n Error code: " + gdir.getStatus().code);	    
   else alert("An unknown error occurred.")
}

//given a list of GDirections objects,
//Return the HTML string of all of the steps
function getResultHTMLString( gList )
{
    result = ""            
    for(i=0; i<gList.length; i++)
    {
        counter = 2
        for(j=0; j<gList[i].getNumRoutes(); j++)
        {
            gList[i].origin.address = gList[i].origin.address.replace(", USA", "")
            gList[i].destination.address = gList[i].destination.address.replace(", USA", "")
            
            result += "1. Start at " + gList[i].origin.address + ".<br>"                    

            for(k=0; k<gList[i].getRoute(j).getNumSteps(); k++)
            {
                result += counter + ". "
                
                line = gList[i].getRoute(j).getStep(k).getDescriptionHtml()
                //alert(line)
                line = line.replace("</div>", " ")
                line = line.replace("<div class=\"\">", " ")
                line = line.replace("<div class=\"google_impnote\">", " ")
                line = line.replace("<div class=\"google_note\">", " ")
                line = line.replace("right", "Right")
                line = line.replace("left", "Left")
                line = line.replace("east", "East")
                line = line.replace("west", "West")
                line = line.replace("north", "North")
                line = line.replace("south", "South")                        
                //alert(line)
                result += line

                //for(t=0; t<5; t++)
                //    result += "&nbsp"

                result += " - go "

                dist = gList[i].getRoute(j).getStep(k).getDistance().html
                                    
                if ( dist.indexOf("ft") != -1 )
                {
                    dist = "< 0.1 mi"
                }

                result += dist
                result += "<br>\n"
                counter += 1
            }
            result += counter + ". "                    
            result += "Arrive at " + gList[i].destination.address + "<br>"
            if (gList[i].destination.description.length > 0)
            {
                result += "<br>" + "___ " + gList[i].destination.description
            }
        }
        result += "<br>------------------------------------------------------<br>\n"
    }
    return result// + "<br>done"
}


/*
function processGeocoderResults(point, index)
{
    if (!point) //Geocode not found
    {
    }
    else //Geocode found!
    {
        locationList[index].geocode = point
    }

    outstandingGeocoderRequests -= 1            
}

function geocodeAddress( address, index )
{
    outstandingGeocoderRequests += 1
    geocoder.getLatLng( address, function(point){ processGeocoderResults(point, index); } )
}

*/



function processGeocoderResults(response, index)
{
    if (!response || response.Status.code != 200) //Geocode not found
    {
    }
    else //Geocode found!
    {
        //alert( response.Placemark.length )
        if (response.Placemark.length > 1)
        {
            //alert( response.Placemark )
        }

        
        places = response.Placemark;
        place = response.Placemark[0];
        //var zipCode = place.AddressDetails.Country.AdministrativeArea.SubAdministrativeArea.Locality.LocalityName //PostalCode.PostalCodeNumber
        point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);

        //alert(zipCode)
        
        locationList[index].address = place.address
        locationList[index].geocode = point
        //locationList[index].zipcode = zipCode                
    }

    outstandingGeocoderRequests -= 1
}

function geocodeAddress( address, index )
{
  //outstandingGeocoderRequests += 1
  geocoder.getLocations(address, function(response){ processGeocoderResults(response, index); });
}








function updateFormDisplay()
{
    hasHome = false
    disableCalcButton = false
    result = "Invalid addresses:\n"
    for(i=0; i<locationList.length; i++)
    {
        if (locationList[i])
        {
            document.getElementById("address" + locationList[i].index).value = locationList[i].address
            if (locationList[i].geocode)
            {
                if (locationList[i].index == 0)
                {
                    hasHome = true
                }
                document.getElementById("address" + locationList[i].index).style.color = "green"
                document.getElementById("address" + locationList[i].index).style.fontWeight = "bold"                    
            }
            else
            {
                if (locationList[i].index > 0)
                    label = "Location " + locationList[i].index
                else
                    label = "Home"
                result += label + ": " + locationList[i].address + "\n"
                disableCalcButton = true
                document.getElementById("address" + locationList[i].index).style.color = "red"
                document.getElementById("address" + locationList[i].index).style.fontWeight = "bold"
            }
        }
    }

    //if (locationList.length > 0)
    //{
    //    document.getElementById("Calculate Directions").disabled = disableCalcButton
    //}

    //alert(

    if (disableCalcButton)
    {
        alert(result)
        hideMap( false )                
    }
    else if ( noAddressesGiven() )//(locationList.length == 0)
    {
        alert("No addresses were given.")
        hideMap( false )
    }
    else
    {
        alert("All addresses valid!")
        showMap( false )
        addAllMarkers()                
    }
}

function removeAllMarkers()
{
    for(i=0; i<markerList.length; i++)
    {
        if ( markerList[i] )
        {
            map.removeOverlay( markerList[i] )
        }
    }
    markerList = new Array()
}

function validateAddresses()
{
    finalList = new Array()
    routeList = new Array()

    //map.clearOverlays()
    removeAllMarkers()
    
    updateDirectionDisplay()
    count = 0 //VALIDATE_ADDRESS_DELAY
    for(i=0; i<locationList.length; i++)
    {
        if (locationList[i])
        {
            //geocodeAddress( locationList[i].address, i )
            outstandingGeocoderRequests += 1
            cmd = "geocodeAddress( locationList[" + i + "].address, " + i + " )"
            setTimeout(cmd, count)
            count = count + VALIDATE_ADDRESS_DELAY
        }
    }
    
    checkGeocoderStatus(1, updateFormDisplay)                        
}

function addMap()
{
    map = new GMap2(document.getElementById("map"));
    map.addControl(new GLargeMapControl());            
    //map.addControl(new GMapTypeControl());
    map.addControl(new ExtMapTypeControl({showTraffic: true, showTrafficKey: true}) ); //traffic + main nav
    map.addControl( new GScaleControl() );
    map.setCenter(new GLatLng(37.4419, -122.1419), 13);
    resizeMap( MAP_WIDTH, MAP_HEIGHT );
    mapDiv = document.getElementById("map")
    mapDiv.onmouseover = function(){ mapCurrentlyMousedOver = true; }
    mapDiv.onmouseout = function(){ mapCurrentlyMousedOver = false; }
    addUndoButton();
    addResizingBox(); //add the resizing box to the map;
    addLogo();
    tooltip = document.createElement("div");            
    tooltip.style.visibility="hidden";
    //map.getPane(G_MAP_FLOAT_PANE).appendChild(tooltip);
    document.getElementById("map").appendChild(tooltip);            
    hideMap( true )    
}

//Add a small black box to the bottom-right of the map, which will be used to resize
function addResizingBox()
{
    var boxPosition = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(0,0));
    boxPosition.apply(document.getElementById("resizeBox"));
    var box = document.getElementById("resizeBox")
    box.onmouseover = function(){ resizeBoxCurrentlyMousedOver = true; doResize = true;}
    box.onmouseout = function(){ resizeBoxCurrentlyMousedOver = false; }            
    map.getContainer().appendChild( box );
}

//Keep track of when the resize is being clicked-and-dragged
function resizeBoxMouseDown( event )
{
    resizeBoxCurrentlyBeingHeld = true;
}

//Add undo button to map
function addUndoButton()
{
    //alert( document.getElementById("undoPicture").x )
    var undoPosition = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(400,10));
    undoPosition.apply(document.getElementById("undoPicture"));
    map.getContainer().appendChild( document.getElementById("undoPicture") );
    updateUndoButtonPosition()
}

//Add logo to map
function addLogo()
{
    //alert( document.getElementById("undoPicture").x )
    var logoPosition = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(400,10));
    logoPosition.apply(document.getElementById("logoPicture"));
    map.getContainer().appendChild( document.getElementById("logoPicture") );
    updateLogoPosition()            
}

//Generate form
function generateMainForm( numEntries, locList )
{
    numFormElements = 0
    //actionA = "getFormInfo(); validateAddresses();"
    //actionB = "addNewLocation()";
    result = ""
    result += "<form>\n"
        //result += "<input type=button id='Validate Addresses' value=\"Validate Addresses\" onclick = \"" + actionA + "\"></input><br><br>\n"
        //result += "<input type=button id='Add New Location' value=\"Add New Location\" onclick = \"" + actionB + "\"></input><br><br>\n"
        result += "<b>Home</b><br>\n"
        result += "<input onfocus=\"focusFormElement(this.id)\" type=\"text\" id=\"address0\" style='width:477;'></input>\n"
        result += "<br><br><hr><br>\n"
        for (count = 1; count<(numEntries+1); count++)
        {
            result += addFormLocation( count, locList )
            /*
            var add = DEFAULT_ADDRESS
            var des = DEFAULT_DESCRIPTION
            if (locList && locList.length >= count)
            {
                add = locList[count - 1].address
                des = locList[count - 1].description
                //alert( "in weird block" )
            }
            result += "<b>Location " + count + "</b><br>\n"
            result += "<input onfocus=\"focusFormElement(this.id)\" type=\"text\" id=\"address" + count + "\" value=\"" + add + "\" style='width:477;'></input>\n"
            result += "<br>\n"
            result += "<textarea onfocus=\"focusFormElement(this.id)\" id=\"description" + count + "\" rows=\"5\" cols=\"57\">" + des + "</textarea>\n"
            result += "<br><br>\n"
            */
        }

        formPartOne = result
        result = ""
        //actionB = "getFormInfo(); processListByClosest(locationList); printOutstandingLoads();"
        //actionB = "getDirectionsInOrder( finalList ); printOutstandingLoads();"
        //actionB = "updateDirectionDisplay()"
        //result += "<input type=button id='Validate Addresses' value=\"Validate Addresses\" onclick = \"" + actionA + "\"></input>\n"
        //result += "<input type=button id='Add New Location' value=\"Add New Location\" onclick = \"" + actionB + "\"></input><br><br>\n"            
        //result += "<input disabled=true type=button id='Calculate Directions' value=\"Calculate Directions\" onclick = \"" + actionB + "\"></input>\n"
        //result += "<input type=button id='Undo' value=\"Undo\" onclick = \"" + "undoLastClick()" + "\"></input>\n"
    result += "</form>\n"
    formPartTwo = result
    document.getElementById("form").innerHTML = formPartOne + formPartTwo
    showFormButtons()
    preloadMarkers( numFormElements )
}

function addFormLocation (count, locList)
{
    result = ""
    //alert( numFormElements )
    numFormElements = parseInt(numFormElements) + 1
    var add = DEFAULT_ADDRESS
    var des = DEFAULT_DESCRIPTION
    
    if (locList && locList.length >= count)
    {
        add = locList[count - 1].address
        des = locList[count - 1].description
        
    }
    
    result += "<b>Location " + numFormElements + "</b><br>\n"
    result += "<input onfocus=\"focusFormElement(this.id)\" type=\"text\" id=\"address" + numFormElements + "\" value=\"" + add + "\" style='width:477;'></input>\n"
    result += "<br>\n"
    result += "<textarea onfocus=\"focusFormElement(this.id)\" id=\"description" + numFormElements + "\" rows=\"5\" cols=\"57\">" + des + "</textarea>\n"
    result += "<br><br>\n"
    return result;
}

function addNewLocation()
{

    //document.getElementById("results").innerHTML += "Hello<br>"            
    //alert( document.getElementById("results").innerHTML)
    
    document.getElementById("results")
    //save data
    var addresses = new Array();
    var descriptions = new Array();

    for( z = 0; z<=numFormElements; z++ )
    {
        addresses.push( document.getElementById("address" + z).value )
        if ( document.getElementById("description" + z) )
        {
            descriptions.push( document.getElementById("description" + z).value )
        }
        else
        {
            descriptions.push( null )
        }
    }
    
    document.getElementById("form").innerHTML = document.getElementById("form").innerHTML.replace("</form>","")
    document.getElementById("form").innerHTML += addFormLocation() + "</form>"
    //alert( document.getElementById("form").innerHTML )

    for( z = 0; z<numFormElements; z++ )
    {
        document.getElementById("address" + z).value = addresses[z]
        if ( document.getElementById("description" + z) )
        {
            document.getElementById("description" + z).value = descriptions[z]
        }
    }

    preloadMarker( numFormElements )

    //restore data
}


//Generate textblock to parse
function generateTextBlock()
{
    var actionA = "processTextBlock(document.getElementById('textBlock').value)"            
    result = ""
    result += "<b><a href='tutorial.html' target='_blank'><img src='images/icon_caution.png' border=0>Please read the VRP Tutorial in order to learn how to properly use this feature.</a></b><br><br>"
    result += "<form>\n"
        result += "<input type=button id='Parse' value=\"Parse\" onclick = \"" + actionA + "\"></input>\n"
        result += "<br><br>\n"            
        result += "<textarea id=\"textBlock\" rows=\"25\" cols=\"80\">" + "" + "</textarea>\n"
        result += "<br><br>\n"
        result += "<input type=button id='Parse' value=\"Parse\" onclick = \"" + actionA + "\"></input>\n"
    result += "</form>\n"
    document.getElementById("form").innerHTML = result                  
}

function processTextBlock( val )
{
    var textArray = val.split("\n")

    var tempArray = new Array()

    var res = ""
    var add = ""
    var des = ""
    
    for(i=0; i<textArray.length; i++)
    {
        var line = textArray[i]
        
        if (line.substring(0,3) == "---") //Add location
        {
            if (add.length > 0)
            {
                tempArray.push( new Location(add, des) )
                add = ""
                des = ""
                continue
            }
        }
        else if (add == "") //If this is the first line of the location block, assign it to address
        {
            add = line
        }
        else
        {
            if (des)
            {
                des += "\n"
            }
            des += line                    
        }
    }

    if (add.length > 0)
    {
        tempArray.push( new Location(add, des) )
    }
    
    //numFormElements = (tempArray.length + 5)
    numFormElements = ( tempArray.length )            
    generateMainForm( numFormElements, tempArray )

    /*

    for(i=0; i<tempArray.length; i++)
    {
        res += "Location " + (i + 1) + "\n"
        res += "add:" + tempArray[i].address + "\n"
        res += "des:" + tempArray[i].description + "\n\n"
    }

    alert(res)

    */
}


//Callback for selecting number of sales
function applySaleNumberSelection(){
    box = document.saleNumberForm.saleNumberSelect
    selection = box.options[box.selectedIndex].value
    if (selection != "Textblock")
    {
        numFormElements = selection
        generateMainForm( parseInt( selection ), null )
    }
    else
    {
        generateTextBlock()
    }
}

//Generate dropdown box containing number of sales choices
function generateSaleNumberSelection()
{            
    torun = "applySaleNumberSelection()"
    document.write("<b>How many locations do you wish to visit?</b><br><br>")
    document.write("<form name='saleNumberForm' action=''>")
    document.write("<select id='saleNumberSelect' name='saleNumberSelect' onchange="+ torun + ">")
    document.write("<option value='--'>--</option>")
    document.write("<option value=\"Textblock\">Bulk Entry</option>")
    document.write("<option value=5>5</option>")
    document.write("<option value=10>10</option>")
    document.write("<option value=25>25</option>")
    document.write("<option value=50>50</option>")
    document.write("<option value=75>75</option>")            
    /*
    for(x=10; x<=100; x+=10)
    {
        document.write("<option value=" + x + ">" + x + "</option>")
    }
    */
    //document.write("<option value=\"Textblock\">Bulk Entry</option>")
    document.write("</select>")
    document.write("</form>")
    document.getElementById("saleNumberSelect").value = "--"
}


function getFormInfo()
{            
    locationList = new Array()
    for(i=0; i<=(numFormElements); i++)
    {                
        add = document.getElementById("address"+i).value
        if (i > 0)
        {
            des = document.getElementById("description"+i).value
        }
        else
        {
            des = "Home"
        }
        if (add != DEFAULT_ADDRESS && add.replace(" ", "") != "")
        {
            newloc = new Location( add, des )
            newloc.index = i
            locationList.push( newloc )
        }
        //TEST CODE, IF BREAKS, REMOVE
        else
        {
            locationList.push( null )                    
        }
        
    }
}

//What happens when you click or tab to a form textbox
function focusFormElement( id )
{
    if (document.getElementById(id).value == DEFAULT_ADDRESS || document.getElementById(id).value == DEFAULT_DESCRIPTION)
    {
        document.getElementById(id).value = ""
    }
    document.getElementById(id).style.color = "black"
    document.getElementById(id).style.fontWeight = "normal"
    //document.getElementById("Calculate Directions").disabled = true
}

function showFormButtons()
{
    document.getElementById("buttonControlsTop").innerHTML = formButtons
    document.getElementById("buttonControlsBottom").innerHTML = formButtons            
    document.getElementById("buttonControlsTop").style.visibility = "visible"
    document.getElementById("buttonControlsBottom").style.visibility = "visible"
    document.getElementById("buttonControlsTop").style.height = "auto"
    document.getElementById("buttonControlsBottom").style.height = "auto"            
}

//timeout - Length of time increment for setTimeout call
//callback - Function to execute once all GDirections objects have been processed
function checkLoadStatus( timeout, callback)
{
    if (outstandingLoadRequests > 0)
    {
        param = "checkLoadStatus(" + timeout + ", " + callback + "\)"
        setTimeout(param, timeout)
    }
    else
    {
        callback()
    }
}

//timeout - Length of time increment for setTimeout call
//callback - Function to execute once all Geocoder calls have been processed
function checkGeocoderStatus( timeout, callback)
{
    if (outstandingGeocoderRequests > 0)
    {
        param = "checkGeocoderStatus(" + timeout + ", " + callback + "\)"
        setTimeout(param, timeout)
    }
    else
    {                
        callback()
    }
}


//timeout - Length of time increment for setTimeout call
//callback - Function to execute once form is loaded
function checkFormLoadStatus( timeout, callback)
{
    if (!formLoaded)
    {
        param = "checkFormLoadStatus(" + timeout + ", " + callback + "\)"
        setTimeout(param, timeout)
    }
    else
    {                
        callback()
    }
}

function displayIDs()
{
    result = ""
    for(i=0; i<routeList.length; i++)
    {
        result += routeList[i].id + "\n"
    }
    alert(result)
}

function sortByID(a, b)
{
    return a.id - b.id
}

function sortByDistance(a, b)
{
    return a.distance - b.distance
}

//Clear routeList
function clearRouteList()
{
    routeList = new Array()
}

//Do it
function processListByClosest( locList )
{
    
    if (locList.length <= 1)
    {
        finalList.push( locList[0] )

        //We're done, and have final list
        //alert(finalList)
        //finalList = new Array()
        getDirectionsInOrder( finalList )                
    }
    else
    {
        clearRouteList()
        origin = locList[0]
        finalList.push( origin )            
        locList = locList.slice(1)            
        for(i = 0; i<locList.length; i++)
        {
            getRouteNoSteps( origin , locList[i] )
        }
        
        checkLoadStatus(1, function(){
            routeList.sort(sortByDistance);
            locList = new Array();
            for(i=0; i<routeList.length; i++)
            {
                locList.push( routeList[i].destination );
            }
            processListByClosest( locList );                    
        })
    }
    
}

//Get the directions of the given LocationList in order, and print the results
function getDirectionsInOrder( locList )
{
    clearRouteList()

    for(i = 0; i < (locList.length - 1); i++)
    {
        getRouteWithSteps( locList[i] , locList[i+1] )
    }

    finalList = new Array()

    checkLoadStatus(1, function(){
        result = ""
        routeList.sort(sortByID)
        result = getResultHTMLString(routeList)
        document.getElementById("results").innerHTML = result                            
    })            
}

//colorNumber = 001->216
function getMarkerAddress(colorNumber, text)
{
    if (colorNumber / 100 < 1)
        colorNumber = "0" + colorNumber
    result = "http://yardsales.lizndom.com/vrp/markers/numbered_marker.php?image=pushpins/webhues/" + colorNumber + ".png&text=" + text
    return result
}


function getMarker(point, colorNumber, text, clicked)
{
    var myIcon = new GIcon(baseIcon);
    myIcon.image = getMarkerAddress(colorNumber, text)
    var marker = new GMarker(point, {icon:myIcon});
    marker.text = text //Whatever is displayed on the actual marker ("2", "H")
    marker.clicked = clicked
    marker.timesClicked = 0

    //alert("getMarker calling getLocation with " + marker.text)
    marker.location = getLocation( marker.text )

    tooltipText = marker.location.address + "<br>------------------<br>"

    var descriptionText = ""
        
    if (marker.location.description.length < 200)
    {
        descriptionText = marker.location.description
    }
    else
    {
        descriptionText = marker.location.description.substring(0,297) + "..."
    }

    
    var countMe = 0

    var tempLength = ( marker.location.address.length * 1.1)

    var lineLength = 0

    if (tempLength > 40)
    {
        lineLength = tempLength
    }
    else
    {
        lineLength = 40
    }
    
    for (z=0; z< descriptionText.length; z++)
    {
        currentChar = descriptionText.charAt(z)
        if (currentChar == " " && (countMe >= lineLength))
        {
            tooltipText += "<br>"
            countMe = 0
        }
        else
        {
            tooltipText += currentChar
            countMe++;
        }
    }
    
    
    marker.tooltip = '<div id="tooltipDiv" class="tooltip"><nobr>'+tooltipText+'</nobr></div>';
    
    //  ======  The new marker "mouseover" and "mouseout" listeners  ======
    GEvent.addListener(marker,"mouseover", function() {
        showTooltip(marker);
    });
    
    GEvent.addListener(marker,"mouseout", function() {
        tooltip.style.visibility="hidden"
    });               

    

    //When marker is clicked...
    GEvent.addListener(marker, "click", function() {
        //marker.openInfoWindowHtml("Marker #" + "</b>");
        //var newicon = new GIcon(baseIcon);
        //newicon.image = getMarkerAddress(55, marker.text)
        //var newmarker = new GMarker(marker.getPoint(), newicon);
        newmarker = null
        
        if (marker.clicked && false) //clicked -> not clicked
        {
            //This is ignored for now
            newmarker = getMarker(marker.getPoint(), MARKER_RED, marker.text, false)
        }
        else //not clicked -> clicked
        {
            newmarker = getMarker(marker.getPoint(), MARKER_GREEN, marker.text, true)

            /*
            if (newmarker.text == "H")
                number = 0
            else
                number = newmarker.text
            
            if (hasHome || true)
            {
                locIndex = parseInt( number )
            }
            else
            {
                locIndex = parseInt( number ) - 1
            }

            currentLocation = locationList[ locIndex ]
            */
            
            currentLocation = getLocation( newmarker.text )

            finalList.push( currentLocation )
            //alert(finalList)
            finalLen = finalList.length

            if (finalLen > 1)
            {
                //points = new Array()
                var from = finalList[ finalLen - 2]
                var to = finalList[ finalLen - 1]
                getRouteWithSteps(from, to)
            }
            
        }
        newmarker.clicked = !marker.clicked
        newmarker.timesClicked = marker.timesClicked + 1
        map.addOverlay(newmarker)
        map.removeOverlay(marker)

        //Update markers in finalList
        for(z=0; z<finalList.length; z++)
        {
            if (finalList[z].marker.text == newmarker.text)
            {
                finalList[z].marker = newmarker
            }
        }
        
        //updateDirectionDisplay()                
        });

    markerList.push( marker )
    return marker;
}

function addAllMarkers()
{
    bounds = new GLatLngBounds();

    //map.clearOverlays()
    removeAllMarkers()

    for(i=0; i<locationList.length; i++)
    {
        if (locationList[i] && locationList[i].geocode)
        {
            if (locationList[i].index >0)
            {
                label = locationList[i].index
                clicked = false
                color = MARKER_RED
            }
            else
            {
                label = "H"
                clicked = true
                color = MARKER_GREEN
                finalList.push(locationList[i])
            }
            var marker = getMarker(locationList[i].geocode, color, label, clicked)
            if (label == "H")
            {
                marker.timesClicked = 1
            }
            locationList[i].marker = marker
            bounds.extend( marker.getLatLng() )
            map.addOverlay(marker)
        }
    }

    /*
    if (locationList.length > 1)
        map.setCenter(locationList[1].geocode, 13)
    else
        map.setCenter(locationList[0].geocode, 13)
    */

    //set zoom/center of map to display all markers
    map.setZoom(map.getBoundsZoomLevel(bounds));
    map.setCenter(bounds.getCenter());
}

// ====== This function displays the tooltip ======
// it can be called from an icon mousover or a side_bar mouseover
function showTooltip(marker) {

    /*
    tooltip.innerHTML = marker.tooltip;
    var point=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.fromDivPixelToLatLng(new GPoint(0,0),true),map.getZoom());
    var offset=map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),map.getZoom());
    var anchor=marker.getIcon().iconAnchor;
    var width=marker.getIcon().iconSize.width;
    var height=tooltip.clientHeight;
    var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(offset.x - point.x - anchor.x + width, offset.y - point.y -anchor.y -height)); 
    pos.apply(tooltip);
    tooltip.style.visibility="visible";
    */
    
    

    
    tooltip.innerHTML = marker.tooltip;
    var point=map.getCurrentMapType().getProjection().fromLatLngToPixel(map.getBounds().getSouthWest(),map.getZoom());
    var offset=map.getCurrentMapType().getProjection().fromLatLngToPixel(marker.getPoint(),map.getZoom());
    var anchor=marker.getIcon().iconAnchor;
    var width=marker.getIcon().iconSize.width;
    var height=marker.getIcon().iconSize.height;
    var ttx = ( offset.x - point.x - anchor.x + width )
    var tty = ( - offset.y + point.y +anchor.y )                        

    var pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize( ttx, tty ) )
    pos.apply(tooltip);
    var ttWidth = tooltip.offsetWidth
    var ttHeight = tooltip.offsetHeight
    var mapDiv = document.getElementById("map")

    if ( (ttx + ttWidth) > parseInt(mapDiv.style.width) )
    {
        //ttx = parseInt(mapDiv.style.width) - ttWidth
        ttx = ttx - ttWidth - width
    }

    if ( (tty + ttHeight) > parseInt(mapDiv.style.height) )
    {
        //tty = parseInt(mapDiv.style.height) - ttHeight
        tty = tty - ttHeight - height
    }            
    
    pos = new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize( ttx, tty ) )
    pos.apply(tooltip);            
    tooltip.style.visibility="visible";            
    
}

//Given a marker's text ("2", "H"), returns the corresponding location
function getLocation( text )
{
    //alert(text)
    if (text == "H")
        number = 0
    else
        number = text
    
    if (hasHome || true)
    {
        locIndex = parseInt( number )
    }
    else
    {
        locIndex = parseInt( number ) - 1
    }

    //alert( locIndex )
    //alert( locationList[locIndex] )
    //alert( locationList )
    
    return locationList[ locIndex ]            
}

//Updates the results div that displays the directions
function updateDirectionDisplay()
{
    routeList.sort(sortByID)
    //alert(routeList)
    result = getResultHTMLString(routeList)
    document.getElementById("results").innerHTML = result
    return result;
}

function undoLastClick()
{
    if (finalList.length == 0)
    {
        return;
    }
    num = finalList.length - 1
    mark = finalList[num].marker

    if (polylines.length >= 0)
    {
        if (polylines.length >= 0)
        {
            var polyline = null
            pnum = polylines.length - 1
            if (pnum >= 0)
            {
                polyline = polylines[pnum]                    
                polylines = polylines.slice(0, pnum)
            }

            if (finalList.length > 0)
            {
                finalList = finalList.slice(0, num)
                routeList = routeList.slice(0, (routeList.length -1))
            }

            if (polyline)
            {
                map.removeOverlay(polyline)
            }
        }
        else
        {
        }
    
        //Apply undo actions to marker
        //If it has only been clicked once, then change it from green->red
        //else decrement its timesClicked variable
        if (mark.timesClicked <= 1)
        {
            newmarker = getMarker(mark.getPoint(), MARKER_RED, mark.text, false)
            //newmarker.timesClicked = mark.timesClicked - 1
            map.removeOverlay(mark)
            map.addOverlay(newmarker)
        }
        else
        {
            mark.timesClicked--
        }

        updateDirectionDisplay()
    }
    else
    {
        //alert("can't undo.")
    }
}

function resizeMap( newWidth, newHeight )
{
    mapDiv = document.getElementById("map")
    mapDiv.style.width = newWidth        
    mapDiv.style.height = newHeight
    map.checkResize()
}

function changeMapSize( dx, dy )
{
    mapDiv = document.getElementById("map")
    if ( parseInt(MIN_MAP_WIDTH) < 0 || ( parseInt(mapDiv.style.width) + dx > parseInt(MIN_MAP_WIDTH) ))
    {
        mapDiv.style.width = parseInt(mapDiv.style.width) + dx
        MAP_WIDTH = mapDiv.style.width
    }
    if (parseInt(MIN_MAP_HEIGHT) < 0 || ( parseInt(mapDiv.style.height) + dy > parseInt(MIN_MAP_HEIGHT) ))
    {
        mapDiv.style.height = parseInt(mapDiv.style.height) + dy
        MAP_HEIGHT = mapDiv.style.height
    }
    //map.checkResize()            
}

//Gets relevent information from mouse, saves to global variables
function pollMouse( event ) {
    tempX = event.screenX //save the current x-coord of the mouse in relation to the entire screen
    tempY = event.screenY //save the current y-coord of the mouse in relation to the entire screen
    mouseDX = tempX - mouseX //amount mouse x-coord moved since last poll
    mouseDY = tempY - mouseY //amount mouse y-coord moved since last poll
    mouseX = tempX 
    mouseY = tempY
}

//Runs while mouse moves
function watchMouse( event )
{
    var resizeBox = document.getElementById("resizeBox")            
    pollMouse( event ); //Update all mouse information
    totalMouseMovement += Math.abs(mouseDX) + Math.abs(mouseDY)
    var mapDiv = document.getElementById("map")

    
    
    if ( resizeBoxCurrentlyBeingHeld ) // && doResize ) //if the resize box is being held
    {
        
        changeMapSize( mouseDX, mouseDY ) //dynamically resize the map
        updateUndoButtonPosition()
        updateLogoPosition()
        if (totalMouseMovement >= MAP_RESIZE_CHECK_INTERVAL)
        {
            totalMouseMovement = 0
            map.checkResize()
        }
    }
    
    
    /*
    if ( mapCurrentlyMousedOver && !resizeBoxCurrentlyMousedOver )
    {
        doResize = false;
    }
    else
    {
        doResize = true;
    }
    */

}

function updateUndoButtonPosition()
{
    var mapDiv = document.getElementById("map")
    var undoPic = document.getElementById("undoPicture")
    var newX = (parseInt(mapDiv.style.width) / 2) // + mapDiv.style.left
    newX = parseInt(newX) - (parseInt(document.getElementById("undoImage").width) / 2)
    undoPic.style.left = parseInt(newX)
}


function updateLogoPosition()
{
    var mapDiv = document.getElementById("map")
    var logoPic = document.getElementById("logoPicture")
    var newX = (parseInt(mapDiv.style.width) / 2) // + mapDiv.style.left
    newX = parseInt(newX) - (parseInt(document.getElementById("logoImage").width) / 2)
    logoPic.style.left = parseInt(newX)
}                    

//Parses address string and returns zipcode
function getZipCode( address )
{
    var result;

    return result;
}

function hideMap( force )
{
    if ( (!mapHidden()) || force)
    {
        mapDiv = document.getElementById("map")
        MAP_WIDTH = mapDiv.style.width
        MAP_HEIGHT = mapDiv.style.height
        mapDiv.style.width = 0
        mapDiv.style.height = 0
        mapDiv.style.visibility = "hidden"
        document.getElementById("results").style.visibility = "hidden"
        document.getElementById("resultsWrap").style.height = 0
        document.getElementById("resultsWrap").style.visibility = "hidden"
        resultsHTML = document.getElementById("results").innerHTML
        document.getElementById("results").innerHTML = ""
        document.getElementById("resultsWrap").style.overflow = "hidden"
        document.getElementById("results").style.overflow = "hidden"                
        
        document.getElementById("banner").style.height = "auto"
        document.getElementById("banner").style.visibility = "visible"
        document.getElementById("banner").style.marginTop = "8px"
        document.getElementById("banner").innerHTML = bannerHTML
    }
}

function showMap( force )
{
    if ( mapHidden() || force )
    {            
        mapDiv = document.getElementById("map")
        mapDiv.style.width = MAP_WIDTH
        mapDiv.style.height = MAP_HEIGHT
        updateUndoButtonPosition()
        updateLogoPosition()
        mapDiv.style.visibility = "visible"
        
        document.getElementById("results").style.visibility = "visible"
        document.getElementById("results").innerHTML = resultsHTML
        document.getElementById("resultsWrap").style.height = "auto"
        document.getElementById("resultsWrap").style.visibility = "visible"        
        document.getElementById("resultsWrap").style.overflow = "visible"
        document.getElementById("results").style.overflow = "visible"

        
        document.getElementById("banner").style.height = 0
        document.getElementById("banner").style.visibility = "hidden"
        document.getElementById("banner").style.marginTop = "0px"
        bannerHTML = document.getElementById("banner").innerHTML
        document.getElementById("banner").innerHTML = ""

        map.checkResize()
    }
    scroll(0,0)    
}

function noAddressesGiven()
{
    for(var a=0; a < locationList.length; a++)
    {
        if ( locationList[a] != null)
        {
            //alert( locationList[a] )
            return false;
        }
    }
    return true;
}

function mapHidden()
{
    return ( mapDiv.style.visibility == "hidden" )
}

function printDirections()
{
    var result = ""
    result += "<html><title>Dom & Liz's Visual Route Planner</title><body>"
    result += updateDirectionDisplay()
    result += "</body></html>"
    printWindow = window.open("","")
    printWindow.document.write ( result )
    printWindow.document.close()
    printWindow.focus()
    setTimeout("printWindow.print()", 100)
    setTimeout("checkPrintWindow()", 500)
}

function checkPrintWindow()
{
    if (!printWindow)
    {
        alert("Your browser did not allow the Directions window to open.\n\nPlease change your popup-blocker settings to allow popup windows from this site.")
    }
}

function preloadMarkers( num )
{
    document.getElementById("preload").innerHTML = ""    
    preloadMarker( "H" )
    for( i=1; i <= num; i++ )
    {
        preloadMarker( i )
    }
    document.getElementById("preload").innerHTML += "<img src=\"http://www.google.com/mapfiles/shadow50.png\"></img>"
}

function preloadMarker( number )
{
    var marker = ""
    var result = ""
    marker = "http://yardsales.lizndom.com/vrp/markers/numbered_marker.php?image=pushpins/webhues/" + "010" + ".png&text=" + number
    result += "<img src=\"" + marker + "\">"
    marker = "http://yardsales.lizndom.com/vrp/markers/numbered_marker.php?image=pushpins/webhues/" + "055" + ".png&text=" + number
    result += "<img src=\"" + marker + "\">"
    document.getElementById("preload").innerHTML += result
}

function doTest()
{
    document.write("<b>Loading</b>")        
    loc1 = "20 Pocahontas Drive Peabody Ma"
    loc2 = "22 Pocahontas Drive Peabody Ma"
    loc3 = "Houston, TX"

    for(x=0; x<10; x++)
    {
        getRouteWithSteps(loc1, loc3)            
    }

    //checkLoadStatus(1, function(){ document.getElementById("results").innerHTML = getResultHTMLString(routeList) })
    //checkLoadStatus(1, function(){ alert("done") })
    checkLoadStatus(1, function(){ routeList.sort(sortByID); displayIDs();})            
}

function testProcessList()
{
    loc1 = new Location( "Boston, MA", "")
    loc2 = new Location( "Burlington, VT", "")
    loc3 = new Location( "Framingham, MA", "")
    loc4 = new Location( "Providence, RI", "")
    loc5 = new Location( "Provincetown, MA", "")
    arr = new Array(loc1, loc2, loc3, loc4, loc5)
    processListByClosest(arr)
    //getDirectionsInOrder(arr)
}

function heyhey()
{
    alert("hi")
}

function printOutstandingLoads()
{
    if (outstandingLoadRequests > 0)
    {
        document.getElementById("debug").innerHTML += totalLoadCalls + " direction requests made, " + (totalLoadCalls - outstandingLoadRequests) + " direction requests processed.<br>"
    }
    setTimeout("printOutstandingLoads()", 3000)
}

