var instance;

function stationClick() {
    tipAFriend(0, 0, 0, instance.number);
    leftBlock.updateDetails(instance);
    return false;    
}
    
    /**
 * Classe contenant les donn�es d'une station

 TODO:
 - recherche + handling des recherches venant du bloc rechercher une station
 */
function Station (name, number, address, fullAddress, latitude, longitude, opened, bonus) {
    this.name = name;
    this.number = number;
    this.address = address;
    this.fullAddress = fullAddress;
    this.ticket = 0;
    this.opened = opened;
    this.bonus = bonus;
    this.lat = latitude;
    this.lng = longitude;
    this.marker = null;
    this.state = 1; // 1 pour donn�es de base charg�es, 2 pour donn�es �tendues charg�es
    this.drawn = false; // false si le marker n'a pas �t� dessin� (avec Station.drawMarker() ), true sinon
    this.availableBikes = 0;
    this.freeCapacity = 0;
    this.totalCapacity = 0;

    //gestion des �v�nements

    this.createMarker = function (myIcon) {
        this.marker = new GMarker( new GLatLng( this.lat, this.lng), {icon:myIcon} );
        var instance = this;
        GEvent.addListener(this.marker, "click", function() {
            instance.openInfoWindow();
        } );
    }

    /**
     * Dessine le marqueur associ� � la station
     */
    this.drawMarker = function() {
        if(! this.drawn && this.state >= 1) {
            map.addOverlay(this.marker);
            this.drawn = true;
        }
    }

    /**
     * Ouvre l'infobulle de la station
     * ATTENTION : ne pas utiliser sur des marqueurs dessin�es par GMarkerManager !
     */
    this.openInfoWindow = function () {
        map.closeInfoWindow();

        var html = "<div class=\"infobulle\">";
//-        if(this.name != "") {
//-            html += "<p class=\"titre\">"+this.name+"</p>";
//-            html += "<p class=\"numero\">"+GmapsTexts.station_num+" "+this.number+"</p>";
//-        } else {
            html += "<p class=\"titre\">"+GmapsTexts.station_num+" "+this.number+"</p>";
//-        }

        if(this.address != "") {
            html += "<p>"+this.address+"</p>";
        }

        // si elles ne sont pas en cache, va chercher les infos de disponibilit� sur le webservice
        if(this.state == 1) {
            html += "<div class=\"details\"><p><b>"+GmapsTexts.station_details+"</b></p>";
            html += "<p>"+GmapsTexts.loading_message+"</p></div>";
        }
        else {
            html += "<div class=\"details\"><p>"+GmapsTexts.available_bikes+" <strong>"+this.availableBikes+"</strong></p>";
            html += "<p>"+GmapsTexts.free_capacity+" <strong>"+this.freeCapacity+"</strong></p></div>";
        }
        html += "<a href=\"#\" id=\"getStationDetails\" onclick=\"stationClick();\">"+GmapsTexts.more_details+"</a>";
        //html += "<a href=\"#\" onclick=\"xajax_saveStationToSession("+this.number+");return false;\">"+GmapsTexts.link_addStation+"</a>";
        html += "<p>&nbsp;</p></div>";

        this.marker.openInfoWindowHtml(html);

        instance = this;

       /* var instance = this;
        var theLink = document.getElementById('getStationDetails');
        theLink.onclick = function () {
            //clic sur le lien "plus de d�tails" : actualise l'url envoyer � un ami, et ouvre la boite des d�tails
            tipAFriend(0, 0, 0, instance.number);
            leftBlock.updateDetails(instance);
            return false;
        }*/

        if(this.state == 1) {

            var request = GXmlHttp.create();
            request.open("GET", stationDetailsUrl + "/"+ this.number, true);
            request.onreadystatechange = function() {

                   if (request.readyState == 4) {
                    var xmlDoc = request.responseXML;
                    instance.availableBikes = xmlDoc.getElementsByTagName('available')[0].firstChild.nodeValue;
                    instance.freeCapacity = xmlDoc.getElementsByTagName('free')[0].firstChild.nodeValue;
                    instance.totalCapacity = xmlDoc.getElementsByTagName('total')[0].firstChild.nodeValue;
                    instance.ticket = xmlDoc.getElementsByTagName('ticket')[0].firstChild.nodeValue;

                    if(cacheEnabled) {
                        instance.state = 2;
                    }

                    var html = "<p>"+GmapsTexts.available_bikes+" <b>"+instance.availableBikes+"</b></p>";
                    html += "<p>"+GmapsTexts.free_capacity+" <b>"+instance.freeCapacity+"</b></p>";

                    var infoWin = map.getInfoWindow();
                    var content = infoWin.getContentContainers();
                    if ( content.length > 0) {
                        var ct = content[0].firstChild.getElementsByTagName('div')[0].getElementsByTagName('div');
                        if(ct.length > 0) {
                            ct[0].innerHTML = html;
                        }
                    }
                    else
                    {
                        setTimeout("station2(\"" + instance + "\", \"" + html + "\")",500);
                    }
                    //actualise l'url de "envoyer � un ami"
                    tipAFriend(0, 0, 0, instance.number);
                }
            }
            request.send(null);
        }
    }
}

