/* KPilot
**
** Copyright (C) 2000,2001 by Dan Pilone
** Copyright (C) 2002-2003 by Reinhold Kainhofer
** Copyright (C) 2007 by Adriaan de Groot <groot@kde.org>
**
** The abbrowser conduit copies addresses from the Pilot's address book to
** the KDE addressbook maintained via the tdeabc library. This file
** deals with the actual copying of HH addresses to KABC addresses
** and back again.
*/

/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program in a file called COPYING; if not, write to
** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
** MA 02110-1301, USA.
*/

/*
** Bug reports and questions can be sent to kde-pim@kde.org.
*/

#include "options.h"

#include <tqregexp.h>

#include <tdeglobal.h>
#include <tdeabc/addressee.h>

#include "tdeabcRecord.h"

/**
 * Okay, this is so that we can map the Pilot phone types to Phone Number
 * types. Email addresses are NOT included in this map, and are handled
 * separately (not in PhoneNumber at all). The Pilot has 8 different kinds
 * of phone numbers (which may be *labeled* however you like). These
 * need to be mapped to the things that TDEABC::PhoneNumber handles.
 *
 * From TDEABC::PhoneNumber
 *		enum Types { Home = 1, Work = 2, Msg = 4, Pref = 8, Voice = 16, Fax = 32,
 *				Cell = 64, Video = 128, Bbs = 256, Modem = 512, Car = 1024,
 *				Isdn = 2048, Pcs = 4096, Pager = 8192 };
 *
 *
 * From PilotAddress:
 * enum EPhoneType {
 *		eWork=0, eHome, eFax, eOther, eEmail, eMain,
 *		ePager, eMobile
 *		};
 *
 * This array must have as many elements as PilotAddress::PhoneType
 * and its elements must be TDEABC::PhoneNumber::Types.
 */

static TDEABC::PhoneNumber::Types pilotToPhoneMap[8] = {
	TDEABC::PhoneNumber::Work,  // eWork
	TDEABC::PhoneNumber::Home,  // eHome,
	TDEABC::PhoneNumber::Fax,   // eFax,
	(TDEABC::PhoneNumber::Types)0, // eOther -> wasn't mapped properly,
	(TDEABC::PhoneNumber::Types)0, // eEmail -> shouldn't occur,
	TDEABC::PhoneNumber::Home,  // eMain
	TDEABC::PhoneNumber::Pager, // ePager,
	TDEABC::PhoneNumber::Cell   // eMobile
} ;

TDEABC::PhoneNumber::List TDEABCSync::getPhoneNumbers(const PilotAddress &a)
{
	FUNCTIONSETUP;

	TDEABC::PhoneNumber::List list;
	TQString test;

	PhoneSlot shownPhone = a.getShownPhone();

	DEBUGKPILOT << fname << ": preferred pilot index is: ["
		<< shownPhone << "], preferred phone number is: ["
		<< a.getField(shownPhone) << "]" << endl;

	for (PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i)
	{
		// skip email entries
		if ( a.getPhoneType(i) == PilotAddressInfo::eEmail )
		{
			continue;
		}

		test = a.getField(i);
		// only look at this if the field is populated
		if (test.isEmpty())
		{
			continue;
		}

		int phoneType = pilotToPhoneMap[a.getPhoneType(i)];

		// only populate a PhoneNumber if we have a corresponding type
		if (phoneType >=0)
		{
			// if this is the preferred phone number, set it as such
			if (shownPhone == i)
			{
				phoneType |= TDEABC::PhoneNumber::Pref;
				DEBUGKPILOT << fname << ": found preferred pilot index: ["
					<< i << "], text: [" << test << "]" << endl;
			}
			TDEABC::PhoneNumber ph(test, phoneType);
			list.append(ph);
		}
		else
		{
			DEBUGKPILOT << fname << ": whoopsie.  pilot phone number: ["
				<< test << "], index: [" << i << "], type: ["
				<< phoneType << "], has no corresponding PhoneNumber type." << endl;
		}
	}

	DEBUGKPILOT << fname << ": returning: ["
		<< list.count() << "] phone numbers." << endl;

	return list;
}

