//============================================
 function FeatureFactory(){
     
          var ff= this;
          
          var concat = this._concatenate;
          var add = this._additive;
          var identical = this._identical;
          
          this.FEATURE_TYPES = {
              
                 "roads":{
                     vector_parser: ff._parsePolyline,
                     style:{strokeWidth:5,strokeColor: "#de0ced",strokeOpacity:0.8},
                     detail_names:{    "id":concat,
                                              "street_id":concat,
                                              "city_name":identical,
                                              "road_type":identical,
                                              "direction":identical,
                                              "street_name":identical,
                                              "english_name":identical,
                                              "txt2speech":identical,
                                              "street_type":identical,
                                              "separator":identical,
                                              "locked":identical,
                                              "road_length":add,
                                              "from_cross_time":add,
                                              "to_cross_time":add,
                                              "road_speed":function(){return ""},//we calculate speed at the end
                                              "update_user":identical,
                                              "user_name":identical,
                                              "user_rank":identical
                                              },
                        noun_id:"road_noun",
                        onMergeEnd : function(merged_details){ merged_details["road_speed"] = parseInt(merged_details["road_length"]) / parseInt(merged_details["from_cross_time"]);}
                 },
		 
                 "nodes":{
                     vector_parser: ff._parsePoint,
                     style:{strokeWidth:4,strokeColor: "blue",strokeOpacity:0.8,pointRadius: 10,fillColor:"transparent",fillOpacity:0.3},
                     detail_names:{
			 "id":concat,
                         "user_name":identical,
                         "user_rank":identical
                     },
                      noun_id:"node_noun",
                      onMergeEnd : function(merged_details){}
                 },
                 
                 "users_notes":{
                     vector_parser: ff._parsePoint,
                     style:{strokeWidth:4,strokeColor: "yellow",strokeOpacity:0.8,pointRadius: 10,fillColor:"transparent",fillOpacity:0.3},
                     detail_names:{
                          "id":concat,
                         "description":identical,
                         "user_name":identical,
                         "user_rank":identical
                     },
                       noun_id:"node_noun",
			onMergeEnd : function(merged_details){}
                 },
                 
                 "speed_cams":{
                     vector_parser: ff._parsePoint,
                     style:{strokeWidth:4,strokeColor: "yellow",strokeOpacity:0.8,pointRadius: 10,fillColor:"transparent",fillOpacity:0.3},
                     detail_names:{
                          "id":concat,
                         "cam_speed":identical,
                          "cam_type":identical,
                         "user_name":identical,
                         "user_rank":identical
                     },
                     noun_id:"speed_cam_noun",
                     onMergeEnd : function(merged_details){}
                 },
                 
                   "street_ranges":{
                     vector_parser: ff._parsePoint,
                     style:{strokeWidth:4,strokeColor: "yellow",strokeOpacity:0.8,pointRadius: 10,fillColor:"transparent",fillOpacity:0.3},
                     detail_names:{
                               "id":concat,
                               "street_name":identical,
                               "city_name":identical,
                               "left_addr":identical,
                               "right_addr":identical,
                               "magvar":identical,
                               "user_name":identical,
                               "user_rank":identical
                     },
                     noun_id:"house_number_noun",
                     onMergeEnd : function(merged_details){}
                 },
                 
                   "update_requests":{
                     vector_parser: ff._parsePoint,
                     style:{strokeWidth:4,strokeColor: "yellow",strokeOpacity:0.8,pointRadius: 10,fillColor:"transparent",fillOpacity:0.3},
                     detail_names:{
                               "id":concat,
                               "update_text":identical,
                               "updater_note":identical,
                               "age":identical,
                               "update_type":identical,
                               "update_state":identical,
                               "name":identical   
                     },
                    noun_id:"update_request_noun",
                     onMergeEnd : function(merged_details){}
                 }
                 
          }       
                 
	this.FEATURE_TYPES["line_roads"]= this.FEATURE_TYPES["roads"];
	this.FEATURE_TYPES["unknown_roads"]= this.FEATURE_TYPES["roads"];
}
//===========================================================================
FeatureFactory.prototype._identical = function(merged_details,next_details,detail_name){
        if(merged_details[detail_name]=="" || merged_details[detail_name]!=next_details[detail_name])//if values are different empty this detail
              return "";

        return merged_details[detail_name];
}
//===========================================================================
FeatureFactory.prototype._additive =  function(merged_details,next_details,detail_name){

         return parseInt(merged_details[detail_name]) + parseInt(next_details[detail_name]);
 }