function station2 (instance, html) {
    var infoWin = map.getInfoWindow();
    var content = infoWin.getContentContainers();
    if ( content.length > 0) {
        var ct = content[0].firstChild.getElementsByTagName('div')[0].getElementsByTagName('div');
        if(ct.length > 0) {
            ct[0].innerHTML = html;
        }
    }
}

/**
 * Classe contenant toutes les stations
 */
function Stations () {

    this.stations = [];
    this.startStation = null;        //r�f�rence vers la station qui doit �tre affich�e en premier, avec l'infobulle ouverte
    this.markers = [];                //contient les r�f�rences vers les marqueurs des stations "normales"
    this.closestMarkers = [];        //contient les r�f�rences vers les marqueurs les plus proches
    this.minDists = [];                //contient les distances des n plus proches stations, tri� par ordre croissant
    this.n = 0;     //nombre de stations � marquer comme "plus proches" (0 = d�sactiv�) -> ne pas changer la vlaeur � cet endroit !
    this.startIsClosest = false;
    this.init = false;

    /**
     * Ajoute la station dans la liste
     */
    this.add = function (newStation) {
        this.stations.push(newStation);
    }

    /**
     * Dessine tous les marqueurs de la carte
     * - desssine le marqueur de d�part par la m�thode Station.drawMarker
     * - dessine les autres par le syst�me GMarkerManager
     */
    this.drawAllMarkers = function () {
        mm = new GMarkerManager(map, {borderPadding:1});
        mm.addMarkers(this.markers,10,17);
        mm.addMarkers(this.closestMarkers,10,17);
        mm.refresh();

        if(this.startStation != null && ! this.startIsClosest) {
            this.startStation.createMarker(startIcon);
            map.addOverlay(this.startStation.marker);
            this.startStation.openInfoWindow();
            leftBlock.updateDetails(this.startStation);
        }
    }

    /**
     * Recalcule tous les marqueurs en s�parant les plus N proches de l'origine (orgin de type GLatLng)
     */
    this.computeClosest = function (origin) {

        //vide les tableaux de marqueurs
        this.markers = [];
        this.closestMarkers = [];
        this.minDists = [];
        this.startIsClosest = false;

        var c = map.getBounds();
        var j = 0;
        var isClosest = false;
        var toSort = [];

        if(this.startStation != null) { var x = this.startStation.lat; var y = this.startStation.lng; }
        else { var x = 0; var y = 0 };



        for(var i = 0; i < this.stations.length ; i++)
        {
            if(this.stations[i].lat != x && this.stations[i].lng != y || this.init == false) {
                var coords = new GLatLng (this.stations[i].lat, this.stations[i].lng)
                //si la station est affichable � l'�cran, et si la diff�renciation des N plus proches est activ�e
                if ( c.contains(coords) && this.n > 0) {

                    //alors on regarde si elle est parmis les N plus proches
                    var dist = origin.distanceFrom(coords);
                    isClosest = false;

                    if(j < this.n) {
                        //pour les premiers points de la boucle, ils sont forc�ment parmi les plus proches
                        //on les ins�re et on trie le tableau des plus proches
                        this.minDists[this.minDists.length] = dist;
                        this.minDists = ArrayFloatSort(this.minDists);
                        j++;
                    }
                    else {
                        //pour les autres, on regarde si ils sont parmi les N plus proches
                        dist = parseFloat(dist);
                        var biggest = parseFloat(this.minDists[this.minDists.length-1]);
                        if(dist < biggest) {
                            //si on a trouv� un plus proche, on remplace le plus �login� des anciens plus proches
                            //par le nouveau plus proche
                            this.minDists[this.minDists.length-1] = dist;
                            this.minDists = ArrayFloatSort(this.minDists);
                        }
                    }
                    toSort.push(this.stations[i]);
                }
                else {
                    //sinon, ajoute le marqueur dans le tableau des marqueurs "normaux"
                    if(this.stations[i].opened == 1 && this.stations[i].bonus == 0) {
                        this.stations[i].createMarker(normalIcon);
                    } else if(this.stations[i].opened == 1 && this.stations[i].bonus == 1) {
                        this.stations[i].createMarker(bonusIcon);
                    }else {
                        this.stations[i].createMarker(closedIcon);
                    }
                    this.markers.push(this.stations[i].marker);
                }
            }
        }    //fin du parcours de tous les points

        if(this.minDists.length > 0)
        {
            //ici on poss�de la distance du Nieme point le plus proche
            var thresold = this.minDists[this.minDists.length-1];

            //pour les points restants � trier, on regarde si leur distance est <= au seuil
            for(var i = 0; i< toSort.length; i++) {

                if(origin.distanceFrom(new GLatLng (toSort[i].lat, toSort[i].lng)) <= thresold && this.n > 0) {
                    //si elle est parmi les + proches, on change sa couleur et on la range a part
                    toSort[i].createMarker(closestIcon);
                    this.closestMarkers.push(toSort[i].marker);
                    //ici la station de d�part est �galeemnt la plus proche. on le marque pour ne pas afficher 2 fois la station de d�part
                    if(toSort[i].lat == x && toSort[i].lng == y && this.init == false) {
                        this.startIsClosest = true;
                    }
                }
                else {
                    //sinon, ajoute le marqueur dans le tableau des marqueurs "normaux"
                    if(toSort[i].opened == 1) {
                        toSort[i].createMarker(normalIcon);
                    } else {
                        toSort[i].createMarker(closedIcon);
                    }
                    this.markers.push(toSort[i].marker);
                }
            }
        }
    }

    /**
     * Renvoie la station d'identifiant "number"
     */
    this.getStationByNumber = function (number) {
        for(var i = 0 ; i < this.stations.length ; i ++) {
            if(this.stations[i].number == number) {
                return this.stations[i];
            }
        }
        return null;
    }
}