void TDEABCSync::setPhoneNumbers(const PilotAddressInfo &info,
	PilotAddress &a,
	const TDEABC::PhoneNumber::List &list)
{
	FUNCTIONSETUP;
	TQString test;

	// clear all phone numbers (not e-mails) first
	for ( PhoneSlot i = PhoneSlot::begin(); i.isValid() ; ++i )
	{
		PilotAddressInfo::EPhoneType ind = a.getPhoneType( i );
		if (ind != PilotAddressInfo::eEmail)
		{
			a.setField(i, TQString());
		}
	}

	// now iterate through the list and for each PhoneNumber in the list,
	// iterate through our phone types using our map and set the first one
	// we find as the type of address for the Pilot
	for(TDEABC::PhoneNumber::List::ConstIterator listIter = list.begin();
		   listIter != list.end(); ++listIter)
	{
		TDEABC::PhoneNumber phone = *listIter;

		PilotAddressInfo::EPhoneType phoneType = PilotAddressInfo::eHome;

		for ( int pilotPhoneType = PilotAddressInfo::eWork;
			pilotPhoneType <= PilotAddressInfo::eMobile;
			++pilotPhoneType)
		{
			int phoneKey = pilotToPhoneMap[pilotPhoneType];
			if ( phone.type() & phoneKey)
			{
				DEBUGKPILOT << fname << ": found pilot type: ["
					<< pilotPhoneType << "] ("
					<< info.phoneLabel( (PilotAddressInfo::EPhoneType)pilotPhoneType)
					<< ") for PhoneNumber: ["
					<< phone.number() << "]" << endl;

				phoneType = (PilotAddressInfo::EPhoneType) pilotPhoneType;
				break;
			}
		}
		PhoneSlot fieldSlot =
			a.setPhoneField(phoneType, phone.number(), PilotAddress::NoFlags);

		// if this is the preferred phone number, then set it as such
		if (fieldSlot.isValid() && (phone.type() & TDEABC::PhoneNumber::Pref))
		{
			DEBUGKPILOT << fname << ": found preferred PhoneNumber. "
				<< "setting showPhone to index: ["
				<< fieldSlot << "], PhoneNumber: ["
				<< phone.number() << "]" << endl;
			a.setShownPhone( fieldSlot );
		}

		if (!fieldSlot.isValid())
		{
			DEBUGKPILOT << fname << ": Phone listing overflowed." << endl;
		}
	}

	DEBUGKPILOT << fname << ": Pilot's showPhone now: ["
		<< a.getShownPhone() << "]." << endl;

	// after setting the numbers, make sure that something sensible is set as the
	// shownPhone on the Pilot if nothing is yet...
	TQString pref = a.getField(a.getShownPhone());
	if (!a.getShownPhone().isValid() || pref.isEmpty())
	{
		DEBUGKPILOT << fname << ": Pilot's showPhone: ["
			<< a.getShownPhone()
			<< "] not properly set to a default."
			<< endl;

		for (PhoneSlot i = PhoneSlot::begin(); i.isValid(); ++i)
		{
			pref = a.getField(i);
			if (!pref.isEmpty())
			{
				a.setShownPhone( i );
				DEBUGKPILOT << fname << ": Pilot's showPhone now: ["
					<< a.getShownPhone() 
					<< "], and that's final." << endl;
				break;
			}
		}
	}
}

unsigned int TDEABCSync::bestMatchedCategory(const TQStringList &pccategories,
	const PilotAddressInfo &info,
	unsigned int hhcategory)
{
	FUNCTIONSETUP;
	// No categories in list, must be unfiled
	if (pccategories.size()<1)
	{
		return Pilot::Unfiled;
	}

	// See if the suggested hhcategory is in the list, and if
	// so that is the best match.
	if (Pilot::validCategory(hhcategory) &&
		pccategories.contains(info.categoryName(hhcategory)))
	{
		return hhcategory;
	}

	// Look for the first category from the list which is available on
	// the handheld as well.
	for(TQStringList::ConstIterator it = pccategories.begin(); it != pccategories.end(); ++it)
	{
		// Do not map unknown to unfiled when looking for category
		int c = info.findCategory( *it, false );
		if ( c >= 0)
		{
			Q_ASSERT(Pilot::validCategory(c));
			return c;
		}
	}

	// didn't find anything. return null
	return Pilot::Unfiled;
}

void TDEABCSync::setCategory(TDEABC::Addressee & abEntry, const TQString &cat)
{
	if ( (!cat.isEmpty()))
	{
		abEntry.insertCategory(cat);
	}
}


