/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.addressbook.vcard;

import java.awt.Component;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

import javax.swing.ProgressMonitorInputStream;

import lu.tudor.santec.gecamed.address.ejb.entity.beans.AddressType;
import lu.tudor.santec.gecamed.addressbook.ejb.entity.beans.Contact;
import lu.tudor.santec.gecamed.addressbook.ejb.entity.beans.ContactAddress;
import lu.tudor.santec.i18n.Translatrix;

/**
 * Utility class to import and export Contact from/to VCARD format
 * 
 *
 * @author Johannes Hermen johannes.hermen(at)tudor.lu
 *
 * @version
 * <br>$Log: VCardManager.java,v $
 * <br>Revision 1.13  2010-04-26 12:44:35  hermen
 * <br>small improvements
 * <br>
 * <br>Revision 1.12  2010-04-23 05:59:09  hermen
 * <br>*** empty log message ***
 * <br>
 * <br>Revision 1.11  2010-04-22 07:33:33  hermen
 * <br>fixed vcard export
 * <br>
 * <br>Revision 1.10  2010-04-22 07:25:15  hermen
 * <br>fixed vcard import
 * <br>
 * <br>Revision 1.9  2010-02-24 10:31:48  hermen
 * <br>Incomplete - # 423: Adress book - Import: Adress information not imported from vcf file
 * <br>http://santec.tudor.lu/trac/gecamed/ticket/423
 * <br>
 * <br>Revision 1.8  2010-02-12 11:04:54  hermen
 * <br>now parses multi-line properties too
 * <br>
 * <br>Revision 1.7  2010-02-12 10:25:54  hermen
 * <br>fixed import of lotus generated vcards (whitespace on beginning of lines)
 * <br>
 * <br>Revision 1.6  2008-09-25 09:42:27  heinemann
 * <br>fixed copyrights
 * <br>
 * <br>Revision 1.5  2008-05-07 13:25:23  hermen
 * <br>updated import
 * <br>
 * <br>Revision 1.4  2008-05-06 14:29:13  hermen
 * <br>updated javadoc
 * <br>
 *
 */
public class VCardManager {


    private static final Object START = "BEGIN:VCARD";
    private static final Object END = "END:VCARD";

    private static DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    
    /**
     * reads VCARD entries from the given file and creates Contact objects from it
     * 
     * @param f
     * @return
     */
    public static Collection<Contact> readVCard(File f, Component parent) {

	ArrayList<Contact> contacts = new ArrayList<Contact>();
 	
	
	try {
	    BufferedReader br = new BufferedReader(
		    new InputStreamReader(new ProgressMonitorInputStream(
			    parent,
			    Translatrix.getTranslationString("Addressbook.importContact"),
                            new FileInputStream(f))));
	    
	    
	    
	    Contact contact = null;
	    
	    
	    String line;
	    String property = null;
	    
	    do {
		line = br.readLine(); 
		try {
		    if (line != null)
			line = line.trim();
		    
		    
		    if (line != null && ! (line.indexOf(":") >= 0))  { // contains no :
			property += line;
			continue;
		    } else {
			if (property == null) 
			    property = line;
			
			// parse old stuff;
			 String key = property.substring(0, property.indexOf(":"));
			    String value = property.substring(property.indexOf(":")+1);
			    key = key.toUpperCase();
				if (property.equals(START)) {
				    contact = new Contact();
				} else if (property.equals(END)) {
				    contacts.add(contact);
				} else if (key.equals("N")){
				    parseName(key, value, contact);
				} else if (key.startsWith("TEL")){
				    parsePhone(key, value , contact);
				} else if (key.startsWith("EMAIL")){
				    parseMail(key, value , contact);
				} else if (key.startsWith("ADR")){
				    parseAddress(key, value , contact);
				} else if (key.startsWith("BDAY")){
				    parseDOB(key, value , contact);
				} else if (key.startsWith("ORG")){
				    parseComment(key, value , contact);
				} else if (key.startsWith("TITLE")){
				    parseTitle(key, value , contact);
				} else if (key.startsWith("NOTE")){
				    parseComment(null, value , contact);
				} else if (key.startsWith("URL")){
				    parseComment(key, value , contact);
				}
			
			
		    }
		    
		   
		} catch (Exception e) {
		    e.printStackTrace();
		    System.out.println(line);
		}
		property = line;
	    } while (line != null);
	
	    br.close();
	    
	} catch (Exception e) {
	    e.printStackTrace();
	}

	return contacts;
    }
    
    /**
     * shortens the given String to the specified length
     * @param s
     * @param length
     * @return
     */
    private static String shorten(String s, int length) {
	if (s != null) {
	    s = s.trim();
        }
	if (s.length() > length)
		return s.substring(0,length);
	return s;
    }
    
    /**
     * parses the given String to the contacts comment
     * @param key
     * @param value
     * @param contact
     */
    private static void parseComment(
    String key, String value, Contact contact) {
	StringBuffer sb = new StringBuffer();
	if (contact.getComment() != null) { 
	    sb.append(contact.getComment());
	    sb.append("\n");
	}
	if (key != null)
	    sb.append(key).append(": ");
	sb.append(value);
	contact.setComment(sb.toString());
    }
    
