//     ____________
//    |            |    A Javascript parser for vCards
//    |  vCard.js  |    Created by Mattt Thompson, 2008
//    |            |    Released under the MIT License
//     ̅̅̅̅̅̅̅̅̅̅̅̅

// JavaScript 1.6 Iterators and generics cross-browser
if (!Array.prototype.forEach) {
  Array.prototype.forEach = function(func, scope) {
    scope = scope || this;
    for (var i = 0, l = this.length; i < l; i++)
      func.call(scope, this[i], i, this); 
  }
}

if (typeof Prototype != 'undefined' || !Array.prototype.map) {
  Array.prototype.map = function(func, scope) {
    scope = scope || this;
    var list = [];
    for (var i = 0, l = this.length; i < l; i++)
        list.push(func.call(scope, this[i], i, this)); 
    return list;
  }
}

if (typeof Prototype != 'undefined' || !Array.prototype.filter) {
  Array.prototype.filter = function(func, scope) {
    scope = scope || this;
    var list = [];
    for (var i = 0, l = this.length; i < l; i++)
        if (func.call(scope, this[i], i, this)) list.push(this[i]); 
    return list;
  }
}

['forEach', 'map', 'filter', 'slice', 'concat'].forEach(function(func) {
    if (!Array[func]) Array[func] = function(object) {
      return this.prototype[func].apply(object, Array.prototype.slice.call(arguments, 1));
    }
});

//////////////////////////////////////////////////////////////////////////


vCard = {
  initialize: function(_input){
    var vc = {};
    this.parse(_input, vc);
    
    vc.prototype = vCard.Base;
    return vCard.extend(vc, vCard.SingletonMethods);
  },
  parse: function(_input, fields) {
    var regexps = {
      simple: /^(version|fn|title|org)\:(.+)\;?$/i,
      complex: /^([^\:\;]+);([^\:]+)\:(.+)$/,
      key: /item\d{1,2}\./,
      properties: /((type=)?(.+);?)+/
    }
 
    var lines = _input.split('\r\n');
    for (n in lines) {
      line = lines[n];
      
      if(regexps['simple'].test(line))
      {
        results = line.match(regexps['simple']);
        key = results[1].toLowerCase();
        value = results[2];
        
        fields[key] = value;
      }
      else if(regexps['complex'].test(line))
      {
        results = line.match(regexps['complex']);
        key = results[1].replace(regexps['key'], '').toLowerCase();
        
        properties = results[2].split(';');
        properties = Array.filter(properties, function(p) { return ! p.match(/[a-z]+=[a-z]+/) });
        properties = Array.map(properties, function(p) { return p.replace(/type=/g, '') });
        
        type = properties.pop() || 'default';
        type = type.toLowerCase();
        
        value = results[3];
        value = /;/.test(value) ? [value.split(';')] : value;

        fields[key] = fields[key] || {};
        fields[key][type] = fields[key][type] || [];
        fields[key][type] = fields[key][type].concat(value);
      }
      else if(/BASE64/.test(lines[n - 1])){
        fields['photo'] = {};
        fields['photo']['base64'] = line.replace(/\n/g,'');
      }
    }
  },
  SingletonMethods: {
    to_html: function() {
      var fields = this;
      var output = $DOM('div', null, {'class': 'vcard'});
      
      if(fields.photo)
      {
        output.append($DOM('img', null, {'class': 'photo', 'src': 'data:image/png;base64,' + fields.photo['base64'] }));
      }
      
      ['fn', 'title', 'org'].forEach(function(field){
        if(fields[field])
        {
          output.append($DOM('span', fields[field], {'class': field}));
        }
      });
    
      output.append($DOM('hr'));
      
      for(type in fields.adr)
      {
        for(n in fields.adr[type])
        {
          var value = fields.adr[type][n];
          address = $DOM('address', null, {'class': 'adr'});
          address.append($DOM('span', type, {'class': 'type'}));
          
          div = $DOM('div', null, {'class': 'content'});
          
          ['post-office-box', 'extended-address', 'street-address', 
           'locality', 'region', 'postal-code', 'country-name'       ].forEach(function(field, i){
             if(value[i])
             {
               div.append($DOM('span', value[i].replace(/\\n/, $DOM('br')), {'class': field}));
             }
           });
        
          output.append(address.append(div));
        }
      }
      
      output.append($DOM('hr'));
      
      for(type in fields.tel)
      {
        for(n in fields.tel[type])
        {
          value = this.tel[type][n];
          
          tel = $DOM('span', null, {'class': 'tel'});
          tel.append($DOM('span', type, {'class': 'type'}));
          tel.append($DOM('span', value, {'class': 'value'}));
          output.append(tel);
        }
      }
      
      output.append($DOM('hr'));
      
      for(type in this.email)
      {
        for(n in this.email[type])
        {
          value = this.email[type][n];
         
          email = $DOM('span', null, {'class': 'email'});
          email.append($DOM('span', type, {'class': 'type'}));
          email.append($DOM('a', value, {'class': 'value', 'href': 'mailto:' + value}));
          output.append(email);
        }
      }
      
      output.append($DOM('hr'));
      
      for(type in this.url)
      {
        for(n in this.url[type])
        {
          value = this.url[type][n].replace(/\\/, '');
          
          url = $DOM('span', null, {'class': 'url'});
          url.append($DOM('span', type, {'class': 'type'}));
          url.append($DOM('a', value, {'class': 'value', 'href': value}));
          output.append(url);
        }
      }

      return output.toString();
    }
  },
  extend : function(dest, source) {
    for (var prop in source) dest[prop] = source[prop];
    return dest;
  },
  
  Base: {}
}