TQString TDEABCSync::getFieldForHHCustom(
	const unsigned int index,
	const TDEABC::Addressee &abEntry,
	const TDEABCSync::Settings &settings)
{
	FUNCTIONSETUPL(4);

	TQString retval;

	if (index>3)
	{
		WARNINGKPILOT << "Bad index number " << index << endl;
		retval = TQString();
	}
	if (settings.customMapping().count() != 4)
	{
		WARNINGKPILOT << "Mapping does not have 4 elements." << index << endl;
		retval = TQString();
	}

	switch (settings.custom(index))
	{
	case eCustomBirthdate:
		if (settings.dateFormat().isEmpty())
		{
			retval = TDEGlobal::locale()->formatDate(abEntry.birthday().date());
		}
		else
		{
			TQString tmpfmt(TDEGlobal::locale()->dateFormat());
			TDEGlobal::locale()->setDateFormat(settings.dateFormat());
			TQString ret(TDEGlobal::locale()->formatDate(abEntry.birthday().date()));
			TDEGlobal::locale()->setDateFormat(tmpfmt);
			retval = ret;
		}
		break;
	case eCustomURL:
		retval = abEntry.url().url();
		break;
	case eCustomIM:
		retval = abEntry.custom(CSL1("KADDRESSBOOK"), CSL1("X-IMAddress"));
		break;
	case eCustomField:
	default:
		retval = abEntry.custom(appString, CSL1("CUSTOM")+TQString::number(index));
		break;
	}

	return retval;
}

void TDEABCSync::setFieldFromHHCustom(
	const unsigned int index,
	TDEABC::Addressee &abEntry,
	const TQString &value,
	const TDEABCSync::Settings &settings)
{
	FUNCTIONSETUPL(4);

	if (index>3)
	{
		WARNINGKPILOT << "Bad index number " << index << endl;
		return;
	}
	if (settings.customMapping().count() != 4)
	{
		WARNINGKPILOT << "Mapping does not have 4 elements." << index << endl;
		return;
	}

	switch (settings.custom(index))
	{
	case eCustomBirthdate:
	{
		TQDate bdate;
		bool ok=false;
		if (settings.dateFormat().isEmpty())
		{
			// empty format means use locale setting
			bdate=TDEGlobal::locale()->readDate(value, &ok);
		}
		else
		{
			// use given format
			bdate=TDEGlobal::locale()->readDate(value, settings.dateFormat(), &ok);
		}

		if (!ok)
		{
			TQString format = TDEGlobal::locale()->dateFormatShort();
			TQRegExp re(CSL1("%[yY][^%]*"));
			format.remove(re); // Remove references to year and following punctuation
			bdate = TDEGlobal::locale()->readDate(value, format, &ok);
		}
		DEBUGKPILOT << "Birthdate from " << index << "-th custom field: "
			<< TQString(bdate.toString()) << endl;
		DEBUGKPILOT << "Is Valid: " << bdate.isValid() << endl;
		if (bdate.isValid())
		{
			abEntry.setBirthday(bdate);
		}
		else
		{
			abEntry.insertCustom(CSL1("KADDRESSBOOK"), CSL1("X-Birthday"), value);
		}
		break;
	}
	case eCustomURL:
		abEntry.setUrl(value);
		break;
	case eCustomIM:
		abEntry.insertCustom(CSL1("KADDRESSBOOK"), CSL1("X-IMAddress"), value);
		break;
	case eCustomField:
	default:
		abEntry.insertCustom(appString, CSL1("CUSTOM")+TQString::number(index), value);
		break;
	}
}


/** First search for a preferred  address. If we don't have one, search
 *  for home or work as specified in the config dialog. If we don't have
 *  such one, either, search for the other type. If we still have no luck,
 *  return an address with preferred + home/work flag (from config dlg). */
TDEABC::Address TDEABCSync::getAddress(const TDEABC::Addressee &abEntry, const TDEABCSync::Settings &s)
{
	// preferhome == (AbbrowserSettings::pilotStreet==0)

	// Check for preferred address first
	TDEABC::Address ad(abEntry.address(TDEABC::Address::Pref));
	if (!ad.isEmpty()) return ad;

	// Look for home or work, whichever is preferred
	int type = s.preferHome() ? TDEABC::Address::Home : TDEABC::Address::Work;
	ad=abEntry.address(type);
	if (!ad.isEmpty()) return ad;

	// Switch preference if still none found
	type = !s.preferHome() ? TDEABC::Address::Home : TDEABC::Address::Work;
	ad=abEntry.address(type);
	if (!ad.isEmpty()) return ad;

	// Last-ditch attempt; see if there is a preferred home or work address
	type = s.preferHome() ? TDEABC::Address::Home : TDEABC::Address::Work;
	return abEntry.address(type | TDEABC::Address::Pref);
}


