<?php
class Mail_ContactsController extends Zend_Controller_Action
{
	private $_contacts;

	public function init()
	{
		//$contextSwitch = $this->_helper->getHelper('contextSwitch');
		//$contextSwitch->addActionContext('index', 'xml')->addActionContext('read', 'xml')->initContext();
		$this->view->addHelperPath('library/Atmail/View/Helper/', 'Atmail_View_Helper');
	}

	public function preDispatch()
	{
        $this->_helper->pluginCall('startControllerPreDispatch');

		// setup filters
		$this->filter = Atmail_Filter_Input_Controller::filterInput($this->_request);

		require_once 'library/jQuery/jQuery.php';
		require_once 'library/Atmail/ThumbNail.php';
		require_once 'library/Atmail/Vcard.php';
        
		if( $this->getRequest()->isXmlHttpRequest() || $this->getRequest()->isAjax )
		{

			$this->view->jsonIdsToRender = array();
			Zend_Registry::get('log')->info(__METHOD__ . ' isAJAX request');//show a hidden dialog box and include desired content
			$this->isAjax = true;

		}
		else
		{

			Zend_Registry::get('log')->info(__METHOD__ . ' normal HTML request');//show a hidden dialog box and include desired content
			$this->isAjax = false;

		}

		// check if we have been authenticated... and redirect if not
		if( !Atmail_FormAuth::authenticated() )
		{

			// we have most probably timed out, so lets kick them to the timeout bootstrap page
			// this will poison json responses, which will fire the php.error ( or ajax.error ) which can detect the special page
			$this->_forward('timeout', 'index', 'default');
			return;

		}
		else
		{

			$this->view->requestParams = $this->getRequest()->getParams();
			$this->view->setEncoding('UTF-8');
			$this->view->siteBaseUrl = Zend_Registry::get('siteBaseUrl');
			$this->view->appBaseUrl = $this->getRequest()->getBaseUrl() . (strpos($this->getRequest()->getBaseUrl(),'index.php')?'':'/index.php');
			$this->view->moduleBaseUrl = $this->view->appBaseUrl . ($this->view->requestParams['module']=='default'?'':'/' . $this->view->requestParams['module']);
			$this->view->thisActionURL = $this->view->moduleBaseUrl . '/' . $this->view->requestParams['controller'] . '/' . $this->view->requestParams['action'];
			$this->view->notices = array();
			$this->view->errors = array();
			$this->session = new Zend_Session_Namespace(ATMAIL_NAMESPACE);
			$this->userData = Zend_Auth::getInstance()->getStorage()->read();
			$this->userData = Atmail_Password::processUser($this->userData);
			
			$this->_helper->pluginCall('postFetchUserData');
			$this->view->global = Zend_Registry::get('config')->global;
			$this->_currentConfig = array();
			
			$this->view->autocompleteFetchThreshold = (isset($this->view->global['autocompleteFetchThreshold']) ? $this->view->global['autocompleteFetchThreshold'] : 50);
			$this->view->autocompleteCacheSize = (isset($this->view->global['autocompleteCacheSize']) ? $this->view->global['autocompleteCacheSize'] : 100);
			$this->view->autocompleteFetchSize = (isset($this->view->global['autocompleteFetchSize']) ? $this->view->global['autocompleteFetchSize'] : 25);
			$this->view->autocompleteMinFetchLength = (isset($this->view->global['autocompleteMinFetchLength']) ? $this->view->global['autocompleteMinFetchLength'] : 2);
            
			require_once 'application/models/contacts.php';
            $this->_helper->pluginCall('preCreateContactsModel');
			$this->_contacts = new contacts( array('Account' => $this->userData['Account'], 'largeInstall' => '0') );
            $this->_helper->pluginCall('postCreateContactsModel');

			// Find the users settings ( used for theme )
			$this->view->UserSettings = Zend_Registry::get('UserSettings');
			$this->_helper->pluginCall('postFetchUserSettings');

			// Used to determine the contact in the global addressbook
			$this->view->Account = $this->userData['Account'];
			try
			{

				$this->view->group = groups::get( array_key_exists('Ugroup', $this->userData) ? $this->userData['Ugroup'] : '' );	
				if($this->view->group == false)
					$this->view->group = groups::get( 'default' );

			}
			catch( exception $e )
			{
				$this->view->group = groups::get( 'default' );		
			}
		}
        $this->_helper->pluginCall('endControllerPreDispatch');

	}
 
	public function indexAction()
	{

		if(!$this->_contacts)
		{

			// the contacts object has gone
			// we are probably timed out
			// bail
			return;

		}
        
		//syncContacts hook
		$this->syncContacts();

		$this->view->groups = $this->_contacts->getGroups();

		$this->view->currentGroup = $this->_contacts->getCurrentGroup();
		$contactsAll = $this->_contacts->getContacts(array('GroupName' => $this->view->currentGroup));
		                                                         
		//TODO: make rather call viewcontactsAction
		$this->view->contactsC = count($contactsAll);
		$this->view->contacts = array_slice($contactsAll, 0, 100);
		$this->view->pageVolume = 100;
		$this->view->pageNumber = 1;

		// sanitize database data
		for($a=0;$a<count($this->view->contacts);$a++)
		{
				$this->filter->setData($this->view->contacts[$a]);
				$this->view->contacts[$a] = $this->filter->getEscapedData();
		}
		
		for($a=0;$a<count($this->view->groups);$a++)
		{
			$this->filter->setData($this->view->groups[$a]);
			$this->view->groups[$a] = $this->filter->getEscapedData();        
		}


		$temp_groups = $this->view->groups;
		
		$this->view->groups = array();
		$this->view->contactTotals = array();

		foreach( $temp_groups as &$group )
		{

			if( $this->view->group['Carddav'] != '1' && isset($group['server']) )
				continue;
			
			if(isset($group['server']))
			{
				if( $group['protocol'] == SYNCML_MODE )
					$group['GroupName'] = $group['GroupName'] . " (SyncML)";
				elseif( $group['protocol'] == LDAP_MODE )
					$group['GroupName'] = $group['GroupName'] . " (LDAP)";
				else
					$group['GroupName'] = $group['GroupName'] . " (CardDav)";
			}
			
			if(isset($group['server']))
				$count = 0;
			else
				$count = $this->_contacts->getGroupCount($group['id']);
			
			if($count < 0)
				$count = 0;
            $this->view->contactTotals[$group['id']] = $count;

			// TODO: Find a more elegant solution
			$group['GroupID'] = ($group['GroupName'] == 'All'?'all':'group');
			$this->view->groups[] = $group;
			
		}
        $this->view->contactTotals['All'] = $this->view->contactsC;
		$this->view->contact = $this->view->contacts[0];
		$requestParams = $this->getRequest()->getParams();
		if( isset($requestParams['addNewContact']) && $requestParams['addNewContact'] == 'true' )
			$this->view->addNewContact = true;
		else
			$this->view->addNewContact = false;

	}
	
	public function pushrefreshcontactsserverslistAction()
	{
		
		//grep same data as index
		$this->indexAction();    
		$this->view->jsonIdsToRender = array();
		$this->view->jsonIdsToRender['Address_Book #secondary'] = 'contacts/listgroups.phtml';
		$this->render('global/jsonresponse', null, true);
		
	}
	
	
	public function addtoaddressbookAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
		$mimeAddressesDecoded = htmlspecialchars_decode( $requestParams['mimeAddresses'] );
		$uniqueAddresses = messageHandling::getUniqueAddresses( $mimeAddressesDecoded );
		$addressObjectsArray = getProcessedRecipientObjects( $uniqueAddresses );
		$responseString = $this->view->translate('Results of adding to Addressbook:') . ' ';
		                                                          
		foreach( $addressObjectsArray as $addressObject )
		{
			
			//skip self
			if( $addressObject->address == $this->userData['Account'] )
			{
				
				continue;
				
			}
			$newContact = array();
			//now try split personal into firstName lastName (company)
			$parts = explode(' ', $addressObject->personalUTF8, 2);
			$restOfPersonal = '';
			$firstPart = $parts[0];
			if( isset($parts[1]) )
			{
				
				$restOfPersonal = $parts[1];
				
			}
			
			if( ($companyOBPos = mb_strpos($restOfPersonal, '(', 0, 'UTF-8')) !== false && ($companyCBPos = mb_strpos($restOfPersonal, ')', $companyOBPos, 'UTF-8')) !== false )
			{
				
				//found brackets so assume company delimiters
				$companyName = mb_substr( $restOfPersonal, $companyOBPos+1, $companyCBPos-$companyOBPos-1 );
				$restOfPersonal = trim( mb_ereg_replace( '\(' . $companyName . '\)', '', $restOfPersonal) );
				$newContact['UserWorkCompany'] = $companyName;
				
			}
			
			//if we find a comma then lastname first
			if( mb_strpos( $addressObject->personalUTF8, ',', 0, 'UTF-8') !== false )
			{
			
				$newContact['UserFirstName'] = $restOfPersonal;
				$newContact['UserLastName'] = trim($firstPart,' ,');
			
			}
			else
			{
				
				$newContact['UserFirstName'] = $firstPart;
				$newContact['UserLastName'] = $restOfPersonal;
			
			}
			$newContact['UserEmail'] = $addressObject->address;
			
			//if no first or last name then place first part of email in first
			if( mb_strlen($newContact['UserFirstName']) == 0 && mb_strlen($newContact['UserLastName']) == 0 )
			{
				
				$newContact['UserFirstName'] = $addressObject->mailbox;
				
			}                                                 
			
			//check if contact exists for this user, if not add
			//search for matching first and last name
			$searchResult = $this->_contacts->searchContact( array('UserFirstName' => $newContact['UserFirstName'], 'UserLastName' => $newContact['UserLastName']) );
			if( $searchResult != 0 )
			{
				
				$responseString .= trim($newContact['UserFirstName'] . ' ' . $newContact['UserLastName']) . ' ' . $this->view->translate('(already in Addressbook)');
				
			}
			else
			{
				
				//search for matching email address
				$searchResult = $this->_contacts->searchContact( array('UserEmail' => $newContact['UserEmail']) );
				if( $searchResult != 0 )
				{
					
					$responseString .= trim($newContact['UserEmail']) . ' ' . $this->view->translate('(already in Addressbook)');
					
				}
				else
				{
					
					$resultId = $this->_contacts->addContact( $newContact );
					if( $addressObject->personalUTF8 == '' )
					{
						
						$responseString .= $addressObject->address;
						
					}
					else
					{
						
						$responseString .= $addressObject->personalUTF8;
						
					}
					$responseString .= ' ' . $this->view->translate('(added)');
					
				}
				
			}
			$responseString .= ', ';
			
		}
		if( mb_substr( $responseString, -2) == ', ' )
		{
			
			$responseString = mb_substr( $responseString, 0, -2 );
			
		}

