<?php

/**
 * This class is responsible for mapping between the Atmail Contact data
 * structure, and vcards.
 *
 * @package Atmail
 * @subpackage Dav
 * @copyright Copyright (C) 2011 Atmail. All rights reserved.
 * @author Evert Pot (http://www.rooftopsolutions.nl/)
 */
class Atmail_Dav_ContactMapper
{

	/**
	 * Maps a contact array to a 'vcard'.
	 *
	 * @param array $contact
	 * @return void
	 */
	static public function mapContactToVCard(array $contact)
	{

		if (isset($contact['VCardData']) && $contact['VCardData'])
		{
			$vcard = Sabre_VObject_Reader::read($contact['VCardData']);
		}
		else
		{
			$vcard = new Sabre_VObject_Component('VCARD');
			$vcard->version = '3.0';
		}

		// make sure all photo data removed
		if (isset($vcard->photo))
		{
			unset($vcard->photo);
		}

		// specific mapping for X-MS-CARDPICTURE
		if (array_key_exists('X-MS-CARDPICTURE', $vcard))
		{
			unset($vcard['X-MS-CARDPICTURE']);
		}

		$vcard->{'UID'} = isset($vcard->{'UID'}) ? $vcard->{'UID'} : $contact['id'];

		if ($contact['UserEmail'])
		{
			$vcard->{"item1.email"} = $contact['UserEmail'];
		}

		foreach (range(2, 5) as $r)
		{
			if ($contact["UserEmail$r"])
			{
				$vcard->{"item$r.email"} = $contact["UserEmail$r"];
			}
		}

		$vcard->fn = $contact['UserFirstName'] . ' ' . $contact['UserLastName'];
		$vcard->n = $contact['UserLastName'] . ';' . $contact['UserFirstName'] . ';' . $contact['UserMiddleName'] . ';' . $contact['UserTitle'];

		if ($contact['UserGender'])
		{
			$vcard->{"X-Atmail-Gender"} = $contact['UserGender'];
		}

		if ($contact['UserDOB'])
		{
			$vcard->bday = date("Y-m-d", strtotime($contact['UserDOB']));
		}

		foreach (array('Home', 'Work') as $type)
		{
			if (!empty($contact['User' . $type . 'Address']))
			{
				$adr = new Sabre_VObject_Property('adr');
				$adr->value = ';;' .
					$contact['User' . $type . 'Address'] . ';' .
					$contact['User' . $type . 'City'] . ';' .
					$contact['User' . $type . 'State'] . ';' .
					$contact['User' . $type . 'Zip'] . ';' .
					$contact['User' . $type . 'Country'];

				$vcard->add($adr);
				$adr['type'] = strtoupper($type);
			}

			$typeMap = array(
				'Phone' => 'VOICE',
				'Mobile' => 'CELL',
				'Fax' => 'FAX',
			);

			foreach (array('Phone', 'Mobile', 'Fax') as $pType)
			{
				if (!$contact['User' . $type . $pType])
				{
					continue;
				}

				$tel = new Sabre_VObject_Property('tel');
				if(array_key_exists('type', $tel))
				{
					$tel['type'] = strtoupper($type) . ',' . $typeMap[$pType];
				}
				else
				{
					$tel->parameters[] = new Sabre_VObject_Parameter($type,'');
					$tel->parameters[] = new Sabre_VObject_Parameter($typeMap[$pType],'');
				}
				$tel->value = $contact['User' . $type . $pType];
				$vcard->add($tel);
			}
		}

		if ($contact['UserURL'])
		{
			$vcard->url = $contact['UserURL'];
		}
		if ($contact['UserInfo'])
		{
			$vcard->{'note'} = $contact['UserInfo'];
		}
		if ($contact['UserWorkCompany'] || $contact['UserWorkDept'])
		{
			$vcard->{"ORG"} = $contact['UserWorkCompany'] . ( $contact['UserWorkDept'] != '' ? (';' . $contact['UserWorkDept']) : '');
		}
		if ($contact['UserWorkTitle'])
		{
			$vcard->{"TITLE"} = $contact['UserWorkTitle'];
		}
		if ($contact['UserWorkOffice'])
		{
			$vcard->{"X-Atmail-WorkOffice"} = $contact['UserWorkOffice'];
		}
		if ($contact['UserPhoto'])
		{
			if (isset($vcard->photo))
			{
				unset($vcard->photo);
			}
			$photo = new Sabre_VObject_Property('PHOTO');
			$photo->value = rtrim($contact['UserPhoto'], "\n");
			$photo['TYPE'] = "JPEG";
			$photo['ENCODING'] = "BASE64";
			$vcard->add($photo);
		}
		else
		{
			if (isset($vcard->photo))
			{
				unset($vcard->photo);
			}
		}

		return rtrim($vcard->serialize(), "\n");

	}

