//////////////////////////////

// need in context :

//   map (map element)
//   chains (array of Chain)

/////////////////  POI         ////////////////////////////////

function Poi(xmlDom) {
    if(xmlDom !=null) {
        this.type = parseInt(xmlDom.getAttribute("type"));
        this.zoom = parseInt(xmlDom.getAttribute("zlevel"));
        this.content = xmlDom.childNodes[0].nodeValue;
    }
}

Poi.prototype.writeContentInDiv = function(divEl) {
   if(this.type == 0 ) {
       alert("Warning : bubble");
       divEl.innerHTML=this.content;
   } else if(this.type == 1 ) {
       divEl.innerHTML=this.content;
   } else if (this.type == 2) {
       divEl.innerHTML="";
       var img = document.createElement("img");
       img.src=this.content;
       divEl.appendChild(img);
   } else { 
       divEl.innerHTML="";
       var iframe = document.createElement("iframe");
       iframe.width = "100%";
       iframe.height = "100%";
       divEl.appendChild(iframe); 
       iframe.src=this.content;
            
   }    
}
/////////////////  ITIELEMENT  ////////////////////////////////

//status : 0 in db, 1 modified, 2 deleted, 3 new  
function ItiElement(chainId,point){
    this.point = point;
    this.gLatLng = (point != null ) ? new GLatLng(point.lat,point.lng) : null;
    this.status = 0;
    this.lineToPrevious=null;
        this.mark = null;
        this.chainId = chainId;
}
//does nothing. Can be overridden
//Called to update the Marker. (next element already in chain);
ItiElement.prototype.updateMarker = function(){}
//Can be overridden. Called when the ItiElement is created, when the next element is not yet in the chain. 
ItiElement.prototype.firstCreateMarker = function(nextId){};


ItiElement.prototype.getNextPointOfChain = function() {
  var chain = chains[this.chainId];
  var id = this.getIdInChain();
  while(id < chain.elements.length - 1) {
     id++;
     if(chain.elements[id].status != 2) {
         return chain.elements[id];
     } 
  }
  return null;
}
ItiElement.prototype.getPrevPointOfChain = function() {
  var chain = chains[this.chainId];
  var id = this.getIdInChain();
  while(id > 0) {
     id--;
     if(chain.elements[id].status != 2) {
         return chain.elements[id];
     } 
  }
  return null;
}
ItiElement.prototype.drawLineToPrevious = function(){   

    var id = this.getIdInChain(); 
    if(this.lineToPrevious != null){ 
        map.removeOverlay(this.lineToPrevious);
    }

    var color = "#FF0000";
    var minus = 1;
    while(id - minus >= 0) {
       var ptB = chains[this.chainId].elements[id-minus];
       if(ptB.status != 2){
           if(this.point != null && ptB.point !=null && (this.point.id - ptB.point.id != minus )) {
              color = "#DD2222";
           }
           this.lineToPrevious = new GPolyline(
                   [ptB.gLatLng,this.gLatLng],color,5,.5);
           map.addOverlay(this.lineToPrevious);
           return;
       }
       minus++;
    }        
}


ItiElement.prototype.getIdInChain = function(){
        return chains[this.chainId].elements.indexOf(this);
}




/////////////////  CHAIN ////////////////////////////////

function Chain(){
        this.firstPointId = null;
        this.lastPointId = null;
        this.elements = new Array();    
}
Chain.prototype.isLast = function(i) {
        return i == this.elements.length - 1;
}

Chain.prototype.setExtremePointsId = function (){
        if(this.elements[0].point == null){
                this.firstPointId = -1;
        } else {
                this.firstPointId = this.elements[0].point.id;  
        }
        if(this.elements.length == 1){
                this.lastPointId = this.firstPointId;
        } else if(this.elements.length == 0){
                this.lastPointId = null;
        } else {
                var lastPt = this.elements.length - 1;
                if(this.elements[lastPt].point != null) {
               this.lastPointId = this.elements[lastPt].point.id;
            } else {
               this.lastPointId = 32000;
            }
        }
}


///////////////// FUNCTION BINDING ////////////////////////////////

//inspired from http://www.brockman.se/writing/method-references.html.utf8
Function.prototype.bind = function (object) {
    var method = this;
    var oldArguments = entries(arguments).slice(1);
    return function () {
        var newArguments = entries(arguments);
        return method.apply(object, oldArguments.concat(newArguments));
    };
}
function entries(collection) {
    var result = [];  
    for (var i = 0; i < collection.length; i++)
        result.push(collection[i]);
    return result;
}



///////////////// MISC ////////////////////////////////



function updatePointsChainId(chainId){
        for(var i = chainId; i < chains.length;i++){
                for(var j = 0 ; j < chains[i].elements.length;j++){
                        chains[i].elements[j].chainId = i;                        
                }
        }
}

function insertPointsIntoChain(points,currentlyInChain,pois){
  if(pois == null) pois = new Array();
  var pointsAdded = 0;
      var chain = chains[currentlyInChain];
      var nextChainFirstPointId = 32000;
      if(currentlyInChain < chains.length -1){
          nextChainFirstPointId = chains[currentlyInChain+1].firstPointId;
      }

      var ccid = 0;   //chain current index

      for (var i = 0; i < points.length ; i++) {
          var point = new Point(points[i]);

          //follow the chain 'till the current input point. 
          while(ccid <= chain.elements.length - 1 &&
              ( chain.elements[ccid].point == null 
                  || chain.elements[ccid].point.id < point.id )) {
                  ccid++; 
          }
                          
                  var el = null;
                          
          if(ccid <= chain.elements.length - 1
             && point.id == chain.elements[ccid].point.id){
              //skip the point if already in chain. 
              chain.elements[ccid].age = 0;
              if(ccid == chain.elements.length -1){
                  el = chain.elements[ccid];
              } else {
                  continue;
              }
          }
        
          //check if we are entering a another chain ?
          if(point.id == nextChainFirstPointId){
                appendTxt("Mergin chains ! removing : " + (currentlyInChain+1) + " cl : " 
                              + chains[currentlyInChain].elements.length + " nl " 
                              + chains[currentlyInChain+1].elements.length );
                el = chains[currentlyInChain+1].elements[0];
                chain.elements = chain.elements.concat(chains[currentlyInChain+1].elements);
                chain.lastPointId = chains[currentlyInChain+1].lastPointId;
                chains.splice(currentlyInChain+1,1);                    
                updatePointsChainId(currentlyInChain);
                appendTxt("Mergin chains ! new l : " + chains[currentlyInChain].elements.length );  
                if(currentlyInChain < chains.length -1){
                    nextChainFirstPointId = chains[currentlyInChain+1].firstPointId;
                }
          }
                      
          if(el == null) {        
              el = new ItiElement(currentlyInChain,point);
              chain.elements.splice(ccid,0,el);
              pointsAdded++;
              ccid++;
              if(ccid < chain.elements.length){
                  chain.elements[ccid].drawLineToPrevious();                  
              }
              if(ccid > 2){
                  chain.elements[ccid-2].updateMarker();
              }
          }
          
          //if the point needs a marker, we add id
          if(el.mark ==null) {
	      var nextId = null;
            if(pois[el.point.id]!= null){
                      el.poi = pois[el.point.id];
            }
            if(i < points.length - 1){
               nextId = parseInt(points[i+1].getAttribute("id"));
            }
            el.firstCreateMarker(nextId);
          }
          el.age = 0;
          el.drawLineToPrevious();
      }
      chain.setExtremePointsId();
      return pointsAdded;
}


