// JavaScript Document

/**
 * Test if a node is member of a css class
 */ 
function hasClassName(node, className){
  var pattern = new RegExp("(^|\\s)"+className+"(\\s|$)");
  if (pattern.test(node.className)) return true;
  return false;
}

/**
 * Get all nodes which are memebers of a className
 */ 
function getElementsByClassName(className, node, tag) {
  var returnElements = new Array();
  if ( node == null ) node = document;
  if ( tag == null ) tag = '*';
  var elements = node.getElementsByTagName(tag);
  //var pattern = new RegExp("(^|\\s)"+className+"(\\s|$)");
  var l = elements.length;
  var cpt=0;
  for (i = 0; i < l; i++) {
    if (hasClassName(elements[i], className)) {
      returnElements[cpt] = elements[i];
      cpt++;
    }
  }
  return returnElements;
}

/**
 * Test if one element is memeber of an array
 */ 
function in_array(el, tab){
  for(var i=0; i<tab.length; i++){
    if(tab[i] == el) return true;
  }
  return false;
}

function getElementByClassName2(needle) {
  var xpathResult = document.evaluate('//*[@class = "needle"]', document, null, 0, null);
  var outArray = new Array();
  var item; while (item = xpathResult.iterateNext()) outArray[outArray.length] = item;
  return outArray;
}