	/**
	 * Maps a VCard blob to a 'Contact' array
	 *
	 * @param string $vcardData
	 * @return array
	 */
	static public function mapVCardToContact($vcardData)
	{

		$vcard = Sabre_VObject_Reader::read($vcardData);

		$contact = array();

		$emailCount = 0;
		foreach ($vcard->select('email') as $key => $email)
		{
			$emailCount++;

			$contact['UserEmail' . ($emailCount === 1 ? '' : $emailCount)] = $email->value;
			unset($vcard->children[$key]);

			// We only store the first 5 emails.
			if ($emailCount === 5)
			{
				break;
			}
		}

		// Getting rid of 'fn' as it duplicates data from 'n'.
		unset($vcard->fn);

		if ($vcard->n)
		{
			$name = explode(';', $vcard->n->value);

			$contact['UserLastName'] = $name[0];
			if (isset($name[1]))
			{
				$contact['UserFirstName'] = $name[1];
			}
			if (isset($name[2]))
			{
				$contact['UserMiddleName'] = $name[2];
			}
			if (isset($name[3]))
			{
				$contact['UserTitle'] = $name[3];
			}
			unset($vcard->n);
		}

		if(isset($vcard->{"note"}))
		{
			$contact['UserInfo'] = $vcard->{"note"}->value;
			unset($vcard->note);
		}

		if (isset($vcard->{"X-Atmail-Gender"}))
		{
			$contact['UserGender'] = $vcard->{"X-Atmail-Gender"}->value;
			unset($vcard->{"X-Atmail-Gender"});
		}

		if (isset($vcard->bday))
		{
			$bday = $vcard->bday;
			if (preg_match('/^([0-9]{4})([-]?)([0-9]{2})([-]?)([0-9]{2})/', $bday->value, $matches))
			{
				$contact['UserDOB'] = $matches[1] . '-' . $matches[3] . '-' . $matches[5];
				unset($vcard->bday);
			}
		}

		foreach ($vcard->select('ADR') as $key => $adr)
		{
			// Skipping if there's no 'TYPE' parameter
			if (array_key_exists('type', $adr))
			{
				if (array_key_exists('type', $adr) && stripos($adr['type']->value, 'home') !== false)
				{
					$type = 'Home';
				}
				else if (array_key_exists('type', $adr) && stripos($adr['type']->value, 'work') !== false)
				{
					$type = 'Work';
				}
				else
				{
					// If it's neither Home nor Work, we'll mark it as Home
					$type = 'Home';
				}
			}
			else if (array_key_exists('parameters', $adr))
			{
				$lType = 'Home';
				foreach ($adr->parameters as $parameter)
				{
					if (strtoupper($parameter->name) == 'WORK')
					{
						$type = 'Work';
					}
					else if (strtoupper($parameter->name) == 'HOME')
					{
						$type = 'Home';
					}
				}
			}

			// If we already parsed this value, we'll skip it too
			if (isset($contact['User' . $type . 'Address']))
			{
				continue;
			}

			$value = explode(';', $adr->value);

			if (isset($value[2]))
			{
				$contact['User' . $type . 'Address'] = $value[2];
			}
			if (isset($value[3]))
			{
				$contact['User' . $type . 'City'] = $value[3];
			}
			if (isset($value[4]))
			{
				$contact['User' . $type . 'State'] = $value[4];
			}
			if (isset($value[5]))
			{
				$contact['User' . $type . 'Zip'] = $value[5];
			}
			if (isset($value[6]))
			{
				$contact['User' . $type . 'Country'] = $value[6];
			}
			unset($vcard->children[$key]);
		}

		foreach ($vcard->select('TEL') as $key => $tel)
		{

			$lType = null;
			$pType = null;

			// Skipping if there's no 'TYPE' parameter
			if (isset($tel['type']))
			{
				// There may be multiple 'TYPE' paramters, so we'll combine them.
				$telType = '';
				if (count($tel['type']) == 1)
				{
					$telType = $tel['type']->value;
				}
				else
				{
					foreach ($tel['type'] as $type)
					{
						$telType .= ',' . $type->value;
					}
				}

				if (stripos($telType, 'home') !== false)
				{
					$lType = 'Home';
				}
				else if (stripos($telType, 'work') !== false)
				{
					$lType = 'Work';
				}
				else
				{
					// If it's neither Home nor Work, we'll mark it as Home
					$lType = 'Home';
				}

				if (stripos($telType, 'cell'))
				{
					$pType = 'Mobile';
				}
				else if (stripos($telType, 'fax'))
				{
					$pType = 'Fax';
				}
				else if (stripos($telType, 'voice'))
				{
					$pType = 'Phone';
				}
				else
				{
					// If it's not mobile, fax or voice, we'll mark it as Mobile
					$pType = 'Mobile';
					//continue;
				}
			}
			else if (array_key_exists('parameters', $tel))
			{
				//try find matches in the paramters for home, work, and then cell voice fax
				foreach ($tel->parameters as $parameter)
				{
					if (!empty($lType) && !empty($pType))
					{
						break;
					}
					if (strtoupper($parameter->name) == 'IPHONE')
					{
						$pType = 'Mobile';
					}
					else if (strtoupper($parameter->name) == 'CELL')
					{
						$pType = 'Mobile';
					}
					else if (strtoupper($parameter->name) == 'WORK')
					{
						$lType = 'Work';
					}
					else if (strtoupper($parameter->name) == 'MAIN')
					{
						$lType = 'Work';
					}
					else if (strtoupper($parameter->name) == 'HOME')
					{
						$lType = 'Home';
					}
					else if (strtoupper($parameter->name) == 'FAX')
					{
						$pType = 'Fax';
					}
					else if (strtoupper($parameter->name) == 'VOICE' && empty($pType))
					{
						$pType = 'Phone';
					}
				}
			}
			if ($pType === null)
			{
				if ($lType !== null && isset($contact['User' . $lType . 'Phone']) && !isset($contact['User' . $lType . 'Mobile']))
				{
					$pType = 'Mobile';
				}
				else
				{
					$pType = 'Phone';
				}
			}
			if ($lType === null)
			{
				if (isset($contact['UserHome' . $pType]) && !isset($contact['UserWork' . $pType]))
				{
					$lType = 'Work';
				}
				else
				{
					$lType = 'Home';
				}

			}
			/*else
			{
				continue;
			}*/

			// If we already parsed this value, we'll skip it as well
			if (isset($contact['User' . $lType . $pType]))
			{
				continue;
			}

			$contact['User' . $lType . $pType] = $tel->value;
			unset($vcard->children[$key]);

		}

		if ($vcard->url)
		{
			$contact['UserURL'] = $vcard->url->value;
			unset($vcard->url);
		}

		$otherValues = array(
			'WorkCompany',
			'WorkTitle',
			'WorkOffice',
		);

		if ($vcard->org)
		{
			$company = $vcard->org->value;
			if(strpos($vcard->org->value, ';') !== false)
			{
				list($company, $dept) = explode(';', $vcard->org->value);
				$contact['UserWorkDept'] = $dept;
			}
			$contact['UserWorkCompany'] = $company;
			unset($vcard->org);
		}
		if ($vcard->title)
		{
			$contact['UserWorkTitle'] = $vcard->title->value;
			unset($vcard->title);
		}

		foreach ($otherValues as $otherValue)
		{

			if (isset($vcard->{'X-Atmail-' . $otherValue}))
			{
				$contact['User' . $otherValue] = $vcard->{'X-Atmail-' . $otherValue}->value;
				unset($vcard->{'X-Atmail-' . $otherValue});
			}

		}

		if (isset($vcard->photo) && isset($vcard->photo['BASE64']) || (isset($vcard->photo['ENCODING']) && $vcard->photo['ENCODING']->value == 'BASE64'))
		{
			// dont accept the default 1x1 picture from outlook.
			if(md5($vcard->photo->value) != '3b574025eb48fda6abd1a708dd3479a5')
			{
				$contact['UserPhoto'] = $vcard->photo->value;
			}
			else
			{
				unset($vcard->photo);
			}
		}

		if (isset($vcard->photo) && array_key_exists('UserPhoto', $contact))
		{
			unset($vcard->photo);
		}

		$contact['VCardData'] = $vcard->serialize();

		return $contact;

	}

}
