<?php

/*
 * Copyright (C) 2002-2013 AfterLogic Corp. (www.afterlogic.com)
 * Distributed under the terms of the license described in LICENSE
 *
 */

/**
 * @package Contacts
 */
class CApiContactsManager extends AApiManager
{
	/*
	 * @var $oApiContactsManager CApiMaincontactsManager
	 */
	private $oApiContactsManager;

	/*
	 * @var $oApiGContactsManager CApiGcontactsManager
	 */
	private $oApiGContactsManager;

	/*
	 * @var $oApiSabreContactsManager CApiMaincontactsManager
	 */
	private $oApiContactsManagerSabreDAV;

	/**
	 * @param CApiGlobalManager &$oManager
	 */
	public function __construct(CApiGlobalManager &$oManager, $sForcedStorage = '')
	{
		parent::__construct('contacts', $oManager, $sForcedStorage);

		$this->oApiGContactsManager = CApi::Manager('gcontacts');
		$this->oApiContactsManager = CApi::Manager('maincontacts');
		$this->oApiContactsManagerSabreDAV = CApi::Manager('maincontacts', 'sabredav');
	}

	/**
	 * @return CContactListItem
	 */
	public function NewContactListItemObject()
	{
		return new CContactListItem();
	}

	/**
	 * @return CContact
	 */
	public function NewContactObject()
	{
		return new CContact();
	}

	/**
	 * @return CGroup
	 */
	public function NewGroupObject()
	{
		return new CGroup();
	}

	/**
	 * @param int $iUserId
	 * @param mixed $mContactId
	 * @return CContact | bool
	 */
	public function GetContactById($iUserId, $mContactId)
	{
		return $this->oApiContactsManager->GetContactById($iUserId, $mContactId);
	}

	/**
	 * @param int $iUserId
	 * @param string $sEmail
	 * @return CContact | bool
	 */
	public function GetContactByEmail($iUserId, $sEmail)
	{
		return $this->oApiContactsManager->GetContactByEmail($iUserId, $sEmail);
	}

	/**
	 * @param int $iUserId
	 * @param string $sContactStrId
	 * @return CContact
	 */
	public function GetContactByStrId($iUserId, $sContactStrId)
	{
		return $this->oApiContactsManager->GetContactByStrId($iUserId, $sContactStrId);
	}

	/**
	 * @param CContact $oContact
	 * @return array | bool
	 */
	public function GetContactGroupsIds($oContact)
	{
		return $this->oApiContactsManager->GetContactGroupsIds($oContact);
	}

	/**
	 * @param int $iUserId
	 * @param mixed $mGroupId
	 * @return CGroup
	 */
	public function GetGroupById($iUserId, $mGroupId)
	{
		return $this->oApiContactsManager->GetGroupById($iUserId, $mGroupId);
	}

	/**
	 * @param int $iUserId
	 * @param string $sGroupStrId
	 * @return CGroup
	 */
	public function GetGroupByStrId($iUserId, $sGroupStrId)
	{
		return $this->oApiContactsManager->GetGroupByStrId($iUserId, $sGroupStrId);
	}

	/**
	 * @param CContact $oContact
	 * @return bool
	 */
	public function UpdateContact($oContact, $bUpdateFromGlobal = true)
	{
		$res1 = $res2 = false;

		if ($oContact)
		{
			if ($oContact->Type === EContactType::Personal)
			{
				$res1 = $this->oApiContactsManager->UpdateContact($oContact);
			}
			else if ($oContact->Type === EContactType::Global_)
			{
				$res1 = $this->oApiContactsManager->UpdateContact($oContact);
				
				if ($res1 && $bUpdateFromGlobal)
				{
					$oGlobalContact = $this->oApiContactsManager->GetMyGlobalContact($oContact->IdUser);
					if ($oGlobalContact)
					{
						if ($oGlobalContact->CompareAndComputedByNewGlobalContact($oContact))
						{
							$res1 = $this->oApiGContactsManager->UpdateContact($oGlobalContact);
						}
						else
						{
							$res1 = true;
						}
					}
				}
			}

			if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
			{
				// TODO sasha
//				$this->UpdateContactGroupsIdsWhithNames($oContact);
				$res2 = $this->oApiContactsManagerSabreDAV->UpdateContact($oContact);
			}
			else
			{
				$res2 = true;
			}
		}

		return ($res1 && $res2);
	}