    /**
     * parses the given String to the contacts title
     * @param key
     * @param value
     * @param contact
     */
    private static void parseTitle(
    String key, String value, Contact contact) {
	contact.setTitle(value);
    }

    /**
     * parses the given String to the contacts birthday
     * @param key
     * @param value
     * @param contact
     */
    private static void parseDOB(
    String key, String value, Contact contact) {
	if (value.indexOf("T") >= 0 ) {
	    value = value.split("T")[0];
	}
	try {
	    contact.setBirthDate(df.parse(value));
	} catch (ParseException e) {
	    e.printStackTrace();
	}
    }

    /**
     * parses the given String to the contacts address
     * @param key
     * @param value
     * @param contact
     */
    private static void parseAddress(String key, String value, Contact contact) {
	String[] values = splitAttributes(value);
	if (values.length >= 7) {
	    ContactAddress ca = new ContactAddress();
	    if (key.indexOf("WORK") >= 0) {
		ca.setType(AddressType.WORK);
	    } else {
		ca.setType(AddressType.PRIVATE);
	    }
	    ca.setStreetName(shorten(values[2], 50));
	    ca.setLocality(shorten(values[3], 50));
            ca.setZip(shorten(values[5], 10));
	    ca.setCountry(shorten(values[6], 50));
	    if (contact.getAddress() == null) 
		contact.setAddress(new HashSet<ContactAddress>());
	    contact.getAddress().add(ca);
	}
    }

    /**
     * parses the given String to the contacts email
     * @param key
     * @param value
     * @param contact
     */
    private static void parseMail(
    String key, String value, Contact contact) {
	contact.setEmail(shorten(value, 40));
    }

    /**
     * parses the given String to the contacts name
     * @param key
     * @param value
     * @param contact
     */
    private static void parseName(
    String key, String value, Contact contact) {
	String[] values = splitAttributes(value);
	if (values.length > 0)
	    contact.setName(shorten(values[0], 40));
	if (values.length > 1)
	    contact.setNameFirst(shorten(values[1], 40));
    }
    
    /**
     * parses the given String to the contacts phone
     * @param key
     * @param value
     * @param contact
     */
    private static void parsePhone(String key, String value, Contact contact) {
	String[] values = splitAttributes(value);
	String phone = shorten(values[0], 40);
	
	if (key.indexOf("VOICE") >= 0 || key.indexOf("HOME") >= 0)
	    contact.setPhonePrivate(phone);
	else if (key.indexOf("CELL") >= 0)
	    contact.setPhoneMobile(phone);
	else if (key.indexOf("FAX") >= 0)
	    contact.setFax(phone);
	else if (key.indexOf("WORK") >= 0)
	    contact.setPhoneWork(phone);
    }
    
    /**
     * splits the given line by ";"
     * @param line
     * @return
     */
    private static String[] splitAttributes(String line) {
	return line.split(";");
    }
    
    /**
     * creates a VCARD from the given contact
     * @param contact
     * @return
     */
    public static String createVCard(Contact contact) {
	    StringBuffer vCard = new StringBuffer("BEGIN:VCARD\n");
	    vCard.append("VERSION:2.1\n");
	    vCard.append("FN:" + (contact.getNameFirst()!=null?  contact.getNameFirst() + " " :  "") +  contact.getName() + "\n");
	    vCard.append("N:" + contact.getName() +  (contact.getNameFirst()!=null?  ";" + contact.getNameFirst() :  "") + "\n");
	    if (contact.getTitle() != null && ! contact.getTitle().equals("")) 
		vCard.append("TITLE:" + contact.getTitle()+ "\n");
	    if (contact.getPhoneWork() != null && ! contact.getPhoneWork().equals("")) 
		vCard.append("TEL;WORK:" + contact.getPhoneWork()+ "\n");
	    if (contact.getPhonePrivate() != null && ! contact.getPhonePrivate().equals("")) 
		vCard.append("TEL;HOME:" + contact.getPhonePrivate()+ "\n");
	    if (contact.getPhoneMobile() != null && ! contact.getPhoneMobile().equals("")) 
		vCard.append("TEL;CELL:" + contact.getPhoneMobile()+ "\n");
	    if (contact.getFax() != null && ! contact.getFax().equals("")) 
		vCard.append("TEL;FAX:" + contact.getFax()+ "\n");
	    if (contact.getEmail() != null && ! contact.getEmail().equals("")) 
		vCard.append("EMAIL:" + contact.getEmail()+ "\n");
	    if (contact.getBirthDate() != null) 
		vCard.append("BDAY:" + df.format(contact.getBirthDate())+ "\n");
	    if (contact.getComment() != null) 
		vCard.append("NOTE:" + contact.getComment() + "\n");
	    
	    if (contact.getAddress() != null) {
		for (Iterator<ContactAddress> iter = contact.getAddress().iterator(); iter.hasNext();) {
		    ContactAddress adr = (ContactAddress) iter.next();
		    vCard.append("ADR:" + adr.toVCardString() + "\n");
		}
	    }
	    vCard.append("END:VCARD\n");
	    return vCard.toString();
    }
    
}