function Arrondissement (number, center, zoom, bounds) {
    this.number = number;
    this.center = center;
    this.zoom = zoom;
    this.bounds = bounds;

    this.toString = function () {
        return "number="+this.number+", center="+this.center+", zoom="+this.zoom;
    }
    this.contains = function (coords) {
        return this.bounds.contains(coords);
    }
}

function Arrondissements() {
    this.arrdts = new Array();

    this.add = function (arrdt) {
        this.arrdts.push(arrdt);
    }
    this.getByNumber = function(number) {
        for(var i = 0; i < this.arrdts.length ; i++) {
            if(this.arrdts[i].number == number) {
                return this.arrdts[i];
            }
        }
        return false;
    }
}

function Home() {
    this.isEnabled = false;
    this.icon = null;
    this.lat = 0;
    this.lng = 0;
    this.marker = null;

    /**
     * Cr�ation de la home aux coordonn�es sp�cifi�es
     */
    this.create = function (lat, lng) {
        this.icon = homeIcon;
        this.lat = lat;
        this.lng = lng;
        map.closeInfoWindow();
        this.marker = new GMarker( new GLatLng( this.lat, this.lng), {icon:homeIcon, draggable: true} );
        map.addOverlay(this.marker);
        this.isEnabled = true;


        //gestion des �v�nements
        var instance = this;
        GEvent.addListener(this.marker, "dragstart", function() {
            map.closeInfoWindow();
        } );
        GEvent.addListener(this.marker, "dragend", function() {
              //op�rations men�es lors du d�placement de la home
              var newPoint = instance.marker.getPoint();
              this.lat = newPoint.lat();
              this.lng = newPoint.lng();
              map.panTo(newPoint);
              instance.computeClosestPoints();
          });
          GEvent.addListener(this.marker, "click", function() {
            instance.marker.openInfoWindowHtml('<div style="width:200px;"><p><b>'+GmapsTexts.home_info_title+'</b></p><p>'+GmapsTexts.home_info_text+'</p></div>');
        } );

        this.computeClosestPoints();
    }
    /**
     * D�placement de la home aux coordonn�es sp�cifi�es
     */
    this.move = function(lat, lng) {
        map.closeInfoWindow();
        this.lat = lat;
        this.lng = lng;
        this.marker.setPoint(new GLatLng( this.lat, this.lng));
        this.computeClosestPoints();
    }

    /**
     * Calcule les points les plus proches de la home et change leur couleur
     */
    this.computeClosestPoints = function () {
          if(stations.n > 0) {
              this.marker.openInfoWindowHtml(GmapsTexts.computing_message);
            stations.computeClosest(this.marker.getPoint());
            stations.drawAllMarkers();
            map.closeInfoWindow();
        }
    }
}