TQString TDEABCSync::getFieldForHHOtherPhone(const TDEABC::Addressee & abEntry, const TDEABCSync::Settings &s)
{
	switch(s.fieldForOtherPhone())
	{
		case eOtherPhone:
			return abEntry.phoneNumber(0).number();
		case eAssistant:
			return abEntry.custom(CSL1("KADDRESSBOOK"), CSL1("AssistantsName"));
		case eBusinessFax:
			return abEntry.phoneNumber(TDEABC::PhoneNumber::Fax | TDEABC::PhoneNumber::Work).number();
		case eCarPhone:
			return abEntry.phoneNumber(TDEABC::PhoneNumber::Car).number();
		case eEmail2:
			return abEntry.emails().first();
		case eHomeFax:
			return abEntry.phoneNumber(TDEABC::PhoneNumber::Fax | TDEABC::PhoneNumber::Home).number();
		case eTelex:
			return abEntry.phoneNumber(TDEABC::PhoneNumber::Bbs).number();
		case eTTYTTDPhone:
			return abEntry.phoneNumber(TDEABC::PhoneNumber::Pcs).number();
		default:
			return TQString();
	}
}

void TDEABCSync::setFieldFromHHOtherPhone(TDEABC::Addressee & abEntry, const TQString &nr, const TDEABCSync::Settings &s)
{
	int phoneType = 0;
	switch (s.fieldForOtherPhone())
	{
	// One very special case which doesn't even map to a real phone type in KABC
	case eAssistant:
		abEntry.insertCustom(CSL1("KADDRESSBOOK"), CSL1("AssistantsName"), nr);
		return;
	// Special case: map phone to email, needs different handling.
	case eEmail2:
		abEntry.insertEmail(nr);
		return;
	// Remaining cases all map to various phone types
	case eOtherPhone:
		phoneType = 0;
		break;
	case eBusinessFax:
		phoneType = TDEABC::PhoneNumber::Fax | TDEABC::PhoneNumber::Work;
		break;
	case eHomeFax:
		phoneType = TDEABC::PhoneNumber::Fax | TDEABC::PhoneNumber::Home;
		break;
	case eCarPhone:
		phoneType = TDEABC::PhoneNumber::Car;
		break;
	case eTelex:
		phoneType = TDEABC::PhoneNumber::Bbs;
		break;
	case eTTYTTDPhone:
		phoneType = TDEABC::PhoneNumber::Pcs;
		break;
	default:
		WARNINGKPILOT << "Unknown phone mapping " << s.fieldForOtherPhone() << endl;
		phoneType = 0;
	}
	TDEABC::PhoneNumber phone = abEntry.phoneNumber(phoneType);
	phone.setNumber(nr);
	phone.setType(phoneType); // Double-check in case there was no phonenumber of given type
	abEntry.insertPhoneNumber(phone);
}

void TDEABCSync::setAddress(PilotAddress &toPilotAddr,
	const TDEABC::Address & abAddress)
{
	toPilotAddr.setField(entryAddress, abAddress.street());
	toPilotAddr.setField(entryCity, abAddress.locality());
	toPilotAddr.setField(entryState, abAddress.region());
	toPilotAddr.setField(entryZip, abAddress.postalCode());
	toPilotAddr.setField(entryCountry, abAddress.country());
}


bool TDEABCSync::isArchived(const TDEABC::Addressee &addr)
{
	return addr.custom(TDEABCSync::appString, TDEABCSync::flagString) == TQString::number(SYNCDEL);
}

void TDEABCSync::makeArchived(TDEABC::Addressee &addr)
{
	FUNCTIONSETUP;
	addr.insertCustom(TDEABCSync::appString, TDEABCSync::flagString, TQString::number(SYNCDEL));
	addr.removeCustom(TDEABCSync::appString, TDEABCSync::idString);
}