	/**
	 * @param CGroup $oGroup
	 * @return bool
	 */
	public function UpdateGroup($oGroup)
	{
		$res1 = $res2 = false;

		$oGroupDb = $this->oApiContactsManager->GetGroupById($oGroup->IdUser, $oGroup->IdGroup);

		$res1 = $this->oApiContactsManager->UpdateGroup($oGroup);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts') && $oGroupDb)
		{
			$oGroup->IdGroup = $oGroupDb->Name;

			$oContactItems = $this->oApiContactsManager->GetContactItems($oGroup->IdUser, EContactSortField::EMail,
				ESortOrder::ASC, 0, 999, '', '', $oGroupDb->IdGroup);
			if (is_array($oContactItems))
			{
				foreach ($oContactItems as $oContactItem)
				{
					$oContact = $this->oApiContactsManagerSabreDAV->GetContactById($oGroup->IdUser, $oContactItem->IdStr);
					if ($oContact)
					{
						$aGroupsIds = array();
						foreach($oContact->GroupsIds as $iGroupId)
						{
							if ($iGroupId === $oGroup->IdGroup)
							{
								$iGroupId = $oGroup->Name;
							}
							$aGroupsIds[] = $iGroupId;
						}
						$oContact->GroupsIds = $aGroupsIds;
						$this->oApiContactsManagerSabreDAV->UpdateContact($oContact);
					}
				}
			}
			$res2 = true;
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @param int $iUserId
	 * @param string $sSearch = ''
	 * @param string $sFirstCharacter = ''
	 * @param int $iGroupId = 0
	 * @return int
	 */
	public function GetContactItemsCount($iUserId, $sSearch = '', $sFirstCharacter = '', $iGroupId = 0)
	{
		return $this->oApiContactsManager->GetContactItemsCount($iUserId, $sSearch, $sFirstCharacter, $iGroupId);
	}

	/**
	 * @param int $iUserId
	 * @param int $iOffset = 0
	 * @param int $iRequestLimit = 20
	 * @return bool | array
	 */
	public function GetContactItemsWithoutOrder($iUserId, $iOffset = 0, $iRequestLimit = 20)
	{
		return $this->oApiContactsManager->GetContactItemsWithoutOrder($iUserId, $iOffset, $iRequestLimit);
	}

	/**
	 * @param string $mUserId
	 * @param int $iSortField = EContactSortField::EMail,
	 * @param int $iSortOrder = ESortOrder::ASC,
	 * @param int $iOffset = 0
	 * @param int $iRequestLimit = 20
	 * @param string $sSearch = ''
	 * @param string $sFirstCharacter = ''
	 * @param string $mGroupId = ''
	 * @return bool | array
	 */
	public function GetContactItems($mUserId,
		$iSortField = EContactSortField::EMail, $iSortOrder = ESortOrder::ASC,
		$iOffset = 0, $iRequestLimit = 20, $sSearch = '', $sFirstCharacter = '', $mGroupId = '')
	{
		return $this->oApiContactsManager->GetContactItems($mUserId, $iSortField, $iSortOrder,
			$iOffset, $iRequestLimit, $sSearch, $sFirstCharacter, $mGroupId);
	}

	/**
	 * @param int $iUserId
	 * @param string $sSearch = ''
	 * @param string $sFirstCharacter = ''
	 * @return int
	 */
	public function GetGroupItemsCount($iUserId, $sSearch = '', $sFirstCharacter = '')
	{
		return $this->oApiContactsManager->GetGroupItemsCount($iUserId, $sSearch, $sFirstCharacter);
	}

	/**
	 * @param int $iUserId
	 * @param int $iSortField = EContactSortField::Name,
	 * @param int $iSortOrder = ESortOrder::ASC,
	 * @param int $iOffset = 0
	 * @param int $iRequestLimit = 20
	 * @param string $sSearch = ''
	 * @param string $sFirstCharacter = ''
	 * @param int $iContactId = 0
	 * @return bool | array
	 */
	public function GetGroupItems($iUserId,
		$iSortField = EContactSortField::Name, $iSortOrder = ESortOrder::ASC,
		$iOffset = 0, $iRequestLimit = 20, $sSearch = '', $sFirstCharacter = '', $iContactId = 0)
	{
		return $this->oApiContactsManager->GetGroupItems($iUserId, $iSortField, $iSortOrder,
			$iOffset, $iRequestLimit, $sSearch, $sFirstCharacter, $iContactId);
	}

	/**
	 * @param CAccount $oAccount
	 * @param string $sSearch = ''
	 * @param int $iRequestLimit = 20
	 * @param bool $bGlobalOnly = false
	 * @param bool $bPhoneOnly = false
	 *
	 * @return bool | array
	 */
	public function GetSuggestItems($oAccount, $sSearch = '', $iRequestLimit = 20, $bGlobalOnly = false, $bPhoneOnly = false)
	{
		return $this->oApiContactsManager->GetSuggestItems($oAccount, $sSearch, $iRequestLimit, $bGlobalOnly, $bPhoneOnly);
	}

	/**
	 * @param CContact $oContact
	 * @return bool
	 */
	public function CreateContact($oContact)
	{
		$res1 = $res2 = false;

		$res1 = $this->oApiContactsManager->CreateContact($oContact);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$this->UpdateContactGroupsIdsWhithNames($oContact);
			$res2 = $this->oApiContactsManagerSabreDAV->CreateContact($oContact);
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @param CGroup $oGroup
	 * @return bool
	 */
	public function CreateGroup($oGroup)
	{
		$res1 = $res2 = false;

		$res1 = $this->oApiContactsManager->CreateGroup($oGroup);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->CreateGroup($oGroup);
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @param int $iUserId
	 * @param array $aContactsIds
	 * @return bool
	 */
	public function DeleteContacts($iUserId, $aContactsIds)
	{
		$aContactsStrIds = array();
		foreach ($aContactsIds as $iContactsId)
		{
			$oContact = $this->oApiContactsManager->GetContactById($iUserId, $iContactsId);
			if ($oContact)
			{
				$aContactsStrIds[] = $oContact->IdContactStr;
			}
		}

		$res1 = $res2 = false;

		$res1 = $this->oApiContactsManager->DeleteContacts($iUserId, $aContactsIds);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->DeleteContacts($iUserId, $aContactsStrIds);
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @param int $iUserId
	 * @param array $aContactsIds
	 * @return bool
	 */
	public function DeleteSuggestContacts($iUserId, $aContactsIds)
	{
		$aContactsStrIds = array();
		foreach ($aContactsIds as $iContactsId)
		{
			$oContact = $this->oApiContactsManager->GetContactById($iUserId, $iContactsId);
			if ($oContact)
			{
				$aContactsStrIds[] = $oContact->IdContactStr;
			}
		}

		$res1 = $res2 = false;

		$res1 = $this->oApiContactsManager->DeleteSuggestContacts($iUserId, $aContactsIds);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->DeleteSuggestContacts($iUserId, $aContactsStrIds);
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @param int $iUserId
	 * @param array $aGroupsIds
	 * @return bool
	 */
	public function DeleteGroups($iUserId, $aGroupsIds)
	{
		$res1 = $res2 = false;

		$res1 = $this->oApiContactsManager->DeleteGroups($iUserId, $aGroupsIds);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->DeleteGroups($iUserId, $aGroupsIds);
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @param int $iUserId
	 * @param mixed $mGroupId
	 * @return bool
	 */
	public function DeleteGroup($iUserId, $mGroupId)
	{
		return $this->oApiContactsManager->DeleteGroup($iUserId, $mGroupId);
	}

	/**
	 * @param int $iUserId
	 * @param array $aEmails
	 * @return bool
	 */
	function UpdateSuggestTable($iUserId, $aEmails)
	{
		$res1 = $res2 = false;

		$res1 = $this->oApiContactsManager->UpdateSuggestTable($iUserId, $aEmails);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->UpdateSuggestTable($iUserId, $aEmails);
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @param int $iUserId
	 * @param string $sSyncType
	 * @param string $sTempFileName
	 * @return int | false
	 */
	public function Import($iUserId, $sSyncType, $sTempFileName)
	{
		$iParsedCount = 0;
		return $this->ImportEx($iUserId, $sSyncType, $sTempFileName, $iParsedCount);
	}

	/**
	 * @param int $iUserId
	 * @param string $sSyncType
	 * @param string $sTempFileName
	 * @param int $iParsedCount
	 * @return int | false
	 */
	public function ImportEx($iUserId, $sSyncType, $sTempFileName, &$iParsedCount)
	{
		$this->inc('helpers.'.$sSyncType.'.formatter');
		$this->inc('helpers.'.$sSyncType.'.parser');
		$this->inc('helpers.sync.'.$sSyncType);

		$sSyncClass = 'CApi'.ucfirst($this->GetManagerName()).'Sync'.ucfirst($sSyncType);
		if (class_exists($sSyncClass))
		{
			$oSync = new $sSyncClass($this);
			return $oSync->Import($iUserId, $sTempFileName, $iParsedCount);
		}

		return false;
	}

	/**
	 * @param int $iUserId
	 * @param string $sSyncType
	 * @return string | bool
	 */
	public function Export($iUserId, $sSyncType)
	{
		$this->inc('helpers.'.$sSyncType.'.formatter');
		$this->inc('helpers.'.$sSyncType.'.parser');
		$this->inc('helpers.sync.'.$sSyncType);

		$sSyncClass = 'CApi'.ucfirst($this->GetManagerName()).'Sync'.ucfirst($sSyncType);
		if (class_exists($sSyncClass))
		{
			$oSync = new $sSyncClass($this);
			return $oSync->Export($iUserId);
		}

		return false;
	}

	/**
	 * @param int $iUserId
	 * @param array $aContactsIds
	 * @return bool
	 */
//	public function DeleteContactsExceptIds($iUserId, $aContactsIds)
//	{
//		$aContactsStrIds = array();
//		foreach ($aContactsIds as $iContactsId)
//		{
//			$oContact = $this->oApiContactsManager->GetContactById($iUserId, $iContactsId);
//			if ($oContact)
//			{
//				$aContactsStrIds[] = $oContact->IdContactStr;
//			}
//		}
//
//		$res1 = $res2 = false;
//
//		$res1 = $this->oApiContactsManager->DeleteContactsExceptIds($iUserId, $aContactsIds);
//		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
//		{
//			$res2 = $this->oApiContactsManagerSabreDAV->DeleteContactsExceptIds($iUserId, $aContactsStrIds);
//		}
//		else
//		{
//			$res2 = true;
//		}
//
//		return ($res1 && $res2);
//	}

	/**
	 * @param int $iUserId
	 * @param array $aGroupIds
	 * @return bool
	 */
//	public function DeleteGroupsExceptIds($iUserId, $aGroupIds)
//	{
//		$res1 = $res2 = false;
//
//		$res1 = $this->oApiContactsManager->DeleteGroupsExceptIds($iUserId, $aGroupIds);
//		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
//		{
//			$res2 = $this->oApiContactsManagerSabreDAV->DeleteGroupsExceptIds($iUserId, $aGroupIds);
//		}
//		else
//		{
//			$res2 = true;
//		}
//
//		return ($res1 && $res2);
//	}

	/**
	 * @param CAccount $oAccount
	 * @return bool
	 */
	public function ClearAllContactsAndGroups($oAccount)
	{
		$res1 = $res2 = false;

		$res1 = $this->oApiContactsManager->ClearAllContactsAndGroups($oAccount);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->ClearAllContactsAndGroups($oAccount);
		}
		else
		{
			$res2 = true;
		}

		return ($res1 && $res2);
	}

	/**
	 * @return bool
	 */
	public function FlushContacts()
	{
		return $this->oApiContactsManager->FlushContacts();
	}

	public function UpdateContactGroupsIdsWhithNames(&$oContact)
	{
		$aResult = array();

		foreach ($oContact->GroupsIds as $mGroupId)
		{
			$oGroup = $this->oApiContactsManager->GetGroupById($oContact->IdUser, $mGroupId);
			if ($oGroup)
			{
				$aResult[] = $oGroup->Name;
			}
		}
		
		$oContact->GroupsIds = $aResult;
	}

	/**
	 * @param CGroup $oGroup
	 * @param array $aContactIds
	 * @return bool
	 */
	public function AddContactsToGroup($oGroup, $aContactIds)
	{
		$res1 = $res2 = false;

		$aContactsStrIds = array();
		foreach ($aContactIds as $iContactId)
		{
			$oContact = $this->oApiContactsManager->GetContactById($oGroup->IdUser, $iContactId);
			if ($oContact)
			{
				$aContactsStrIds[] = $oContact->IdContactStr;
			}
		}
		
		$res1 = $this->oApiContactsManager->AddContactsToGroup($oGroup, $aContactIds);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->AddContactsToGroup($oGroup, $aContactsStrIds);
		}
		else
		{
			$res2 = true;
		}
		
		return ($res1 && $res2);
	}
	
	/**
	 * @param CAccount $oAccount
	 * @param CGroup $oGroup
	 * @param array $aContactIds
	 * @return bool
	 */
	public function AddGlobalContactsToGroup($oAccount, $oGroup, $aContactIds)
	{
		if ($this->oApiGContactsManager)
		{
			$aNewContactIds = array();

			foreach ($aContactIds as $mId)
			{
				$mContactId = $this->oApiContactsManager->ConvertedContactLocalId($oAccount, $mId, EContactType::Global_);

				CApi::LogObject($mContactId);
				if (!$mContactId)
				{
					$oGlobalContact = $this->oApiGContactsManager->GetContactById($oAccount, $mId);

					CApi::LogObject($oGlobalContact);
					
					/* @var $oGlobalContact CContact */
					if ($oGlobalContact)
					{
						$oGlobalContact->IdUser = $oAccount->IdUser;
						$oGlobalContact->IdDomain = $oAccount->IdDomain;
						$oGlobalContact->IdTenant = $oAccount->IdTenant;
						$oGlobalContact->Type = EContactType::Global_;
						$oGlobalContact->IdTypeLink = $mId;

						$bResult = $this->CreateContact($oGlobalContact);
						if ($bResult)
						{
							$aNewContactIds[] = $oGlobalContact->IdContact;
						}
					}
				}
				else
				{
					$aNewContactIds[] = $mContactId;
				}
			}

			if (0 < count($aNewContactIds))
			{
				return $this->AddContactsToGroup($oGroup, $aNewContactIds);
			}
		}
	}

	/**
	 * @param CGroup $oGroup
	 * @param array $aContactIds
	 * @return bool
	 */
	public function RemoveContactsFromGroup($oGroup, $aContactIds)
	{
		$res1 = $res2 = false;

		$aContactsStrIds = array();
		foreach ($aContactIds as $iContactId)
		{
			$oContact = $this->oApiContactsManager->GetContactById($oGroup->IdUser, $iContactId);
			if ($oContact)
			{
				$aContactsStrIds[] = $oContact->IdContactStr;
			}
		}

		$res1 = $this->oApiContactsManager->RemoveContactsFromGroup($oGroup, $aContactIds);
		if ('sabredav' !== CApi::GetManager()->GetStorageByType('contacts'))
		{
			$res2 = $this->oApiContactsManagerSabreDAV->RemoveContactsFromGroup($oGroup, $aContactsStrIds);
		}
		else
		{
			$res2 = true;
		}
		return ($res1 && $res2);
	}

	/**
	 * @param CAccount $oAccount
	 * @return bool
	 */
	public function SynchronizeExternalContacts($oAccount, $bSelfOnly = false)
	{
		$aIds = array();
		if ($this->oApiGContactsManager)
		{
			if ($bSelfOnly)
			{
				$oGlobalContact = $this->oApiGContactsManager->GetContactByTypeId($oAccount, $oAccount->IdUser);

				/* @var $oGlobalContact CContact */
				if ($oGlobalContact)
				{
					$mContactId = $this->oApiContactsManager->ConvertedContactLocalId($oAccount,
						$oGlobalContact->IdContact, EContactType::Global_);

					if ($mContactId)
					{
						$aIds[$mContactId] = $oGlobalContact->IdContact;
					}
				}
			}
			else
			{
				$aIds = $this->oApiContactsManager->ConvertedContactLocalIdCollection($oAccount, EContactType::Global_);
			}

			if ($aIds && is_array($aIds) && 0 < count($aIds))
			{
				CApi::Log('SynchronizeExternalContacts: '.count($aIds));

				$aLinkedContact = $this->oApiContactsManager->ContactIdsLinkedToGroups(array_keys($aIds));
				$aLinkedContact = is_array($aLinkedContact) ? $aLinkedContact : array();

				$aContactToDelete = array();
				foreach ($aIds as $iLocalContactId => $sGlobalId)
				{
					if (in_array($iLocalContactId, $aLinkedContact))
					{
						$oGlobalContact = $this->oApiGContactsManager->GetContactById($oAccount, $sGlobalId);
						if ($oGlobalContact)
						{
							$oLocalGlobalContact = $this->oApiContactsManager->GetContactById($oAccount->IdUser, $iLocalContactId);
							if ($oLocalGlobalContact && EContactType::Global_ === $oLocalGlobalContact->Type)
							{
								if ($oLocalGlobalContact->CompareAndComputedByNewGlobalContact($oGlobalContact))
								{
									$this->UpdateContact($oLocalGlobalContact, false);
								}
							}
						}
						else
						{
							$aContactToDelete[] = $iLocalContactId;
						}
					}
					else
					{
						$aContactToDelete[] = $iLocalContactId;
					}
				}

				if (0 < count($aContactToDelete))
				{
					$this->DeleteContacts($oAccount->IdUser, $aContactToDelete);
				}

				return true;
			}
			else
			{
				CApi::Log('SynchronizeExternalContacts: none');
			}
		}

		return true;
	}
}