/**
 * Classe de gestion du bloc de gauche (d�tails d'une station + formulaire de recherche)
 */
function LeftBlock (id) {
    this.id=id;
    this.elem = document.getElementById(id);

    this.showLoadMessage = function() {
        this.elem.innerHTML = '<p>'+GmapsTexts.loading_message+'</p>';
    }

    this.updateDetails = function (theStation) {

        if(theStation.state == 1) {
            this.showLoadMessage();
            var instance = this;
            var request = GXmlHttp.create();
            request.open("GET", stationDetailsUrl + "/"+ theStation.number, true);
            request.onreadystatechange = function() {

                   if (request.readyState == 4) {
                    var xmlDoc = request.responseXML;
                    theStation.availableBikes = xmlDoc.getElementsByTagName('available')[0].firstChild.nodeValue;
                    theStation.freeCapacity = xmlDoc.getElementsByTagName('free')[0].firstChild.nodeValue;
                    theStation.totalCapacity = xmlDoc.getElementsByTagName('total')[0].firstChild.nodeValue;
                    theStation.ticket = xmlDoc.getElementsByTagName('ticket')[0].firstChild.nodeValue;

                    theStation.state = 2;

                    instance.updateDetails(theStation);
                }
            }
            request.send(null);

        } else {
            var html = "";
//-            if(theStation.name != "") {
//-                html += "<p class=\"pad_bot\">"+GmapsTexts.lc_name+" <span>"+theStation.name+"</span></p>";
//-                html += "<p class=\"pad_bot\">"+GmapsTexts.lc_borne+" <span>"+theStation.number+"</span></p>";
//-            } else {
                html += "<p class=\"pad_bot\">"+GmapsTexts.lc_borne+" <span>"+theStation.number+"</span></p>";
//-            }

            if(theStation.fullAddress != "") {
                html += "<p class=\"pad_bot\">"+GmapsTexts.lc_full_address+"<br  /><span>"+theStation.fullAddress+"</span></p>";
            }

            html += "<div class=\"details\">";
            html += "<p>"+GmapsTexts.lc_available_bikes+" <span>"+theStation.availableBikes+"</span></p>";
            html += "<p>"+GmapsTexts.lc_free_capacity+" <span>"+theStation.freeCapacity+"</span></p>";
            if(theStation.totalCapacity > 0) {
                html += "<p>"+GmapsTexts.lc_total_capacity+" <span>"+theStation.totalCapacity+"</span></p>";
            }
            html += "</div>";
            html += "<p>"+GmapsTexts.lc_details_cb+" <span>";
            if(theStation.ticket == 1) { html += GmapsTexts.lc_yes; }else{ html += GmapsTexts.lc_no; }
            html += "</span></p>";
            //html += "<p><a href=\"#\" onclick=\"xajax_saveStationToSession("+theStation.number+");return false;\">"+GmapsTexts.link_addStation+"</a></p>"
            this.elem.innerHTML = html;
            if(!cacheEnabled) {
                theStation.state = 1;
            }
        }
    }
}