void TDEABCSync::copy(PilotAddress &toPilotAddr,
	const TDEABC::Addressee &fromAbEntry,
	const PilotAddressInfo &appInfo,
	const TDEABCSync::Settings &syncSettings)
{
	FUNCTIONSETUP;

	toPilotAddr.setDeleted(false);

	// don't do a reset since this could wipe out non copied info
	//toPilotAddr.reset();
	toPilotAddr.setField(entryLastname, fromAbEntry.familyName());
	toPilotAddr.setField(entryFirstname, fromAbEntry.givenName());
	toPilotAddr.setField(entryCompany, fromAbEntry.organization());
	toPilotAddr.setField(entryTitle, fromAbEntry.prefix());
	toPilotAddr.setField(entryNote, fromAbEntry.note());

	// do email first, to ensure they get stored
	toPilotAddr.setEmails(fromAbEntry.emails());

	// now in one fell swoop, set all phone numbers from the Addressee.  Note,
	// we don't need to differentiate between Fax numbers here--all Fax numbers
	// (Home Fax or Work Fax or just plain old Fax) will get synced to the Pilot
	TDEABCSync::setPhoneNumbers(appInfo,toPilotAddr,fromAbEntry.phoneNumbers());

	// Other field is an oddball and if the user has more than one field set
	// as "Other" then only one will be carried over.
	TQString oth = TDEABCSync::getFieldForHHOtherPhone(fromAbEntry,syncSettings);
	DEBUGKPILOT << fname << ": putting: ["<<oth<<"] into Palm's other"<<endl;
	toPilotAddr.setPhoneField(PilotAddressInfo::eOther,
		oth, PilotAddress::Replace);

	TDEABC::Address homeAddress = TDEABCSync::getAddress(fromAbEntry, syncSettings);
	TDEABCSync::setAddress(toPilotAddr, homeAddress);

	// Process the additional entries from the Palm(the palm database app block tells us the name of the fields)
	unsigned int customIndex = 0;
	unsigned int hhField = entryCustom1;

	for ( ; customIndex<4; ++customIndex,++hhField )
	{
		toPilotAddr.setField(hhField,getFieldForHHCustom(customIndex,fromAbEntry,syncSettings));
	}

	int categoryForHH = TDEABCSync::bestMatchedCategory(fromAbEntry.categories(),
		appInfo,toPilotAddr.category());
	toPilotAddr.setCategory(categoryForHH);

	if (isArchived(fromAbEntry))
	{
		toPilotAddr.setArchived( true );
	}
	else
	{
		toPilotAddr.setArchived( false );
	}
}

void TDEABCSync::copy(TDEABC::Addressee &toAbEntry,
	const PilotAddress &fromPiAddr,
	const PilotAddressInfo &appInfo,
	const TDEABCSync::Settings &syncSettings)
{
	FUNCTIONSETUP;

	// copy straight forward values
	toAbEntry.setFamilyName(fromPiAddr.getField(entryLastname));
	toAbEntry.setGivenName(fromPiAddr.getField(entryFirstname));
	toAbEntry.setOrganization(fromPiAddr.getField(entryCompany));
	toAbEntry.setPrefix(fromPiAddr.getField(entryTitle));
	toAbEntry.setNote(fromPiAddr.getField(entryNote));

	// set the formatted name
	// TODO this is silly and should be removed soon.
	toAbEntry.setFormattedName(toAbEntry.realName());

	// copy the phone stuff
	// first off, handle the e-mail addresses as a group and separate from
	// the other phone number fields
	toAbEntry.setEmails(fromPiAddr.getEmails());

	// going from Pilot to tdeabc, we need to clear out all phone records in tdeabc
	// so that they can be set from the Pilot.  If we do not do this, then records
	// will be left in tdeabc when they are removed from the Pilot and we'll look
	// broken.
	TDEABC::PhoneNumber::List old = toAbEntry.phoneNumbers();
	for (TDEABC::PhoneNumber::List::Iterator it = old.begin(); it != old.end(); ++it) {
		TDEABC::PhoneNumber phone = *it;
		toAbEntry.removePhoneNumber(phone);
	}

	// now, get the phone numbers from the Pilot and set them one at a time in tdeabc
	TDEABC::PhoneNumber::List phones = TDEABCSync::getPhoneNumbers(fromPiAddr);
	for (TDEABC::PhoneNumber::List::Iterator it = phones.begin(); it != phones.end(); ++it) {
		TDEABC::PhoneNumber phone = *it;
		// check for fax number if it is one, set the type per the user's direction
		if (phone.type() & TDEABC::PhoneNumber::Fax)
		{
			phone.setType(syncSettings.faxTypeOnPC());
		}
		toAbEntry.insertPhoneNumber(phone);
	}

	// Note:  this is weird, and it may cause data to not be synced if there is
	// more than one "Other" field being used on the Pilot, since only one will
	// be synced in either direction.
	TDEABCSync::setFieldFromHHOtherPhone(toAbEntry,
		fromPiAddr.getPhoneField(PilotAddressInfo::eOther),syncSettings);

	// going from Pilot to tdeabc, we need to clear out all addresses in tdeabc
	// so that they can be set from the Pilot.  If we do not do this, then records
	// will be left in tdeabc when they are removed from the Pilot and we'll look
	// broken.
	TDEABC::Address::List oAddr = toAbEntry.addresses();
	for (TDEABC::Address::List::Iterator it = oAddr.begin(); it != oAddr.end(); ++it) {
		const TDEABC::Address addr = *it;
		toAbEntry.removeAddress(addr);
	}
	TDEABC::Address homeAddress = TDEABCSync::getAddress(toAbEntry,syncSettings);
	homeAddress.setStreet(fromPiAddr.getField(entryAddress));
	homeAddress.setLocality(fromPiAddr.getField(entryCity));
	homeAddress.setRegion(fromPiAddr.getField(entryState));
	homeAddress.setPostalCode(fromPiAddr.getField(entryZip));
	homeAddress.setCountry(fromPiAddr.getField(entryCountry));
	toAbEntry.insertAddress(homeAddress);

	unsigned int customIndex = 0;
	unsigned int hhField = entryCustom1;

	for ( ; customIndex<4; ++customIndex,++hhField )
	{
		TDEABCSync::setFieldFromHHCustom(customIndex,
			toAbEntry,
			fromPiAddr.getField(hhField),
			syncSettings);
	}

	// copy the fromPiAddr pilot id to the custom field KPilot_Id;
	// pilot id may be zero(since it could be new) but couldn't hurt
	// to even assign it to zero; let's us know what state the
	// toAbEntry is in
	toAbEntry.insertCustom(TDEABCSync::appString, TDEABCSync::idString, TQString::number(fromPiAddr.id()));

	TDEABCSync::setCategory(toAbEntry, appInfo.categoryName(fromPiAddr.category()));

	showAddressee(toAbEntry);
}