hCard = {
  hcard : new Array(), 
  
  classes : ['fn',
		['n' , ['honorific-prefix', 'given-name', 'additional-name', 'family-name', 'honorific-suffix']],
		['adr' , ['post-office-box', 'extended-address', 'street-address', 'postal-code', 'country-name' , 'type', 'region', 'locality']],
		'label', 'bday', 'agent', 'nickname', 'photo', 'class', 
		['email' , ['type', 'value']], 
    'category', 'key', 'logo', 'mailer', 'note', 
    ['org' , ['organization-name', 'organization-unit']],
		['tel' , ['type', 'value']],
    ['geo' , ['latitude', 'longitude']],
		'tz', 'uid', 'url', 'rev', 'role', 'sort-string', 'sound', 'title'],

  singles : ['fn', 'n', 'bday', 'tz', 'geo', 'sort-string', 'uid', 'class'],
  
  //Given an attribute, give if the value expected is a URL or a simple string
  valueExpected : function(att){
    tab = ['logo', 'url', 'photo'];
    if(in_array(att, tab)) return "URL";
    return "STRING";
  },
  
  //apply rules, defines in hCard specs to extract the value from a node
  getValueFromNode : function(node, att){
    if(node.tagName.toLowerCase() == "a"){
      var abbrs = node.getElementsByTagName("abbr");
      if(abbrs.length>0){
        if(abbrs[0].title) return abbrs[0].title;
      }
      if(this.valueExpected(att) == "URL") return node.href;
      return node.innerHTML;
    }
    if(node.tagName.toLowerCase() == "img"){
      if(this.valueExpected(att) == "URL") return node.src;
      return node.innerHTML;
    }
    if(node.tagName.toLowerCase() == "object"){
      if(this.valueExpected(att) == "URL") return node.data;
      return node.innerHTML;
    }
    return node.innerHTML;
  },
  
  detect : function(node){
    if(!node) node = document;
    var vCardElements = getElementsByClassName("vcard", node);
    for(var att in vCardElements){
      this.extract(vCardElements[att], this.classes);
    }
  },
  
  extract : function(node, attributes ){
    var l = attributes.length;
    for(var i= 0; i<l; i++){
      //main properties
      if(typeof attributes[i] == "string"){
        var elements = getElementsByClassName(attributes[i], node);
        if(elements.length>0){
           if(in_array(attributes[i], this.singles)){ // single, first is picked
            this.hcard[attributes[i]] = this.getValueFromNode(elements[0], attributes[i]); 
            //alert("singlestring"+attributes[i]);
          }
          else{
            if(this.hcard[attributes[i]] == undefined) this.hcard[attributes[i]] = new Array();  
            for(var j=0; j<elements.length; j++){  
              this.hcard[attributes[i]].push(this.getValueFromNode(elements[j], attributes[i]));
              //alert("multistring"+attributes[i]);
            }
          }
        }
      }
      else{ //properties may contains subproperties
        //searching each elements which have the main properties
        var nodes = getElementsByClassName(attributes[i][0], node);
        if(this.hcard[attributes[i][0]] == undefined) this.hcard[attributes[i][0]] = new Array(); 
        for(var j=0; j<nodes.length; j++){  
          var toParse = false;
          var subAttributesLength = attributes[i][1].length;
          //test if at least one subpropertie is found
          for(var k=0; k<subAttributesLength; k++){
            if(getElementsByClassName(attributes[i][1][k], nodes[j]).length>0) toParse = true;
          }
          //No subproperties found, extract data
          if(toParse == false){
            this.hcard[attributes[i][0]].push(this.getValueFromNode(nodes[j], attributes[i][0]));
            //alert("sub0 : "+attributes[i][0]+" val : "+this.getValueFromNode(nodes[j], attributes[i][0]));
          }
          //subproperties found 
          else{       
            var struct =   new Array();
            for(var k=0; k<subAttributesLength; k++){
              var subNodes = getElementsByClassName(attributes[i][1][k], nodes[j]);
              var subNodesLength = subNodes.length;
              for(var n=0; n<subNodesLength; n++){
                struct[attributes[i][1][k]] = this.getValueFromNode(subNodes[n], attributes[i][1][k]);
                //alert("sub : "+attributes[i][1][k]+"val : "+this.getValueFromNode(subNodes[n], attributes[i][1][k]));
                //alert(struct[attributes[i][1][k]]);
              }
              
            }
            this.hcard[attributes[i][0]].push(struct);
          }
        }
      } 
    }
  },
  
  serialize : function(obj, step){
    var t = "";
    if(typeof obj == "string"){
      t+= obj;
    }
    
    if(typeof obj == "object"){
      for(var att in obj){
        if(typeof obj[att] == "string"){
          t+= att+" : "+obj[att]+"\n";
        }
        if(typeof obj[att] == "object"){
          t+=att+"\n\n";
          t+= this.serialize(obj[att], step+1);
        }
      }
    }
    return t;
  },
  
  save : function(){
   
    /*for(var att in this.hcard){
     alert(this.hcard[att]);
    }
  */       
  
  alert(this.serialize(this.hcard),0);   
  }
  
  this.download = function(){
    var n =  '%0D%0A';
    	    var keys = [], i, parts;
    		var vcard = 'data:text/vcard;utf-8,BEGIN:VCARD' + n;

    		if (hCard.n.family-name) vcard+ = hCard.family-name;
    		if (hCard.n.given-name) {
    			if (hCard.n) hCard.n += ';';
    			hCard.n += hCard.n.given-name;
    		}

    		if (hCard.adr) {
    			keys = ['post-office-box', 'extended-address', 'street-address', 'locality', 'region', 'postal-code', 'country-name'];
    			hCard.adr = '';
    			for (i = 0; i < keys.length; i++) {
    				if (hCard[keys[i]]) {
    					hCard.adr += hCard[keys[i]];
    				}
    				hCard.adr += ';';
    			}
    		}

    		if (!hCard.n) {				
    			if (!hCard.n && hCard.fn && (hCard.fn.split(' ').length == 2)) {
    				parts = hCard.fn.split(' ');
    				parts = parts.reverse();
    				hCard.n = parts.join(';');
    			}
    		}

    		keys = ['fn', 'n' , 'org', 'title', 'role', 'note', 'nickname', 'adr', 'email', 'photo', 'url', 'bday'];
    		for (i = 0; i < keys.length; i++) {
    			if (hCard[keys[i]]) vcard += keys[i].toUpperCase() + ':' + encodeURIComponent(hCard[keys[i]]) + nl;
    		}

    		for (i in hCard.tel) {
    			vcard += 'TEL;' + i.toUpperCase() + ':' + hCard.tel[i] + nl;
    		}

    		vcard += 'END:VCARD';
    		return vcard;
    	};

    	return this;
    };
  
  
  
  }
  
   
}

 