var leftBlock = null;
var stations = new Stations();
var normalIcon = null;
var startIcon = null;
var closestIcon = null;
var home = new Home();
var mm = null;
var geo = new GClientGeocoder();
var arrdts = new Arrondissements();

//error handling
var reasons=[];
reasons[G_GEO_MISSING_ADDRESS]    = GmapsTexts.search_not_found;
reasons[G_GEO_UNKNOWN_ADDRESS]    = GmapsTexts.search_not_found;
reasons[G_GEO_UNAVAILABLE_ADDRESS]= GmapsTexts.search_not_found;
reasons[G_GEO_BAD_KEY]            = GmapsTexts.search_error;
reasons[G_GEO_TOO_MANY_QUERIES]   = GmapsTexts.search_error;
reasons[G_GEO_SERVER_ERROR]       = GmapsTexts.search_error;

function gMapsInit() {

    stations.n = nbOfClosest;
    leftBlock = new LeftBlock('stationDetails');

    /*if(keyWords)
    {
        alert(keyWords);
    }*/

    // Read the stations list
    var request = GXmlHttp.create();
    request.open("GET", stationsListUrl, true);

    request.onreadystatechange = function() {

           if (request.readyState == 4) {
            var xmlDoc = request.responseXML;
            // obtain the array of stations and loop through it
            var markers = xmlDoc.documentElement.getElementsByTagName("marker");

            var flag = 0;

            //pour chaque point lu, cr�e la station
            for (var i = 0; i < markers.length; i++) {
                var lat = parseFloat(markers[i].getAttribute("lat"));
                var lng = parseFloat(markers[i].getAttribute("lng"));
                var name = markers[i].getAttribute("name");
                var number = markers[i].getAttribute("number");
                var address = markers[i].getAttribute("address");
                var fullAddress = markers[i].getAttribute("fullAddress");
                var opened = markers[i].getAttribute("open");
                var bonus = markers[i].getAttribute("bonus");
                
                //if we are adding the start station
                if(displayMode == 2 && lat == orig_lat && lng == orig_long && !flag)
                {
                    var station = new Station(name, number, address, fullAddress, lat, lng, opened, bonus);
                    stations.startStation = station;
                    flag = 1;
                }
                else {
                    //add the other stations
                    var station = new Station(name, number, address, fullAddress, lat, lng, opened, bonus);
                }
                stations.add(station);
            }

            //initialise la map
            map = new GMap2(document.getElementById(mapid));
            map.addControl(new GLargeMapControl());
            map.addControl(new GMapTypeControl());
            if(minimapEnabled) {
                map.addControl(new GOverviewMapControl());
            }

            //r�cup�re les coordonn�es des arrondissements
            var arrdtsNodes = xmlDoc.documentElement.getElementsByTagName("arrondissement");
            for (var i = 0; i < arrdtsNodes.length; i++) {
                var minLat = parseFloat(arrdtsNodes[i].getAttribute("minLat"));
                var minLng = parseFloat(arrdtsNodes[i].getAttribute("minLng"));
                var maxLat = parseFloat(arrdtsNodes[i].getAttribute("maxLat"));
                var maxLng = parseFloat(arrdtsNodes[i].getAttribute("maxLng"));
                var number = arrdtsNodes[i].getAttribute("number");

                var zone = new GLatLngBounds(new GLatLng(minLat, minLng), new GLatLng(maxLat, maxLng));
                var arrdtCenter = zone.getCenter();
                var arrdtZoomLevel = map.getBoundsZoomLevel(zone);

                var myArr = new Arrondissement(number, arrdtCenter, arrdtZoomLevel, zone);
                arrdts.add(myArr);
            }

            //param map
            var mt = map.getMapTypes();
            for (var i=0; i<mt.length; i++) { mt[i].getMinimumResolution = function() {return 10} }
            map.setCenter(startPoint, 15);

            var ctr = map.getCenter();
            tipAFriend(ctr.lat(), ctr.lng() , 0, 0);

            //gestion d'�v�nements pour le lien "envoyer � un ami"
            GEvent.addListener(map, "moveend", function() {
                var ctr = map.getCenter();
                tipAFriend(ctr.lat(), ctr.lng() , 0, 0);
            });

            if(stations.n > 0) {

                //si on est en mode != 2 (c a dire pas dans un affichage de station), on cr�e la home
                if(displayMode != 2) {
                    home.create(orig_lat, orig_long);
                }

                //ajoute la gestion d'�v�nements pour cr�er/d�placer la home au clic sur la carte
                GEvent.addListener(map, "click", function(marker, point) {
                    if(point) {
                        if(! home.isEnabled) {
                            home.create(point.lat(), point.lng());
                        }
                    }
                });
                GEvent.addListener(map, "dblclick", function(marker, point) {
                    if(point) {
                        if(home.isEnabled) {
                            home.move(point.lat(), point.lng());
                        } else {
                            home.create(point.lat(), point.lng());
                        }
                    }
                });
            }

            stations.init = true;
            stations.computeClosest(map.getCenter());
            stations.init = false;
            stations.drawAllMarkers();

            //lance la recherche si on l'a fait depuis un param�tre GET
            if(keyWords != "")
            {
                launchSearch(keyWords);
            }
        }
    }
    request.send(null);

    //build the icons
    normalIcon = new GIcon();
    normalIcon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
    normalIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    normalIcon.iconSize = new GSize(12, 20);
    normalIcon.shadowSize = new GSize(22, 20);
    normalIcon.iconAnchor = new GPoint(6, 20);
    normalIcon.infoWindowAnchor = new GPoint(5, 1);

    closestIcon = new GIcon();
    closestIcon.image = "http://labs.google.com/ridefinder/images/mm_20_blue.png";
    closestIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    closestIcon.iconSize = new GSize(12, 20);
    closestIcon.shadowSize = new GSize(22, 20);
    closestIcon.iconAnchor = new GPoint(6, 20);
    closestIcon.infoWindowAnchor = new GPoint(5, 1);

    startIcon = new GIcon();
    startIcon.image = "http://labs.google.com/ridefinder/images/mm_20_green.png";
    startIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    startIcon.iconSize = new GSize(12, 20);
    startIcon.shadowSize = new GSize(22, 20);
    startIcon.iconAnchor = new GPoint(6, 20);
    startIcon.infoWindowAnchor = new GPoint(5, 1);

    homeIcon = new GIcon();
    homeIcon.image = "http://labs.google.com/ridefinder/images/mm_20_yellow.png";
    homeIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    homeIcon.iconSize = new GSize(12, 20);
    homeIcon.shadowSize = new GSize(22, 20);
    homeIcon.iconAnchor = new GPoint(6, 20);
    homeIcon.infoWindowAnchor = new GPoint(5, 1);

    closedIcon = new GIcon();
    closedIcon.image = "http://labs.google.com/ridefinder/images/mm_20_white.png";
    closedIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    closedIcon.iconSize = new GSize(12, 20);
    closedIcon.shadowSize = new GSize(22, 20);
    closedIcon.iconAnchor = new GPoint(6, 20);
    closedIcon.infoWindowAnchor = new GPoint(5, 1);
    
    bonusIcon = new GIcon();
    bonusIcon.image = imagesUrl + "contenu/picto-bonus.png";
    bonusIcon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
    bonusIcon.iconSize = new GSize(14, 20);
    bonusIcon.shadowSize = new GSize(22, 20);
    bonusIcon.iconAnchor = new GPoint(6, 20);
    bonusIcon.infoWindowAnchor = new GPoint(5, 1);
}