void TDEABCSync::showAddressee(const TDEABC::Addressee & abAddress)
{
	FUNCTIONSETUP;
#ifdef DEBUG
	DEBUGKPILOT << "\tAbbrowser Contact Entry" << endl;
	if (abAddress.isEmpty())
	{
		DEBUGKPILOT<< "\t\tEMPTY"<<endl;
		return;
	}
	DEBUGKPILOT << "\t\tLast name = " << abAddress.familyName() << endl;
	DEBUGKPILOT << "\t\tFirst name = " << abAddress.givenName() << endl;
	DEBUGKPILOT << "\t\tCompany = " << abAddress.organization() << endl;
	DEBUGKPILOT << "\t\tJob Title = " << abAddress.prefix() << endl;
	DEBUGKPILOT << "\t\tNote = " << abAddress.note() << endl;
	DEBUGKPILOT << "\t\tCategory = " << abAddress.categories().first() << endl;
	DEBUGKPILOT << "\t\tEmail = " << abAddress.emails().join(",") << endl;

	TDEABC::PhoneNumber::List phs = abAddress.phoneNumbers();
	for (TDEABC::PhoneNumber::List::Iterator it = phs.begin(); it != phs.end(); ++it) {
		TDEABC::PhoneNumber phone = *it;
		DEBUGKPILOT << "\t\t" << phone.label() 
			<< "= " << phone.number() << endl;
	}

	TDEABC::Address::List ads = abAddress.addresses();
	for (TDEABC::Address::List::Iterator it = ads.begin(); it != ads.end(); ++it) {
		const TDEABC::Address addr = *it;
		DEBUGKPILOT << "\t\tAddress = " << addr.street() <<endl;
		DEBUGKPILOT << "\t\tLocality = " << addr.locality() <<endl;
		DEBUGKPILOT << "\t\tRegion = " << addr.region() <<endl;
		DEBUGKPILOT << "\t\tPostal code = " << addr.postalCode() <<endl;
		DEBUGKPILOT << "\t\tCountry = " << addr.country() <<endl << endl;
	}
#else
	Q_UNUSED( abAddress );
#endif
}




TDEABCSync::Settings::Settings() :
	fDateFormat(),
	fCustomMapping(4), // Reserve space for 4 elements, value 0 == CustomField
	fOtherPhone(eOtherPhone),
	fPreferHome(true),
	fFaxTypeOnPC(TDEABC::PhoneNumber::Fax | TDEABC::PhoneNumber::Home)
{
}