		jQuery::addMessage( $responseString );
		$this->render('global/jsonresponse', null, true);
		
	}
	
	private function syncContacts()
	{
		
		if( isset($this->session->lastHit) && (time()-$this->session->lastHit < 5) )
			return;
		$syncMLEnabled = false;
		if( !$syncMLEnabled )
			return;
		
		//for now manual trigers, but could automate like plugins (find all transparent active sync accounts and sync in full circle)
		//CONSIDER: latency might dictate that this be done behind the scenes so UI more responsive
		//for now, find first syncML account and ise for transparent sync and hide from showing as a virtual folder
		$syncMLAccountSameAsEmail = true;
		if( $syncMLAccountSameAsEmail ) 
		{
			
			$firstSyncMLAccount = $serverInfo = array(
				'server' => 'localhost', 'protocol' => 'syncml', 'port' => '6060', 'url' => '/nab/sync', 
				'username' => $this->userData['Account'], 'password' => $this->userData['password']
			);
			$serverInfo = $firstSyncMLAccount;
			
		}
		else
		{
			$firstSyncMLAccount = false;
			$serversObject = new Atmail_Abook_Servers( array('Account' => $this->view->Account) );

			$serversInfo = $serversObject->GetServers( $this->view->Account );
			foreach( $serversInfo as $serverInfo)
			{
				if( array_key_exists('protocol', $serverInfo) && $serverInfo['protocol'] == 'syncml' )
				{
					$firstSyncMLAccount = $serverInfo;
					break;
				}
			}
		}
		
		if( $firstSyncMLAccount !== false )
		{
			
			$url = 'http://' . $firstSyncMLAccount['server'] . ($firstSyncMLAccount['port']!='80'?':'.$firstSyncMLAccount['port']:'') . $firstSyncMLAccount['url'];
			try 
			{
				
				$loginArray = array('url' => $url, 'username' => $serverInfo['username'], 'password' => $serverInfo['password'], 'localUsername' => $this->view->Account);
				$syncMLClient = new Atmail_SyncML_SyncMLClient( $loginArray );
				$success = $syncMLClient->sync();
				if( !$success )
				{
					$this->view->error = $syncMLClient->result['message'];
					Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": Sync Failed: " . $this->view->error );
				}
				else
					$this->view->notice = "Contacts updated from SyncML source successfully";
				
			} 
			catch( Exception $e )
			{
				
				$success = false;
				$this->view->error = $this->view->translate('Unable to synchronize with Addressbook');
				Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": Sync Failed: " . $e->getMessage() );
				
			}

		}                                
		//set timer so SyncML server does not get hit more than every x second
		$this->session->lastHit = time();

	}

	public function viewcontactsAction()
	{
		
		//hook to trigger SyncML and other transparent syncronisation service
		$this->syncContacts();
		$requestParams = $this->getRequest()->getParams();
		$this->view->pageVolume = 100;
		$page = isset($requestParams['page'])?$requestParams['page']:1;
		$this->view->pageNumber = $page;
		
		$contactsAll = $this->_contacts->getContacts($requestParams);
		$this->view->contactsC = count($contactsAll);
		$offset = ($page - 1) * $this->view->pageVolume;
		$this->view->contacts = array_slice($contactsAll, $offset, $this->view->pageVolume);
		$this->view->groupID = $requestParams['GroupID'];
        
		// sanitize database data
		for($a=0;$a<count($this->view->contacts);$a++)
		{
			$this->filter->setData($this->view->contacts[$a]);
			$this->view->contacts[$a] = $this->filter->getEscapedData();
		}

		$this->view->contact = isset($this->view->contacts[0])?$this->view->contacts[0]:null;

		if( is_array($this->view->contact) )
		{
			$this->view->contact['id'] = $this->view->contact['contactId'];
		}
		
		if( $this->isAjax )
		{
			jQuery('#address_contacts')->scrollTop(0);
			$this->view->jsonIdsToRender['address_contacts'] = 'contacts/listcontacts.phtml';
			$this->view->jsonIdsToRender['contact_info'] = 'contacts/viewcontact.phtml';
			$this->render('global/jsonresponse', null, true);
		}
		else
		{
			$this->render('listcontacts');
		}
	}

	public function viewcontactAction()
	{
		
		$this->view->ucsettings = users::getUCPlusSettings();
		$requestParams = $this->getRequest()->getParams();
		if(!isset($requestParams['GroupID']))
			$requestParams['GroupID'] = '';
		
		$contact = $this->_contacts->getContact($requestParams['id'], $requestParams['GroupID']);
		if( $contact == NULL )
			$contact = array();	
		// sanitize database data
		$this->filter->setData($contact);
		$this->view->contact = $this->filter->getEscapedData();

		$this->view->contact['UserDOB'] = str_replace('0000-00-00', '', $this->view->contact['UserDOB']);
		$this->view->contact['UserDOB'] = str_replace("00:00:00", '', $this->view->contact['UserDOB']);
		if($this->view->contact['UserDOB'] == ' ')
			$this->view->contact['UserDOB'] = '';

		$this->view->GroupID = $requestParams['GroupID'];

        $this->_helper->pluginCall("preRenderContactView");
        
		if( $this->isAjax ) 
		{ 

			$this->view->jsonIdsToRender['contact_info'] = 'contacts/viewcontact.phtml';
			$this->render('global/jsonresponse', null, true);

		}
		else
			$this->render('viewcontact');

	}

	public function creategroupAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
		
		try
		{
			$id = $this->_contacts->createGroup($requestParams);
		}
		catch (Exception $e)
		{
			jQuery::addError( $this->view->translate('Group with same name already exists') );
		}
		
		if( !empty($id) ) 
		{

			// Append the new GroupID to the element, supporting groups with the same name
			jQuery('li[newgroup="true"]')->attr('groupname', $requestParams['newGroupName'] );
			jQuery('li[newgroup="true"]')->attr('groupid', $id );
			jQuery('li[newgroup="true"] a span span')->html($requestParams['newGroupName']);
			jQuery('li[newgroup="true"]')->removeAttr('newgroup');
			
		}
		else
		{
			jQuery('li[newgroup="true"]')->remove();
		}
		
		$this->render('global/jsonresponse', null, true);
		
	}

	public function addcontacttogroupAction()
	{
		$requestParams = $this->getRequest()->getParams();
		$status = 1;

		if(!is_array($requestParams['id']))
		{
			$requestParams['id'] = array($requestParams['id']);
		}
		
		if($requestParams['GroupID'] < 0 && ($requestParams['GroupID'] != GROUP_SHARED && $requestParams['GroupID'] != GROUP_FAV)) 
		{
	
			jQuery::addError($this->view->translate('You are not allow to drop contacts to that folder.'));
			$this->render('global/jsonresponse', null, true); 
			return;	
		}

		foreach($requestParams['id'] as $id)
		{
			if($requestParams['GroupID'] == GROUP_SHARED)
			{
				//shared contact, update
				$this->_contacts->updateContact(array('Shared' => 1, 'id' => $id));
			}
			else if ($requestParams['GroupID'] == GROUP_FAV)
			{
				// 'add' the contact to the favourite group by flagging it as such
				$this->_contacts->updateContact(array('Favourite' => 1, 'id' => $id));
				jQuery('.address_row[contactid=' . $id . '] div.contact-fav')->show();
			}
			else
			{
				$groupIDs = $this->_contacts->getGroupIdsFromAbookId(array('id' => $id));

				$found = false;
				foreach($groupIDs as $groupID)
				{
					if($groupID['GroupID'] == GROUP_AUTO)
					{
						$found = true;
						break;
					}
				}
				
				if($found)
				{
					// remove the contact from the auto group
					$response = $this->_contacts->deleteContactGroup(array('id' => $id, 'GroupID' => GROUP_AUTO));
					jQuery('.address_row[contactid=' . $id . ']')->remove();
					// Update live the "count" for the message view
					jQuery('li[GroupID=' . GROUP_ALL . '] .unread strong')->updateCount( '1' );
					jQuery('li[GroupID=' . GROUP_AUTO . '] .unread strong')->updateCount( '-1' );
					
				}
				$status = $this->_contacts->addContactToGroup(array('GroupID' => $requestParams['GroupID'], 'id' => $id));
				$this->_contacts->updateContact(array('Shared' => 0, 'id' => $id));
			}
		}

		// If the contact was successfully added ( Without a duplicate, update the count )
		if($status == 1)
		{
			jQuery('li[groupid=' . $requestParams['GroupID'] . '] .unread strong')->updateCount( count($requestParams['id']) );
			jQuery::evalScript("$.jCacher.remove('autocomplete'); $.jCacher.remove('autocomplete_global');");
		}

		$this->render('global/jsonresponse', null, true); 
	}

	public function updategroupnameAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
		if( !isset($requestParams['newGroupName']) )
		{
			
			//sometimes browser will not post the newGroupName var because chars not valid etc.
			$response = 0;
			
		}   
		else
		{
		
			$response = $this->_contacts->updateGroupName($requestParams);
			
		}
		$processedName = $this->_contacts->getGroupNameFromId( $requestParams['GroupID'] );
		
		if( strlen($response) > 0 && ( $response != 1 || $response != true ) ) 
		{ //if failed
		    
			if( $response == 0 )
			{
				jQuery::addError( $this->view->translate('Group name not changed') );
				
			}
			else
			{
				
				jQuery::addError( $this->view->translate('Unable to save change to group name') );
				
			}
		
		}
		else
		{

			//push groupname as it was stored
			jQuery('li[groupid=' . $requestParams['GroupID'] . '] a span span.labelname')->text( $processedName ); 
			jQuery('li[groupid=' . $requestParams['GroupID'] . ']')->attr( 'groupname', $processedName ); 
			jQuery::evalScript("$.jCacher.remove('autocomplete'); $.jCacher.remove('autocomplete_global');");
			
		}
		
		$this->render('global/jsonresponse', null, true);
	}

	public function deletegroupAction()
	{
		$requestParams = $this->getRequest()->getParams();
		$response = $this->_contacts->deleteGroup($requestParams);
		jQuery('li[GroupID=' . $requestParams['GroupID'] . ']')->remove('');
		jQuery::evalScript("listContactsClick($('#Address_Book ul#nav_secondary li:first a')); $.jCacher.remove('autocomplete'); $.jCacher.remove('autocomplete_global');resetMyGroupButtons();");
		
		$this->render('global/jsonresponse', null, true);
	}

	public function deletecontactAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
        	if( !is_array($requestParams['id']) )
		{

			$requestParams['id'] = array($requestParams['id']);

		}
		
		$GroupID = '';
		if(isset($requestParams['GroupID']))
			$GroupID = $requestParams['GroupID'];
			
		$actually_removed = 0;
		$global_contacts_rejected = '';

		// Loop for each element selected to delete
		foreach($requestParams['id'] as $id) 
		{
			$contact = $this->_contacts->getContact(array('id' => $id));
		 	$groups = $this->_contacts->getGroupIdsFromAbookId($id);
		
			if($contact['Global'] == 1)
			{
				$details = 'Unknown';
				
				if(isset($contact['UserEmail']) && $contact['UserEmail'] != '')
				{
					$details = $contact['UserEmail'];
				}
				else if(isset($contact['UserEmail2']) && $contact['UserEmail2'] != '')
				{
					$details = $contact['UserEmail2'];
				}
				else if(isset($contact['UserEmail3']) && $contact['UserEmail3'] != '')
				{
					$details = $contact['UserEmail3'];
				}
				else if(isset($contact['UserEmail4']) && $contact['UserEmail4'] != '')
				{
					$details = $contact['UserEmail4'];
				}
				else if(isset($contact['UserEmail5']) && $contact['UserEmail5'] != '')
				{
					$details = $contact['UserEmail5'];
				}

				if($global_contacts_rejected == '')
				{
					$global_contacts_rejected .= $details;
					$global_messsage = $this->view->translate('was not deleted as it is a global contact.');
				}
				else
				{
					$global_contacts_rejected .= ", " . $details;
					$global_messsage = $this->view->translate('were not deleted as they are global contacts.');
				}
			}
			else
			{
				// update the group count for each group this items belongs too, apart from the current groupid

				foreach($groups as $group)
				{
					if($group['GroupID'] != $requestParams['GroupID'])
					{
						// Update live the "count" for the message view
						jQuery('li[groupid=' . $group['GroupID'] . '] .unread strong')->updateCount( '-1' );
					}
				}
				$response = $this->_contacts->deleteContact(array('id' => $id, 'GroupID' => $GroupID));
				jQuery('.address_row[contactid=' . $id . ']')->remove();
				$actually_removed ++;
			}
		}
		
		if($global_contacts_rejected != '')
		{
			jQuery::addMessage($global_contacts_rejected . ' ' . $global_messsage);
		}

		// Update live the "count" for the message view
		jQuery('li[groupid=' . $requestParams['GroupID'] . '] .unread strong')->updateCount( '-' . $actually_removed );
        
		jQuery::evalScript("$.jCacher.remove('autocomplete'); $.jCacher.remove('autocomplete_global');");

		//Call sync Contacts hook
		$this->syncContacts();

		$this->render('global/jsonresponse', null, true);
	
	}

	public function deletecontactgroupAction()
	{
		$requestParams = $this->getRequest()->getParams();
		// Loop for each element selected to delete

		if (!is_array($requestParams['id'])) {
			$requestParams['id'] = array($requestParams['id']);
		}

		foreach($requestParams['id'] as $id) {	 	
			$response = $this->_contacts->deleteContactGroup(array('id' => $id, 'GroupID' => $requestParams['GroupID']));
			jQuery('.address_row[contactid=' . $id . ']')->remove();
		}

		// Update live the "count" for the message view
		jQuery('li[GroupID=' . $requestParams['GroupID'] . '] .unread strong')->updateCount( '-' . count($requestParams['id']) );
		jQuery::evalScript("$.jCacher.remove('autocomplete'); $.jCacher.remove('autocomplete_global');");

		$this->render('global/jsonresponse', null, true);
	}

	public function editcontactAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
		$this->view->edit = true;
		if(empty($requestParams['id']))
		{
			$requestParams['id'] = 'new' . rand(1, 1000000);
			$contact = array();
			$contact['id'] = $requestParams['id'];
		}
		else
		{
			$contact = $this->_contacts->getContact($requestParams['id'], $requestParams['GroupID']);
		}
		$this->view->editingOwnProfile = ($contact['Global']=='1' && $contact['Account'] == $this->view->Account);
		$userDataComplete = users::getAllUserData( $this->view->Account );
		$this->view->GroupwareZone = $userDataComplete['Groups']['GroupwareZone'];
		$this->view->SharedAbook = $userDataComplete['Groups']['SharedAbook'];
		
		// sanitize database data
		$this->filter->setData($contact);
		$this->view->contact = $this->filter->getEscapedData();
        
		$this->view->contact['NewContact'] = 0;

		$this->view->contact['UserDOB'] = str_replace('0000-00-00', '', $this->view->contact['UserDOB']);
		$this->view->contact['UserDOB'] = str_replace("00:00:00", '', $this->view->contact['UserDOB']);
		if($this->view->contact['UserDOB'] == ' ')
			$this->view->contact['UserDOB'] = '';
		
		// Decide if to expand the 'more' options div
		foreach(array('UserWorkCompany', 'UserTitle', 'UserDOB', 'UserURL', 'UserWorkTitle', 'UserWorkDept', 'UserInfo') as $field) 
		{
		
			if(!empty($this->view->contact[$field]))
				$this->view->contact['ExpandMoreOptions'] = 1;
		
		}

		if(!empty($this->view->contact['Shared']))
			$this->view->contact['ExpandSharedOptions'] = 1;
			
		if(!isset($this->view->contact['Permissions']))
			$this->view->contact['Permissions'] = '';
		else
		{
			
			//cleanup Permissions, removing self 
			$Permissions = explode(',', $this->view->contact['Permissions']);
			if( count($Permissions) == 0)
				$this->view->contact['Shared'] = '0';
			foreach($Permissions as $k => $Permission)
				if($Permission == $this->view->Account)
					unset($Permissions[$k]);
			$this->view->contact['Permissions'] = implode(', ', $Permissions);
			
		}
		
		if( $this->isAjax ) 
		{ 
		
			$this->view->jsonIdsToRender['contact_info'] = 'contacts/editcontact.phtml';
			$this->render('global/jsonresponse', null, true);																								 
		} 
		else
			$this->render('editcontact');

	}

	// Load the contact creation page, using the existing editcontact for code re-use
	public function newcontactAction()
	{
		
		$requestParams = $this->getRequest()->getParams();

		$this->view->edit = true;
		if(!empty($requestParams['ui']))
		{	
			$this->view->edit = true;
			$this->view->contact = array();
			$this->view->contact['NewContact'] = 1;

			if(!empty($requestParams['GroupID']))
				$this->view->GroupID = $requestParams['GroupID'];

			if( $this->isAjax ) 
			{ 
				$this->view->jsonIdsToRender['contact_info'] = 'contacts/editcontact.phtml';
					$this->render('global/jsonresponse', null, true);																								 
		
			}
			else
			{
		
				$this->render('editcontact');
		
			}
		}
		else
		{
			$id = $this->_contacts->addContact($requestParams);

			if( !empty($requestParams['GroupID']) && strpos($requestParams['GroupID'], ABOOK_SERVER_GROUP_TAG) == -1 )
			{
		
				$status = $this->_contacts->addContactToGroup(array('GroupID' => $requestParams['GroupID'], 'id' => $id));

				// If the contact was successfully added ( Without a duplicate, update the count )
				if($status == 1)
				{
				
					jQuery('li[groupid=' . $requestParams['GroupID'] . '] .unread strong')->updateCount( 1 );
				
				}
		
			}
		
			if( !empty($requestParams['GroupID']) && strpos($requestParams['GroupID'], ABOOK_SERVER_GROUP_TAG) != -1)
			{
				$this->view->contact = $this->_contacts->getContact($id, $requestParams['GroupID']);
			}
			else
			{
				$this->view->contact = $this->_contacts->getContact($id);			
			}
		
			// sanitize database data
			if($this->view->contact)
			$this->filter->setData($this->view->contact);

			$this->view->contact = $this->filter->getEscapedData();

			$this->view->contact['NewContact'] = 1;

			if( $this->isAjax ) 
			{ 
		
				$this->view->jsonIdsToRender['contact_info'] = 'contacts/editcontact.phtml';
					$this->render('global/jsonresponse', null, true);																								 
		
			}
			else
			{
		
				$this->render('editcontact');
		
			}
		}
	}

	// Create a new contact into the DB, return the ID, and reload the view with the specified ID
	public function addcontactAction()
	{
		$requestParams = $this->getRequest()->getParams();

		$id = $this->_contacts->addContact($requestParams);

		$this->view->contacts = $this->_contacts->getContacts();
		$this->view->contact = $this->_contacts->getContact($id);

		// sanitize database data
		$this->filter->setData($this->view->contact);
		$this->view->contact = $this->filter->getEscapedData();
		for($a=0;$a<count($this->view->contacts);$a++)
		{
				$this->filter->setData($this->view->contacts[$a]);
				$this->view->contacts[$a] = $this->filter->getEscapedData();
		}

		//syncContacts hook
		$this->syncContacts();
		
		if( $this->isAjax ) 
		{ 

			jQuery('#listcontacts')->remove();

			$this->view->jsonIdsToRender['address_contacts'] = 'contacts/listcontacts.phtml';
			$this->view->jsonIdsToRender['contact_info'] = 'contacts/viewcontact.phtml';

			jQuery('li[GroupName=All] .unread strong')->updateCount( 1 );

			$this->render('global/jsonresponse', null, true);
		}
		else
		{
		
			$this->render('viewcontact');
		
		}

	}

	public function addphotoAction()
	{
		$result = 'success';
		$this->_helper->viewRenderer->setNoRender();
		$requestParams = $this->getRequest()->getParams();
		if(!isset($_FILES['UserPhoto']) || (isset($_FILES['UserPhoto']) && ($_FILES['UserPhoto']['error'] != UPLOAD_ERR_OK || $_FILES['UserPhoto']['size'] <= 0)))
		{
			return;
		}
		$retries = 0;
		$filename = '';
		while(is_file($filename) || $filename == '' && $retries++ < 3)
		{
	        $filename = users::getTmpFolder() . uniqid() . '.' . Thumbnail::findFormat($_FILES['UserPhoto']['name']);
		}

		if( !move_uploaded_file($_FILES['UserPhoto']['tmp_name'], $filename))
		{
			file_put_contents("php://stderr", "Unable to move user uploaded file.\nTEMPNAME = " . $_FILES['UserPhoto']['tmp_name'] . " moving to " . $filename . "\n");
			return;
		}

		$this->_createThumbnail($filename , $filename, 110, 110);

		$UserPhotoBase64 = base64_encode(file_get_contents($filename));
		//unlink($filename);
		//TODO: refactor workaround where adding photo dependant on GroupID (UI limits access to change photo)
		if( !empty($requestParams['GroupID']) && strpos($requestParams['GroupID'], ABOOK_SERVER_GROUP_TAG) == -1 )
			$requestParams['GroupID'] = 1;
		
		if(empty($requestParams['id']))
		{
			$result = $requestParams['id'] = $this->_contacts->addContact(array());
			$result = 'id=' . $result;
		}
		$data = array('id' => $requestParams['id'], 'GroupID' => $requestParams['GroupID'], 'UserPhoto' => $UserPhotoBase64);
        
		$this->_contacts->uploadUserPhoto($data);
		//sync contacts hook
		$this->syncContacts();
		
		echo $result;
		
	}

	public function viewphotoAction()
	{

		$requestParams = $this->getRequest()->getParams();

		if(array_key_exists('logo', $requestParams) && $requestParams['logo']) {
            $requestParams['logo'] = makeFSSafe($requestParams['logo']);
			$photoContent = file_get_contents(APP_ROOT . "images/mobile/logo/" . $requestParams['logo']);
		}
		else {
			if($requestParams['id'] == -1000) {
				$requestParams['id'] = $this->_contacts->getProfileAbookId();
			}
			
			$photoContent = $this->_contacts->viewUserPhoto($requestParams);
			$abookId = $requestParams['id'];			
		}

		//if no photo then show default
		if( $photoContent == false )
		{
			
			//if no photo then serve default
			if( array_key_exists('mobile', $requestParams) && $requestParams['mobile'] )
			{
				$photoContent = file_get_contents(APP_ROOT . "images/mobile/contact-photo-profile.png");
			}
			else
			{
                $this->view->UserSettings['cssStyleTheme'] = makeFSSafe($this->view->UserSettings['cssStyleTheme']);
				$photoContent = file_get_contents(APP_ROOT . "images/themes/" . $this->view->UserSettings['cssStyleTheme'] . "/contact-photo.png");
			}
			$this->getResponse()
				 ->setHeader('Content-Type','image/png') 
				 ->appendBody($photoContent);
			$this->_helper->viewRenderer->setNoRender();
			return;
		}
		
		// Resize an image (for the autocomplete)
		if(isset($requestParams['resize']) && $requestParams['resize'])
		{
			$photoContent = users::getPhotoResize($photoContent);
        }

		// Create the shadow effect on the image
		if (isset($requestParams['shadow']))
		{
			$photoContent = users::getPhotoShadow($photoContent);
		}

		// TODO: Convert all images to jpeg
		$this->getResponse()
			 ->setHeader('Content-Type','image/jpeg') 
			 ->appendBody($photoContent);
		$this->_helper->viewRenderer->setNoRender(); 
	 
	}

	private function _createThumbnail($sourcePath, $destPath, $w, $h, $q = 100) 
	{

		$thumb = new Thumbnail($sourcePath);
		if($thumb && $thumb->init_success)
		{
			$thumb->cropAspectAndResizeAvatar($w, $h);
			$thumb->save($destPath, $q);
		}
	}

	public function updatecontactAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
		$contact = array();
		$was_errors = false;
        $newContact = isset($requestParams['contact']['NewContact'])&&$requestParams['contact']['NewContact']=='1';
		
        //contact number fields		   
		$contactNumberFields = array('UserHomePhone', 'UserHomeMobile', 'UserHomeFax','UserWorkPhone', 'UserWorkMobile', 'UserWorkFax');
		$contactNumberFieldNameC = (isset($requestParams['contact']['numberFieldName']) ? count( $requestParams['contact']['numberFieldName'] ) : 0);

		//create zeroed fields forst so that deleted fields do actually get zeroed on the db
		foreach( $contactNumberFields as $k) 
		{
			$contact[$k] = '';
		}
		
		for( $a = 0 ; $a < $contactNumberFieldNameC ; $a++ ) 
		{
			if( strlen($requestParams['contact']['numberValue'][$a]) > 0 )
			{
				$contact[$requestParams['contact']['numberFieldName'][$a]] = $requestParams['contact']['numberValue'][$a];
			}		
		}

		// Process the email addresses
		foreach( array( 'UserEmail', 'UserEmail2', 'UserEmail3', 'UserEmail4', 'UserEmail5') as $emailField)	
		{
			//CONSIDER: Revise form because selecting email # is irrelevant, should just be sequential, no dropdown to select email # order
			//for now, process accordingly
			$foundEmailNameInParams = false;
			if( isset($requestParams['contact']["emailFieldName"]) )
			{
				foreach( $requestParams['contact']["emailFieldName"] as $k => $paramEmailName )
				{
					if( $paramEmailName == $emailField )    
					{
						$foundEmailNameInParams = true;
						break;
					}
				
				}
			}                              
			if( $foundEmailNameInParams )
			{
			    $contact[$emailField] = $requestParams['contact']["emailValue"][$k];
			}
			else
			{
				$contact[$emailField] = '';
			}
		}

		// Load the Home/Work address and other misc fields
		foreach( array( 'UserFirstName', 'UserLastName', 'UserMiddleName', 'UserHomeAddress', 'UserHomeCity', 'UserHomeState', 'UserHomeZip', 'UserHomeCountry', 'UserWorkAddress', 'UserWorkCity', 'UserWorkState', 'UserWorkZip', 'UserWorkCountry', 'UserInfo', 'UserTitle', 'UserGender', 'UserDOB', 'UserURL', 'UserWorkCompany', 'UserWorkTitle', 'UserWorkDept', 'SIP') as $addressField )
		{
			if(!isset($requestParams['contact'][$addressField]))
			{
				$requestParams['contact'][$addressField] = '';
			}
			$contact[$addressField] = $requestParams['contact'][$addressField];
		}

		// Avoid specifying the DOB of 0000-00-00 in the DB
		if( $contact['UserDOB'] == '0000-00-00' || empty($contact['UserDOB']) )
		{
			$contact['UserDOB'] = null;
		}
		
		// verify the email addresses
		require_once('Mail/RFC822.php');
		$mail_rfc822 = new Mail_RFC822;
	 	
		// TODO: Decide if the account has permissions to add shared contacts
		foreach(array('Shared', 'Permissions') as $addressField) 
		{
			// if(account has shared permissions)
			// foreach @permissions, check the array is the users local domain or site wide permissions
			if(!isset($requestParams['contact'][$addressField]))
			{
				$requestParams['contact'][$addressField] = '';
			}
			
			$was_errors = false;
			$contact[$addressField] = '';

			try
			{
				$rcpt = $mail_rfc822->parseAddressList($requestParams['contact'][$addressField], null, false);
				$moreThenOne = false;
				foreach($rcpt as $permissionAddress)
				{
					if($rcpt instanceof PEAR_Error || $permissionAddress instanceof PEAR_Error)
					{
						$was_errors = true;
					}
					
					if($permissionAddress->host == '' || $permissionAddress->host == 'localhost')
					{
						continue;
					}
					
					if(!$was_errors)
					{
						$contact[$addressField] .= ($moreThenOne ? ', ' : '') . $permissionAddress->mailbox . '@' . $permissionAddress->host;
						$moreThenOne = true;
					}
				}
			}
			catch(Exception $e)
			{
				$was_errors = true;
			}
		}

		if( $requestParams['contact']['Shared'] == 1 || $requestParams['contact']['Shared'] == true )
		{
			$contact['Shared'] = 1;
		}
		else
		{
			$contact['Shared'] = 0;
		}
			
		$contact['id'] = $requestParams['contact']['id'];
	 
	 	// verify the email addresses
		$a=0;
		foreach(array( 'UserEmail', 'UserEmail2', 'UserEmail3', 'UserEmail4', 'UserEmail5') as $emailField)	
		{
			if(!isset($requestParams['contact']["emailValue"][$a]))
			{
				$requestParams['contact']["emailValue"][$a] = '';
			}
			
			if($requestParams['contact']["emailValue"][$a] != '')
			{
				try
				{
					$rcpt = $mail_rfc822->parseAddressList($requestParams['contact']["emailValue"][$a], null, false);
					if($rcpt instanceof PEAR_Error || $rcpt[0] instanceof PEAR_Error)
					{
						$was_errors = true;
						continue;
			        }
			
					if($rcpt[0]->host == '' || $rcpt[0]->host == 'localhost')
					{
						continue;
					}
				}
				catch(Exception $e)
				{
					$was_errors = true;
					continue;
				}
			}
			$a++;
		}

		if($was_errors)
		{
			jQuery::addError( $this->view->translate('The email address(es) provided appears to be invalid.') );
			jQuery::evalScript("$('.contact_field_value input:text:eq(" . $a . ")').select().focus()");
		}

		if(isset($requestParams['contact']['serverID']) && !empty($requestParams['contact']['serverID']))
		{
			$contact['serverID'] = $requestParams['contact']['serverID'];
		}
		
		if( !$was_errors )
		{
			$this->filter->setData($contact);
			$contact = $this->filter->getEscapedData();
			//if all empty then abort (no point in saving an empty contact)
			$allEmpty = true;
			
			foreach( $contact as $k => $v )
			{
				//ignore certain field content
				if( in_array($k, array('id')) )
				{
					continue;
				}
				
				if( !empty($v) )
				{
					$allEmpty = false;
					break;
				}
			}
			if( $allEmpty )
			{
				jQuery::addError( $this->view->translate('Please enter information for the new contact.') );
				$was_errors = true;
			}
		}
	 	if(!$was_errors)
	 	{
			if( empty($contact['id']) )
			{
				
				unset($contact['NewContact']);
                $requestParams['contact']['id'] = $contact['id'] = $this->_contacts->addContact($contact);
				
				if( isset($requestParams['contact']['GroupID']) && $requestParams['contact']['GroupID'] != '' && strpos($requestParams['contact']['GroupID'], ABOOK_SERVER_GROUP_TAG) == false )
				{
					$status = $this->_contacts->addContactToGroup(array('GroupID' => $requestParams['contact']['GroupID'], 'id' => $requestParams['contact']['id']));
					// If the contact was successfully added ( Without a duplicate, update the count )
					if($status == 1)
					{
						jQuery('li[groupid=' . $requestParams['contact']['GroupID'] . '] .unread strong')->updateCount( 1 );
					}
				}
				jQuery('#Address_Book li[GroupID=0] .unread strong')->updateCount( 1 );
				$this->_contacts->updateContact($contact);
				//below checks this to decide if to add new contact row/reload list/update existing row item
			}
			else
			{
				$this->_contacts->updateContact($contact);
			}

			// the id could exist anywhere, either personal or global group
			// so lets try catch here
			if( isset($contact['serverID']) && !empty($contact['serverID']) ) // this contact is from a server
			{
				$this->view->contact = $this->_contacts->getContact($requestParams['contact']['id'], $requestParams['contact']['serverID']);
			}
			else
			{
				try 
				{
					$this->view->contact = $this->_contacts->getContact($requestParams['contact']['id'], '-2');
					if( !is_array($this->view->contact) || count($this->view->contact) == 0 )
					{
						$this->view->contact = $this->_contacts->getContact($requestParams['contact']['id']);
					}
				}
				catch( Exception $e )
				{
					$this->view->contact = $this->_contacts->getContact($requestParams['contact']['id']);
				}
			}
			
			//if photo available then change picture
			if( empty($this->view->contact['UserPhoto']) )
			{
				$pictureUrl = $this->view->siteBaseUrl . "images/themes/" . $this->view->UserSettings['cssStyleTheme'] . "/contact-photo-small.png";
			}
			else
			{
				$pictureUrl = $this->view->moduleBaseUrl . "/contacts/viewphoto/id/" . $this->view->contact['id'] . "/resize/1/" . rand();
			}
			
			if( $newContact )
			{
				jQuery::evalScript("newContact(true, false, " . $contact['id'] . ", '" . addslashes($contact['UserFirstName']) . "', '" . addslashes($contact['UserLastName']) . "', '". addslashes($contact['UserEmail']) . "', '" . $pictureUrl . "', " . (isset($requestParams['contact']['favourite']) && $requestParams['contact']['favourite'] ? 1:0) . ");");
			}
			
			if(isset($requestParams['contact']['favourite']) && $requestParams['contact']['favourite'])
			{
				$this->_contacts->updateContact(array('id' => $contact['id'], 'Favourite' => 1));				
			}	

            if($this->view->contact != null)
            {
                // sanitize data
                $this->filter->setData($this->view->contact);
                $this->view->contact = $this->filter->getEscapedData();

                //syncContacts hook
                $this->syncContacts();
            }
		}

		if( $this->isAjax ) 
		{ 
			if(!$was_errors)
			{
				if( !isset($contact['NewContact']) || $contact['NewContact'] == '0' )
				{
					// Live update the users firstname/lastname
					$firstname = $contact['UserFirstName'];
					$lastname = $contact['UserLastName'];
					if($firstname == "" && $lastname == "") 
					{
						if($contact['UserEmail'] != "")
						{
							$firstname = $contact['UserEmail'];
						}
						else if($contact['UserEmail2'] != "")
						{
							$firstname = $contact['UserEmail2'];
						}
						else if($contact['UserEmail3'] != "")
						{
							$firstname = $contact['UserEmail3'];
						}
						else if($contact['UserEmail4'] != "")
						{
							$firstname = $contact['UserEmail4'];
						}
						else if($contact['UserEmail5'] != "")
						{
							$firstname = $contact['UserEmail5'];
						}
						else
						{
							$firstname = $this->view->translate("No Details");
						}
					}
					
					jQuery('.address_row[contactid=' . $requestParams['contact']['id'] . '] .first_name')->html($firstname);
					jQuery('.address_row[contactid=' . $requestParams['contact']['id'] . '] .last_name')->html($lastname);
				}

				$this->view->jsonIdsToRender['contact_info'] = 'contacts/viewcontact.phtml';
			}
			else
			{
				jQuery::evalScript('$("#contact_info").scrollTop(0); $("input", "#contactform").blur();');
			}
			$this->render('global/jsonresponse', null, true);
		}
		else
		{
			$this->render('viewcontact');
		}
	}

	public function importAction()
	{

		$requestParams = $this->getRequest()->getParams();
		
		$groupid = 0;
		if(isset($requestParams['GroupID'])) $groupid = $requestParams['GroupID'];
		
		$pathname = users::getTmpFolder() . $_FILES['ImportFile']['name'];

		$this->view->duplicates = 0;
		$this->view->added = 0;

		if( !move_uploaded_file($_FILES['ImportFile']['tmp_name'], $pathname)) 
		{

			throw new Exception('Unable to access the uploaded vcard. Check Web server has permissions on tmp folder.');

		}
		
		$vcard = new Vcard();
		$contacts = $vcard->build($pathname);
        
		foreach($contacts as $contact)	
		{

			$importContact = $vcard->viewPart($contact);
			
			// collect all the emails and ensure that they are placed correctly
			$emails = array();
			foreach(array('UserEmail', 'UserEmail2', 'UserEmail3', 'UserEmail4', 'UserEmail5') as $fieldname)
			{
				if(isset($importContact[$fieldname]) && $importContact[$fieldname] != '')
				{
					$emails[] = $importContact[$fieldname];
				}
			}
			
			$fields = array('UserEmail', 'UserEmail2', 'UserEmail3', 'UserEmail4', 'UserEmail5');
			foreach($fields as $field)
			{
				unset($importContact[$field]);
			}
						
			for($z=0;$z<count($emails);$z++)
			{
				$importContact[$fields[$z]] = $emails[$z];
			}
			
			// Skip blank rows
			if(count($importContact) == 0)
				continue;

			// Add the contact if the user email, firstname and lastname DO NOT already exist ( avoid duplicate contacts )
			$importContact['GroupID'] = $groupid;
			
			$found = false;
			if( !$this->_contacts->searchContact( $importContact) )
			{
				$found = true;
			}

			if( $found )
			{					
				$this->view->added++;
				$id = $this->_contacts->addContact($importContact);
			}
			else
			{
				$this->view->duplicates++;          
			}
		}
		unlink($pathname);
	
		//syncContacts hook
		$this->syncContacts();
		$this->render('import');

	}

	public function favouriteAction()
	{
		$requestParams = $this->getRequest()->getParams();
		$id = $requestParams['id'];
		$fav = $requestParams['set'];

		try
		{
			$this->_contacts->updateContact(array('id' => $id, 'Favourite' => $fav));
		}
		catch(Exception $e)
		{
			// caught exception while attempting to set favourite. 
			// return blank json	
		}
		$this->render('global/jsonresponse', null, true);
	}

	public function exportcontactAction()
	{
		$requestParams = $this->getRequest()->getParams();
		$vcard = new Vcard();

		$ids = explode(":", $requestParams['id']);

		// Optionally, export "ALL" contacts
		if(empty($ids[0]))
		{
			$ids = $this->_contacts->getContacts(array('GroupID' => $requestParams['GroupID']));

			foreach($ids as $id)
			{
				if(empty($id))
				{
					continue;
				}
				$exportVcard[] = implode("\n", $vcard->exportPart($id));
			}
		}
		else
		{
			// Loop for each element selected to export
			foreach($ids as $id)
			{
				if(empty($id))
				{
					continue;
				}

				$contact = $this->_contacts->getContact($id, $requestParams['GroupID']);
				$exportVcard[] = implode("\n", $vcard->exportPart($contact));
			}
		}

		// Output the VCF file
		header('Pragma: ', true);
		header('Cache-Control: ', true);
		header('Content-Type: text/vcf', true);
		header('Content-Disposition: attachment; filename=vcard.vcf', true);
		echo implode("\n",$exportVcard);
		// exit;
		return 1;
	}

	public function searchfuzzyAction()
	{
		$requestParams = $this->getRequest()->getParams();
		$query = array();

		$skipFields = array(
			'Global',
			'DateAdded',
			'DateModified',
			'EntryID',
			'UserPhoto',
			'UserFileAs',
			'Shared',
			'Favourite',
			'UsageCount',
			'VCardData',
			'CardDAVUrl',
			'Account',
			'UserType',
			'UserDOB',
			'UserGender'
		);
		
		if (!is_numeric($requestParams['query'])) {
			$skipFields[] = 'UserHomePhone';
			$skipFields[] = 'UserHomeMobile';
			$skipFields[] = 'UserHomeFax';
			$skipFields[] = 'UserWorkPhone';
			$skipFields[] = 'UserWorkMobile';
			$skipFields[] = 'UserWorkFax';
		}
		
		foreach($this->_contacts->allowedFields as $field) 
		{
			if(in_array($field, $skipFields))
			{
				continue;
			}
			$query[$field] = $requestParams['query'];
		}

		if( count($query) > 0 )
		{
		
			$search_results = $this->_contacts->searchFuzzyContact($query, $requestParams['GroupID']);
			$contacts = array();
			foreach($search_results as $result)
				$contacts[] = $this->_contacts->getContact($result['id'], $requestParams['GroupID']);
			$contactsAll = $contacts;

		}
		else
			$contactsAll = $this->_contacts->getContacts();
		
		$this->view->groupID = 0;

		$this->view->contactsC = count($contactsAll);

		//prepare pagination
		$this->view->pageVolume = 100;
		$page = isset($requestParams['page'])?$requestParams['page']:1;
		$this->view->pageNumber = $page;
		$offset = ($page - 1) * $this->view->pageVolume;
		$this->view->contacts = array_slice($contactsAll, $offset, $this->view->pageVolume);
		$this->view->contact = isset($this->view->contacts[0])?$this->view->contacts[0]:null;
		
		$this->view->query = $requestParams['query'];
		
		
		if( $this->isAjax ) 
		{
		
			jQuery('#address_contacts')->scrollTop(0);
			$this->view->jsonIdsToRender['address_contacts'] = 'contacts/listcontacts.phtml';
			$this->view->jsonIdsToRender['contact_info'] = 'contacts/viewcontact.phtml';
			$this->render('global/jsonresponse', null, true);
		
		}
		else
			$this->render('listcontacts');
		
	}

	public function getPriority($contact) {
		//IF photo && realname = best
		//if photo && !realname = better
		//if !photo && realname = ok
		//if !photo && !realname = average


		$hasPhoto = !empty($contact['UserPhoto']);
		$hasRealName = !empty($contact['UserFirstName']) || !empty($contact['UserLastName']);

		$priority = $hasPhoto && $hasRealName? 10 :	$hasPhoto && !$hasRealName? 20 : !$hasPhoto && $hasRealName? 30 : 40;

		if($contact['Global'] == '1') {
			$priority += 1;
		}

		return $priority;
	}

	public function autocompleteAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
        //TODO: onle search as wide as user has access to. e.g. if user has system wide access then search entire system, else domain
		// get names (eg: database)
		// the format is: 
		// id, searchable plain text, html (for the textboxlist item, if empty the plain is used), html (for the autocomplete dropdown)

		// Check if the global addressbook is available
		$userDataComplete = users::getAllUserData( $this->userData['Account'] );
		
		if( isset($requestParams['need']) && in_array($requestParams['need'], array("sms", "voice", "email")) )
			$need = $requestParams['need'];
		else
			$need = 'email';
		
		$limit = 100;	// default limit, set to -1 for infinite
		if(isset($requestParams[Atmail_Enum::ID_LIMIT]))
		{
			$limit = $requestParams[Atmail_Enum::ID_LIMIT];
		}
		else
		{
			$requestParams[Atmail_Enum::ID_LIMIT] = $limit;
		}
		
		$search = '';
		if(isset($requestParams['search']))
		{
			$search = $requestParams['search'];
		}
		else if( isset($requestParams['q']))
		{
			$search = $requestParams['q'];
		}
		else
		{
			$requestParams['search'] = $search;
		}

		$searchArrayForVoiceAndSms = array(
			'SIP' => $search,
			'UserWorkPhone' => $search,
			'UserWorkMobile' => $search,
			'UserHomePhone' => $search,
			'UserHomeMobile' => $search,
			'UserHomeNumber4' => $search,
			'UserWorkNumber4' => $search,
			'UserNumber5' => $search,
			'UserNumber6' => $search,
			'UserNumber7' => $search,
			'UserFirstName' => $search,
			'UserMiddleName' => $search,
			'UserLastName' => $search,
			'fuzzy' => 1,
			'limit' => $limit,
			'sort' => 'UsageCount',
			'order' => 'desc'
		);



		$response = array();
		if(!isset($requestParams['type']))
		{
			$requestParams['type'] = '';
		}
		
		$contacts = array();		
		if($requestParams['type'] == 'global')
		{
			if($search != '')
			{
				
				if( $need == 'voice' || $need == 'sms')
					$searchArray = array_merge($searchArrayForVoiceAndSms, array('GroupID' => '-1',));
				else
						$searchArray = array('UserEmail' => $search, 'UserEmail2' => $search, 'UserEmail3' => $search, 'UserEmail4' => $search, 'UserEmail5' => $search, 'UserFirstName' => $search, 'UserMiddleName' => $search, 'UserLastName' => $search, 'fuzzy' => 1, 'GroupID' => '-1', Atmail_Enum::ID_LIMIT => $limit, 'sort' => 'UsageCount', 'order' => 'desc' );
				$contactsIds = $this->_contacts->searchContact($searchArray);
				foreach($contactsIds as $id)
				{
					try
					{
						$contacts[] = $this->_contacts->getContact($id, '-1');
					}
					catch(Exception $e)
					{

					}
				}
			}
			else
			{	
				try
				{
					$contacts = $this->_contacts->getContacts(array('GroupID' => '-1', Atmail_Enum::ID_LIMIT => $limit, 'emailOnly' => true, 'sort' => 'UsageCount', 'order' => 'desc'));
				}
				catch(Exception $e)
				{
				}
			}
		}
		else
		{
			// Load our personal contacts
			if($search != '')
			{
				if( $need == 'voice' || $need == 'sms')
					$searchArray = $searchArrayForVoiceAndSms;
				else
					$searchArray = array('UserEmail' => $search, 'UserEmail2' => $search, 'UserEmail3' => $search, 'UserEmail4' => $search, 'UserEmail5' => $search, 'UserFirstName' => $search, 'UserMiddleName' => $search, 'UserLastName' => $search, 'fuzzy' => 1, Atmail_Enum::ID_LIMIT => $limit, 'sort' => 'UsageCount', 'order' => 'desc');

				$contactsIds = $this->_contacts->searchContact($searchArray);
				foreach($contactsIds as $id)
				{
					$contact_ar = $this->_contacts->getContact($id, '');
					if($contact_ar != null)
						$contacts[] = $contact_ar;
				}
			}
			else
			{
				$contacts = $this->_contacts->getContacts(array_merge($requestParams, array('emailOnly' => true, 'sort' => 'UsageCount', 'order' => 'desc')));
			}

			// If the global addressbook is enabled, add up to 100 contacts to the global populated list
			if( !empty($userDataComplete['Groups']['SharedAbook']) )
			{
				if($search != '')
				{
					$contactsGlobal = array();
					
					if( $need == 'voice' || $need == 'sms')
						$searchArray = array_merge($searchArrayForVoiceAndSms, array('GroupID' => '-1',));
					else
						$searchArray = array('UserEmail' => $search, 'UserEmail2' => $search, 'UserEmail3' => $search, 'UserEmail4' => $search, 'UserEmail5' => $search, 'UserFirstName' => $search, 'UserMiddleName' => $search, 'UserLastName' => $search, 'fuzzy' => 1, 'GroupID' => '-1', Atmail_Enum::ID_LIMIT => $limit, 'sort' => 'UsageCount', 'order' => 'desc');
					$contactsIds = $this->_contacts->searchContact($searchArray);
					foreach($contactsIds as $id)
					{
						$contact_temp = $this->_contacts->getContact($id, '-1');
						if($contact_temp != null)
							$contactsGlobal[] = $contact_temp;
					}
				}
				else
				{
					$contactsGlobal = $this->_contacts->getContacts(array('GroupID' => '-1', Atmail_Enum::ID_LIMIT => $limit, 'emailOnly' => true, 'sort' => 'UsageCount', 'order' => 'desc'));
				}
			}

			// If global contacts found, append to the autocomplete array
			if(is_array($contactsGlobal))
			{
				$contacts = array_merge($contacts, $contactsGlobal);
			}

			$contactsShared = array();
			// If the shared addressbook is enabled, add up to 100 additional contacts to the autocomplete list
			if( !empty($userDataComplete['Groups']['SharedAbook']) )
			{
				if($search != '')
				{
					
					if( $need == 'voice' || $need == 'sms')
						$searchArray = array_merge($searchArrayForVoiceAndSms, array('GroupID' => '-2',));
					else
						$searchArray = array('UserEmail' => $search, 'UserEmail2' => $search, 'UserEmail3' => $search, 'UserEmail4' => $search, 'UserEmail5' => $search, 'UserFirstName' => $search, 'UserMiddleName' => $search, 'UserLastName' => $search, 'fuzzy' => 1, 'GroupID' => '-2', Atmail_Enum::ID_LIMIT => $limit, 'sort' => 'UsageCount', 'order' => 'desc');
					$contactsIds = $this->_contacts->searchContact($searchArray);
					foreach($contactsIds as $id)
					{
						try
						{
							$contact_temp = $this->_contacts->getContact($id, '-2');
							if($contact_temp != null)
							{
								$contactsShared[] = $contact_temp;
							}
						}
						catch(Exception $e)
						{
						}
					}
				}
				else
				{
					try
					{
						$contactsShared = $this->_contacts->getContacts(array('GroupID' => '-2', Atmail_Enum::ID_LIMIT => $limit, 'emailOnly' => true, 'sort' => 'UsageCount', 'order' => 'desc'));
					}
					catch(Exception $e)
					{
					}
				}
			}

			// If shared contacts found, add to the autocomplete array
			if(is_array($contactsShared))
			{
				$contacts = array_merge($contacts, $contactsShared);
			}

			// Include the rememebered auto contacts
			if($search != '')
			{
				$contactsAuto = array();
				if( $need == 'voice' || $need == 'sms')
					$searchArray = array_merge($searchArrayForVoiceAndSms, array('GroupID' => '-3',));
				else
					$searchArray = array('UserEmail' => $search, 'UserEmail2' => $search, 'UserEmail3' => $search, 'UserEmail4' => $search, 'UserEmail5' => $search, 'UserFirstName' => $search, 'UserMiddleName' => $search, 'UserLastName' => $search, 'fuzzy' => 1, 'GroupID' => '-3', Atmail_Enum::ID_LIMIT => $limit, 'sort' => 'UsageCount', 'order' => 'desc');
				$contactsIds = $this->_contacts->searchContact($searchArray);
				foreach($contactsIds as $id)
				{
					$contact_temp = $this->_contacts->getContact($id, '-3');
					if($contact_temp != null)
						$contactsAuto[] = $contact_temp;
				}
			}
			else
			{
				$contactsAuto = $this->_contacts->getContacts(array('GroupID' => '-3', Atmail_Enum::ID_LIMIT => $limit, 'emailOnly' => true, 'sort' => 'UsageCount', 'order' => 'desc'));
			}

			// If contacts Auto found
			if(is_array($contactsAuto))
			{
				$contacts = array_merge($contacts, $contactsAuto);
			}
		}

		$groupsContacts = $this->_contacts->getGroupsContacts(array(Atmail_Enum::ID_LIMIT => $limit, 'search' => $search, 'sort' => 'UsageCount', 'order' => 'desc', 'need' => $need));


		$groupsMimeRecipientsList = array();
		foreach( $groupsContacts as $groupName => $gContacts)
		{
			
			//can only call 1 voice number at a time so exclude group matches from a voice autocomplete search
			if( $need == 'voice' )
				continue;
				
			$groupHTML = htmlentities($groupName . ' (' . $this->view->translate('Group') . ') ', ENT_COMPAT, 'UTF-8');
			
			if($need=='voice' || $need=='sms')
				$groupContact = array('', $groupHTML, null, $groupHTML . ': ', 0, $groupName);
			else
				$groupContact = array('', $groupHTML, null, $groupHTML . ' ', 0, $groupName);
			
			foreach ($gContacts as $contact)
			{
				// sanitize database data
				$this->filter->setData( $contact );
				$contact = $this->filter->getEscapedData();
				
				$groupContact[6] = Atmail_Enum::AUTOCOMPLETE_GROUP;
				if( $need == 'sms' ) //try find mobiles first
					$fieldArray = array('SIP', 'UserHomeMobile', 'UserWorkMobile',
						'UserHomeNumber4', 'UserWorkNumber4', 'UserNumber5', 'UserNumber6', 'UserNumber7' );
				else if(  $need == 'voice' )
					$fieldArray = array('SIP', 'UserHomePhone', 'UserHomeMobile', 'UserWorkPhone', 'UserWorkMobile',
						'UserHomeNumber4', 'UserWorkNumber4', 'UserNumber5', 'UserNumber6', 'UserNumber7' );
				else
					$fieldArray = array('UserEmail', 'UserEmail2', 'UserEmail3', 'UserEmail4', 'UserEmail5');


				foreach ( $fieldArray as $fieldname )
				{
					if( !empty($contact[$fieldname]) ) 
					{
						$displayName = $contact['UserFirstName'] . ' ' . $contact['UserLastName'];
						$groupContact[7] = $this->getPriority($contact);

						//strip out commas for now
						$displayName = str_replace(',', '', $displayName);
						if( mb_strlen($displayName) > 1 ) 
						{
							if( $need == 'sms' )
							{
								$groupContact[0] .= $contact[$fieldname] . ', '; //formValue
								$groupContact[2] .= htmlentities( $displayName, ENT_COMPAT, 'UTF-8' ) . ', '; //textbox value
								$groupContact[3] .= htmlentities( $displayName, ENT_COMPAT, 'UTF-8' ) . ' ' . htmlentities( $contact[$fieldname], ENT_COMPAT, 'UTF-8' ) . ', '; //dropdown value
								$groupContact[5] .= $displayName . ' ' . $contact[$fieldname] . ', '; //search string
								
							}
							else
							{
								
								$groupContact[0] .= '"' . $displayName . '" <' . $contact[$fieldname] . '>' . ', ';
								$groupContact[3] .= htmlentities('"' . $displayName . '" <' . $contact[$fieldname] . '>', ENT_COMPAT, 'UTF-8') . ', ';
							}
						}
						else
						{
							if( $need == 'sms' )
							{
								
								$groupContact[0] .= $contact[$fieldname] . ', '; 
								$groupContact[2] .= htmlentities( $contact[$fieldname], ENT_COMPAT, 'UTF-8' ) . ', '; 
								$groupContact[3] .= htmlentities( $contact[$fieldname], ENT_COMPAT, 'UTF-8' ) . ', ';
								$groupContact[5] .= $contact[$fieldname] . ', '; 
								
							}
							else
							{
							$groupContact[0] .= $contact[$fieldname] . ', '; 
							$groupContact[3] .= htmlentities( '<' . $contact[$fieldname] . '>', ENT_COMPAT, 'UTF-8' ) . ', ';	
								
							}
						}
						continue 2; //contact recipient using first matched contact method (you dont want to go spamming the user on all listed contact methods)
					}
				}
			}

			//trim the last comma off
			if(mb_strlen($groupContact[0]) > 2 && mb_substr($groupContact[0], -2) == ', ') 
				$groupContact[0] = mb_substr( $groupContact[0], 0, -2);
			if(mb_strlen($groupContact[2]) > 2 && mb_substr($groupContact[2], -2) == ', ') 
				$groupContact[2] = mb_substr( $groupContact[2], 0, -2);
			if(mb_strlen($groupContact[3]) > 2 && mb_substr($groupContact[3], -2) == ', ') 
				$groupContact[3] = mb_substr( $groupContact[3], 0, -2);
			if(mb_strlen($groupContact[5]) > 2 && mb_substr($groupContact[5], -2) == ', ') 
				$groupContact[5] = mb_substr( $groupContact[5], 0, -2);

			//add the addresses into the search string as well
			if( mb_strlen($groupContact[0]) > 0 && mb_strlen($groupContact[1]) > 0)
			{
				$groupsMimeRecipientsList[] = $groupContact;
			}
		}

		$contactsMimeRecipientsList = array();

		if(count($contacts)!= 0)
		{
			foreach( $contacts as $contact )
			{
				if($contact == null)
					continue;
					
				// sanitize database data
				$this->filter->setData( $contact );
				$contact = $this->filter->getEscapedData();
				
				
				if( 
					( $need == 'email' && (!empty($contact['UserEmail']) || !empty($contact['UserEmail2']) || !empty($contact['UserEmail3']) || !empty($contact['UserEmail4']) || !empty($contact['UserEmail5']) ) )
					||
					( ($need == 'voice' || $need == 'sms') && (
						!empty($contact['SIP']) || !empty($contact['UserWorkPhone']) || !empty($contact['UserWorkMobile']) || !empty($contact['UserHomePhone']) || !empty($contact['UserHomeMobile']) ||
						!empty($contact['UserHomeNumber4']) || !empty($contact['UserWorkNumber4']) || !empty($contact['UserNumber5']) || !empty($contact['UserNumber6']) || !empty($contact['UserNumber7'])
					) )
				)
				{
					if( !empty($contact['UserPhoto']) )
					{
						$id = $contact['id'];
						$rand = rand();
						$displayImg = "<img width='30' height='30' src='" . $this->view->moduleBaseUrl . "/contacts/viewphoto/id/$id/resize/1/$rand'/>";
					}
					else
					{
						// Display the blank user profile image
						$displayImg = "<img width='30' height='30' src='" . $this->view->siteBaseUrl . "images/themes/" . $this->view->UserSettings['cssStyleTheme'] . "/contact-photo-small.png'/>";						
					}

					$displayName = $contact['UserFirstName'] . ' ' . $contact['UserLastName'];
					
					if($displayName == ' ')
					{
						$displayName = '';
					} 
					//strip out commas for now
					$displayName = str_replace(',', '', $displayName);
					if( $need == 'voice' || $need == 'sms' ) 
						$fieldArray = array('SIP', 'UserWorkPhone', 'UserWorkMobile', 'UserHomePhone', 'UserHomeMobile',
							'UserHomeNumber4', 'UserWorkNumber4', 'UserNumber5', 'UserNumber6', 'UserNumber7',
							);
					else
						$fieldArray = array('UserEmail', 'UserEmail2', 'UserEmail3', 'UserEmail4', 'UserEmail5');


					$fieldMapCustomField = array('HomePhone'=>'Home','HomeMobile'=>'Mobile','WorkPhone'=>'Work','WorkMobile'=>'Mobile');

					$fieldMap = array(
						'SIP' => "SIP ID",
						'UserWorkPhone' => "Work",
						'UserWorkMobile' => "Mobile",
						'UserHomePhone' => "Home",
						'UserHomeMobile' => "Mobile",

						'UserHomeNumber4' => "Home",
						'UserWorkNumber4' => "work"
                    );
                    if(array_key_exists('UserNumber5Type', $contact) && array_key_exists($contact['UserNumber5Type'], $fieldMapCustomField))
                    {
                        $fieldMap = array_merge($fieldMap, array('UserNumber5' => $fieldMapCustomField[$contact['UserNumber5Type']]));
                    }
                    if(array_key_exists('UserNumber6Type', $contact) && array_key_exists($contact['UserNumber6Type'], $fieldMapCustomField))
                    {
                        $fieldMap = array_merge($fieldMap, array('UserNumber6' => $fieldMapCustomField[$contact['UserNumber6Type']]));
                    }
                    if(array_key_exists('UserNumber7Type', $contact) && array_key_exists($contact['UserNumber7Type'], $fieldMapCustomField))
                    {
                        $fieldMap = array_merge($fieldMap, array('UserNumber7' => $fieldMapCustomField[$contact['UserNumber7Type']]));
                    }

					foreach ( $fieldArray as $fieldname )
					{
						
						//if field populated AND matches what the user was searchign for (dont include the other contacts numbers found in their card)
						//compare by simplifying to alphanumeric only
						//if search string inside matched contact field then add it to the results
						//if the search matched the name then insclude all contact fields available for the contact matches
						if( empty($search) || mb_strpos( mb_strtolower($displayName), mb_strtolower($search)) !== false )
						{
							
							//continue with populating with all contact fields found records
							
						}
						else if( $need == 'sms' || $need == 'voice' )
						{
							
							//for SIP ID compare entire string else just last 9
							if( $fieldname == "SIP" )
							{
								$searchSimplified = mb_strtolower( $search );
								$contactFieldValueSimplified = mb_strtolower( $contact[$fieldname] );
								
								if( mb_strpos($contactFieldValueSimplified, $searchSimplified) === false)
									continue;
							}
							else
							{
								$searchSimplified            = mb_strtolower( mb_ereg_replace('[^0-9A-Za-z]', '', $search             ), 'UTF-8' ); //mb_substr( mb_strtolower( mb_ereg_replace("[^0-9]", "", $search             ) ), -9, 'utf-8' );
								$contactFieldValueSimplified = mb_strtolower( mb_ereg_replace('[^0-9A-Za-z]', '', $contact[$fieldname]), 'UTF-8' ); //mb_substr( mb_strtolower( mb_ereg_replace("[^0-9]", "", $contact[$fieldname]) ), -9, 'utf-8' );
								
								if( mb_strpos($contactFieldValueSimplified, $searchSimplified) === false )
									continue;
								
								
							}
							
						}
						else
						{
							
							//match email addresses
							$searchSimplified = mb_strtolower( $search );
							$contactFieldValueSimplified = mb_strtolower( $contact[$fieldname] );
							if( mb_strpos($contactFieldValueSimplified, $searchSimplified) === false)
								continue;
								
						}
						
						if( isset($contact[$fieldname]) && $contact[$fieldname] != '')
						{
							
							
							if(mb_strlen($displayName) > 1)
							{
								if( $need == 'sms' || $need == 'voice' )
								{
									$formValue = $contact[$fieldname]; 
									$displayTextbox = htmlentities($displayName, ENT_COMPAT, 'UTF-8');
									$displayDropdown = '<table width="200" class="np"><tr><td class="np ac_name" colspan="2">' . htmlentities($displayName, ENT_COMPAT, 'UTF-8') . '</td></tr><tr><td class="np">' . htmlentities($contact[$fieldname] . '', ENT_COMPAT, 'UTF-8') . '</td><td class="np" width="40">' . $fieldMap[$fieldname] . '</td></tr></table>'; 
									$matchString = $displayName . ' ' . $contact[$fieldname];
								}
								else
								{
									$matchString = '"' . $displayName . '" <' . $contact[$fieldname] .'>';
								$displayHTML = $displayImg . htmlentities('"' . $displayName . '" <' . $contact[$fieldname] . '>', ENT_COMPAT, 'UTF-8'); 
								$displayEmail = htmlentities('"' . $displayName . '" <' . $contact[$fieldname] . '>', ENT_COMPAT, 'UTF-8');
								}
							}
							else
							{
								if( $need == 'sms' || $need == 'voice' )
								{
									$formValue = $contact[$fieldname];
									$displayTextbox = htmlentities($contact[$fieldname], ENT_COMPAT, 'UTF-8');
									$displayDropdown = htmlentities($contact[$fieldname], ENT_COMPAT, 'UTF-8'); 
									$matchString = $contact[$fieldname];
								}
								else
								{
									$matchString = $contact[$fieldname];
									$displayHTML = $displayImg . htmlentities($contact[$fieldname], ENT_COMPAT, 'UTF-8'); 
									$displayEmail = htmlentities($contact[$fieldname], ENT_COMPAT, 'UTF-8');
								}
							} //6 fields  form, match, textbox, dropdown, usageCount, blank

							if( $need == 'sms' || $need == 'voice')
								$contactsMimeRecipientsList[] = array(trim($formValue), null, trim($displayTextbox), trim($displayDropdown), $contact['UsageCount'], trim($matchString));
							else
								$contactsMimeRecipientsList[] = array(trim($matchString), trim($displayEmail), null, trim($displayHTML), $contact['UsageCount'], '', $contact[$fieldname], $this->getPriority($contact));

							continue; //contact recipient using first matched contact method (you dont want to go spamming the user on all listed contact methods)
							
						}
					}
				}
			}
		}
		else
		{
			$contactsMimeRecipientsList = array();
		}

		$mimeRecipientsList = array_merge($contactsMimeRecipientsList, $groupsMimeRecipientsList );

		//now cull duplicates
		$mimeRecipientsListUnique = array();
		foreach( $mimeRecipientsList as $k => $v )
		{
			if( !array_key_exists($v[0], $mimeRecipientsListUnique) || $v[6] == Atmail_Enum::AUTOCOMPLETE_GROUP)
			{
				$mimeRecipientsListUnique[$v[0]] = $v;
			}
			else
			{
				//use the one with more detail (photo etc.)
				if( strlen($mimeRecipientsListUnique[$v[0]][3]) < strlen($v[3]) )
				{
					$mimeRecipientsListUnique[$v[0]] = $v;
				}
				unset( $mimeRecipientsList[$k] );
			}
		}
		
		if( $need!='voice' && $need!='sms')
		{
	
			// Merge duplicated recipients based on email
			$uniqueRecipients = array();
			foreach($mimeRecipientsList as $key=>$recipient)
			{
				
				$email = strtolower( $recipient[6] );
				if(!$email)
					$uniqueRecipients[] = array( $key );
				else 
				{

					if( isset( $uniqueRecipients[ $email ] ))
						$uniqueRecipients[ $email ][] = $key;
                    elseif( $email == 'group' )
                        $uniqueRecipients[ $recipient[1] ] = array($key);
					else
						$uniqueRecipients[ $email ] = array($key);

				}
				
			}
	
			$mimeRecipientsListMerged = array();
			foreach($uniqueRecipients as $items)
			{
				
				if(count($items) == 1)
					$mimeRecipientsListMerged[] = $mimeRecipientsList[ $items[0] ];
				else if ( count($items) > 1 ) 
				{
	
					$tmpRecipient = $mimeRecipientsList[ $items[0] ];
					for($index=1; $index<count($items); ++$index) 
					{
	
						$contact = $mimeRecipientsList[$items[$index]];
						if($tmpRecipient[7] > $contact[7])
							$tmpRecipient = $contact;

					}
					$mimeRecipientsListMerged[] = $tmpRecipient;

				}

			}
			$mimeRecipientsListUnique = $mimeRecipientsListMerged;

		}

		// dont sort, we dont use any binary searches as our returned array is quite small now
		// we will actually sort by usage now
		// make sure they're sorted alphabetically, for binary search tests
		// usort($mimeRecipientsListUnique, "strcmpAk");
		function bestUsed($a,$b) { return $a[4]<$b[4]; }
		usort($mimeRecipientsListUnique, 'bestUsed');
		
		if($limit != -1 && count($mimeRecipientsListUnique) > $limit) $mimeRecipientsListUnique = array_slice($mimeRecipientsListUnique, 0, -(count($mimeRecipientsListUnique) - $limit));
		$json = Zend_Json::encode($mimeRecipientsListUnique); 
		if( !empty($requestParams['pretty']) )
			$json = Zend_Json::prettyPrint($json, array("indent" => "    "));
	    $this->getResponse()->setHeader('Content-Type','application/json')->appendBody($json);
		$this->_helper->viewRenderer->setNoRender();
	}

	
	public function whoisAction()
	{
		
		$requestParams = $this->getRequest()->getParams();
        
		// Check if the global addressbook is available
		$userDataComplete = users::getAllUserData( $this->userData['Account'] );
		
		
		$search = '';
		if( isset($requestParams['search']) )
			$search = $requestParams['search'];
		$search_last9 = substr($search, -9);
		
		$searchArray = array(
			'UserHomePhone' => $search_last9,
			'UserHomeMobile' => $search_last9,
			'UserHomeFax' => $search_last9,
			'UserWorkPhone' => $search_last9,
			'UserWorkMobile' => $search_last9,
			'UserWorkFax' => $search_last9,
			'SIP' => $search,
			'fuzzy' => 1, 
			'GroupID' => ''
		);
		$contactsIds = $this->_contacts->searchContact($searchArray);
		$contactMatch = null;
		if( count($contactsIds) > 0 )
			$contactMatch = $this->_contacts->getContact($contactsIds[0], '');
		else
		{
			
			$searchArray['GroupID'] = '-1';
			$contactsIds = $this->_contacts->searchContact($searchArray);
			if( count($contactsIds) > 0 )
				$contactMatch = $this->_contacts->getContact($contactsIds[0], '-1');
			else
			{

				$searchArray['GroupID'] = '-2';
				$contactsIds = $this->_contacts->searchContact($searchArray);
				if( count($contactsIds) > 0 )
					$contactMatch = $this->_contacts->getContact($contactsIds[0], '-2');
				else
				{
					$searchArray['GroupID'] = '-3';
					$contactsIds = $this->_contacts->searchContact($searchArray);
					if( count($contactsIds) > 0 )
						$contactMatch = $this->_contacts->getContact($contactsIds[0], '-3');
				}

			}

		}
		//Zend_Registry::get('log')->debug( "\n" . print_r($contactMatch, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$contactMatch \n");
		$matchData = array(
			'status' => 'success', //did the query complete cuccessfully
			'result' => 'not found', //was a match found
			'name' => $this->view->translate('Unknown'), 
			'imageUrl' => $this->view->siteBaseUrl . 'images/themes/' . $this->view->UserSettings['cssStyleTheme'] . '/contact-photo.png'
		);

		$matchData['defaultImageUrl'] = $matchData['imageUrl'];
		
		if( $contactMatch !== null )
		{
			if( !empty($contactMatch['UserPhoto']) )
				$matchData['imageUrl'] = $this->view->moduleBaseUrl . '/contacts/viewphoto/id/' . $contactMatch['id'] . '/shadow/1/forceReloadOnChanged/' . md5($contactMatch['UserPhoto']);
 		
			//TODO: company name if no first and last name e.g. organisations
			$displayName = trim(htmlentities($contactMatch['UserFirstName'] . ' ' . $contactMatch['UserLastName'], ENT_COMPAT, 'UTF-8'));
			if( !empty($displayName) )
				$matchData['name'] = $displayName;
		
			$matchData['result'] = 'found';
			$matchData['abook_number'] = '';

			if(!empty($search_last9))
			{
				foreach ($contactMatch as $key => $value) {
					if($key == 'SIP') {
						if(strpos($value, $search) !== FALSE) {
							$matchData['source_device'] = $key;
							$matchData['abook_number'] = $value;
							break;
						}
					}
					else if(in_array($key, array('UserHomePhone', 'UserHomeMobile', 'UserHomeFax', 'UserWorkPhone', 'UserWorkMobile', 'UserWorkFax' ,)))
					{
						$value_digit = preg_replace('/\D/','',$value);
						if(!empty($value) && !empty($value_digit) && strpos($value_digit, $search_last9) !== FALSE)
						{
							$matchData['source_device'] = $key;
							$matchData['abook_number'] = $value;
							break;
						}
					}
				}
			}
		}
		
		//Zend_Registry::get('log')->debug( "\n" . print_r($matchData, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$matchData \n");
	    
		$json = Zend_Json::encode($matchData); 
		$this->getResponse()->setHeader('Content-Type','application/json')->appendBody($json);
		$this->_helper->viewRenderer->setNoRender();
		//Zend_Registry::get('log')->debug( "\n" . print_r($json, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$json \n");
		
	}
	
	
	// Add recipient window in composer
	public function addrecipientAction()
	{
		$requestArray = $this->getRequest()->getParams();
		$all_selected = $requestArray['all_selected'];

		$fakeRequest = array_merge($requestArray, array(Atmail_Enum::ID_LIMIT=>-1, 'sort' => 'UsageCount', 'order' => 'desc', 'finalSort' => 'email'));
		$this->view->contacts = fetchAutocompleteList(users::getAllUserData( $this->userData['Account'] ),  $fakeRequest, $this->_contacts, $this->filter, $this->view );//array_slice($contactsAll, 0, 100);
		foreach($this->view->contacts as &$contact)
		{
			$contact = array_merge($contact[6], array('UserEmailFormatted' => $contact[1]));
		}
		
		$this->view->contactsC = count($this->view->contacts);
		// autocomplete fetch already has sanitize database data
	}

}