//===========================================================================
FeatureFactory.prototype._concatenate = function(merged_details,next_details,detail_name){
         
         return merged_details[detail_name]+","+next_details[detail_name];
}
//===========================================================================
 FeatureFactory.prototype._parseDetails = function(element,type){
         
        var getKeysArray = function(map){
             var arr = [];
             for(var key in map)
                 arr.push(key);
        
             return arr;
        }
        
        var dnames = getKeysArray(this.FEATURE_TYPES[type].detail_names);
       
        var details = {};
	
        for(var i=0; i<dnames.length; i++)
			details[dnames[i]] = $(":ns(http://www.ttt.org/myns,"+dnames[i]+")",element).text();
	

         return details;
 }
//===========================================================================
    /**
    * @return a Vector with a point geometry
    */
   FeatureFactory.prototype._parsePoint = function(element){

		var point = null;
		
		var coordinatesStr =  $(":ns(http://www.opengis.net/gml,Point) :ns(http://www.opengis.net/gml,coordinates)",element).text();
		var coordinates =$.trim(coordinatesStr).split(",");
		point = new OpenLayers.Feature.Vector(geometry=new OpenLayers.Geometry.Point(x=coordinates[0],y=coordinates[1]));
                     

		return point;

   }
  //===========================================================================
   /**
    * @return a Vector with a polyline (LineString)  geometry
    */
  FeatureFactory.prototype._parsePolyline = function(element){
            var polyline_vector = null;
            //coordinates are returned in the format : 'x1,y1 x2,y2 x3,y3'
	    
	    var coordinatesStr = $(":ns(http://www.opengis.net/gml,LineString) :ns(http://www.opengis.net/gml,coordinates)",element).text();
	    var coordinates =$.trim(coordinatesStr).split(" ");
	    var pline = new OpenLayers.Geometry.LineString();
	    for(var i in coordinates){
		    var point = coordinates[i].split(",");
		    pline.addPoint(new OpenLayers.Geometry.Point(x=point[0],y=point[1]));
	    }
	     polyline_vector = new OpenLayers.Feature.Vector(geometry=pline);
         

            return polyline_vector;
}
//===========================================================================
 FeatureFactory.prototype._parseVector = function(element,type){
      
      //console.log(element);
      var vp = this.FEATURE_TYPES[type].vector_parser;
      var vector = vp(element);
      vector.style =  this.FEATURE_TYPES[type].style;
      return vector;
 }
//=========================================================================== 
FeatureFactory.prototype.make= function(element){
            
               var type = $(element).attr("fid").split(".")[0];
               var vector = this._parseVector(element,type);
               var details = this._parseDetails(element,type);
             
               return {"vector":vector,"details":details};
 }
 //===========================================================================   
 /**
  * All features in feature arary must be of  the type features_type
  * This method will not test this.
  */
 FeatureFactory.prototype.mergeDetails =  function(feature_map,features_type){
            
     var merged_details = {}; 
     var detail_names   =  this.FEATURE_TYPES[features_type].detail_names;
     
     for(var name in detail_names)
         merged_details[name] = null;
     
     for(var id in feature_map){
         var next_feature_details =  feature_map[id].details;
         for(var next_detail in merged_details)
              if(merged_details[next_detail]==null)//if no value found take this value
                  merged_details[next_detail] = next_feature_details[next_detail];
              else
                  merged_details[next_detail] = detail_names[next_detail](merged_details,next_feature_details,next_detail);
                
     }
     
     this.FEATURE_TYPES[features_type].onMergeEnd(merged_details);
   
     return merged_details;
 }
