<?php

/**
 * Extends the BaseFacebook class with the intent of using
 * PHP sessions to store user ids and access tokens.
 */
class Atmail_Provider_SocialNetwork_Facebook extends Atmail_Provider_SocialNetwork_Abstract
{
	const FB_URL = "https://graph.facebook.com/";

	public $fieldMap = array("newsfeed" => "home", "wall" => "feed"); //maps public field names to internal field names
	private $_myData = null;
	private $_myContactsIds = null;
	private $_myContactsDetails = null;
	private $_myContactsSummary = null;
	
	public function __construct( Array $configArray ) 
	{
		$this->_session = new Zend_Session_Namespace('defaultNamespace');
		$this->dbAdapter = Zend_Registry::get('dbAdapter');
		$this->username = $configArray['UserId'];
		$this->displayName = $configArray['DisplayName'];
		$this->userAuthedToken = $configArray['Password'];
//Zend_Registry::get('log')->debug( "\n" . print_r($this->userAuthedToken, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$this->userAuthedToken \n");
		
		$this->appId = Zend_Registry::get('config')->Facebook['FbAppId'];
		$this->appSecret = Zend_Registry::get('config')->Facebook['FbAppSecret'];
		$this->Account = $this->_config['Account'];
//Zend_Registry::get('log')->debug( "\n" . print_r(Zend_Registry::get('config')->Facebook, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \Zend_Registry::get('config')->Facebook \n");
		
		$this->facebookInterface = new Atmail_Provider_SocialNetwork_FacebookInterface( array('appId' => $this->appId, 'secret' => $this->appSecret) );
		$this->facebookInterface->setAccessToken($this->userAuthedToken);
		if( !parent::__construct($configArray) )
			return false;
		
	}
	
	private function mapToInternal( $publicField )
	{
		
		if( array_key_exists($publicField, $this->fieldMap) )
			return $this->fieldMap[$publicField];
		else
			return $publicField;
		
	}

	private function mapToPublic( $internalField )
	{
		
		$result = array_search($internalField, $this->fieldMap);
		if( $result )
			return $result;
		else
			return $internalField;
		
	}

	public function getList( Array $args = array() )
	{
		
		//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		if( array_key_exists('folder',$args) )
			$folder = $this->mapToInternal($args['folder']);
		else 
			$folder = 'feed';
		
		if( array_key_exists('id', $args) )
			$id = $args['id'];
		else
			$id = 'me';
		//prep result array
		$return = $args;
		
		try {
			$result = $this->_get($id . "/" . $folder);
			if(!$result)
			{
				throw new Exception('Could not authenticate you.');
			}

			if( !array_key_exists('data', $result) )
				$return['serviceData'] = $result;
			else
				$return['serviceData'] = $result['data'];
			$return['success'] = "true"; //Did the action complete without failure (server fails, network down etc.)
			$return['result'] = "true"; //Did the executing the action result in a success or fail for the commend (e.g. delete, or add)
			$return['noteEnglish'] = "Fetched remote data successfully"; //used for english display and translation
			$return['noteCode'] = "200"; //used for programatic success and result handling
			$return['lastUpdated'] = time();
			$return['serviceType'] = "SocialNetwork";
			$return['serviceName'] = "Facebook";
			$return['myId'] = $this->username;
			$return['myDisplayName'] = $this->displayName;
			$return['folder'] = $this->mapToPublic($args['folder']);
			
		} catch( Exception $e) {
			
			$return['success'] = "true"; //Did the action complete without failure (server fails, network down etc.)
			$return['result'] = "false"; //Did the executing the action result in a success or fail for the commend (e.g. delete, or add)
			$return['noteEnglish'] = "Failed fetching remote data: " . $e->getMessage(); //used for english display and translation
			$return['noteCode'] = "404"; //used for programatic success and result handling
			$return['lastUpdated'] = time();
			$return['serviceType'] = "SocialNetwork";
			$return['serviceName'] = "Facebook";
			$return['myId'] = $this->username;
			$return['myDisplayName'] = $this->displayName;
			$return['folder'] = $this->mapToPublic($args['folder']);
			
		}
		//Zend_Registry::get('log')->debug( "\n" . print_r($return, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$return \n");
		return $return;
		
	}

	public function getSummary( Array $args = array( 'groupBy' => 'from', 'groupOrder' => 'ASC') )
	{
		
		//Old Depreciated?
		return $this->getList($args);
		
	}
	
	public function getThread( Array $args = array() )
	{
        
		//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		try {
			return $this->_get($args['oid']);
		} catch( Exception $e) {

			return array('Failed: Unable to reach Facebook servers: ' . $e->getMessage() );

		}

	}
	
	public function getStream( Array $args = array() )
	{
		
		$rows = $this->getList($args);
//Zend_Registry::get('log')->debug( "\n" . print_r($rows, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$rows \n");
		
		$stream = array();
		if( !array_key_exists('serviceData', $rows) )
		{
			
			return $stream;
			
		}
		
		foreach( $rows['serviceData'] as $row )
		{
			
			$ts = UnixGMTToISO8601TZ( strtotime($row['created_time']) );
			$stream[] = array(
				'pid' => $args['pid'], 
				'providerType' => 'SocialNetwork', 
				'providerName' => 'Facebook', 
				'providerDescription' => 'Main Facebook Account', 
				'id' => $row['id'], 
				'receivedDateISO8601' => $ts,
				'timeAgo' => timeago(strtotime($ts)),
				'seen' => 'false', 
				'from' => array(
					'id' => $row['from']['id'],
					'name' => $row['from']['name']
				),
				'subject' => $row['subject'],
				'messageType' => $row['type'], 
				'summary' => $row['message'],
				'avatar' => Atmail_Provider_SocialNetwork_FacebookInterface::FB_URL . $row['from']['id'] . '/picture'
			);
			
		}
		return $stream;
		
	}


	public function getInfo( Array $args = array() )
	{
		
		if( !array_key_exists('messageId', $args) )
			throw new Exception('Error: messageId must be specified');
		return $rows[0];
		
	}
	
	
	public function deleteThread( Array $args )
	{
		
		if( !array_key_exists('messageId', $args) )
			throw new Exception('Error: from field must be specified to delete thread');
		//Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ': $q=' . $q);
		//return $this->dbAdapter->query($q);

	}
	public function delete( Array $args )
	{
		
		if( !array_key_exists('messageId', $args) )
			throw new Exception('Error: messageId must be specified');
			
		//Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ': $q=' . $q);
		//return $this->dbAdapter->query($q);

	}
	
	public function getComments( Array $args )
	{
		
		//return array('dummy');
		//$this->facebookInterface
		$requiredParams = array('oid', 'comment');
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		
		//$this->facebookInterface->setFileUploadSupport( true );
		$response = $this->facebookInterface->api($args['oid'] . '/comments/', array('message' => $args['comment']) );
		return $response;

	}
	
	private function _post($url, $data = '', $optional_headers = null)
	{
		$url = Atmail_Provider_SocialNetwork_Facebook::FB_URL . $url;
		$data = "access_token=" . $this->userAuthedToken . $data;
		$params = array('http' => array(
			'method' => 'POST',
			'content' => $data
		));
		if ($optional_headers !== null)
		{
			$params['http']['header'] = $optional_headers;
		}
		$ctx = stream_context_create($params);
		$fp = @fopen($url, 'rb', false, $ctx);
		if (!$fp)
		{
			throw new Exception("Problem with $url, $php_errormsg");
		}
		$response = @stream_get_contents($fp);
		if ($response === false)
		{
			throw new Exception("Problem reading data from $url, $php_errormsg");
		}
		return Zend_Json::decode($response);
	}
	
	private function _get($url, $data = '', $decode = true)
	{
		$url = Atmail_Provider_SocialNetwork_Facebook::FB_URL . $url;
		if($data[0] != '&') $data = '&' . $data;

		$fp = @fopen($url . "?access_token=" . $this->userAuthedToken . $data ,'r');
		$response = '';
		while (!feof($fp) && $chunk = @fread($fp, 1024))
		{
			$response .= $chunk;
		}
		@fclose($fp);
		return $decode ? Zend_Json::decode($response) : $response;
	}
	
	public function like( Array $args )
	{
		
		Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		
		$requiredParams = array('oid'); //pid = providerid, oid = unique id of message
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
				
		return $this->_post($args['oid'] . '/likes');
	}
	
	public function getLikes( Array $args )
	{
		Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		
		$requiredParams = array('oid'); //pid = providerid, oid = unique id of message
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);

		$results = $this->_get($args['oid'] . '/likes');
		
		if(isset($results['data']))
		{
			$data = $results['data'];
		}
		else
		{
			$data = array();	
		}
		return count($data);
	}
	
	public function getMyData()
	{
		if( $this->_myData != null )
			return $this->_myData['name'];
		try {
			$this->_myData = $this->_get("me");
			return $this->_myData;
		} catch( Exception $e) {
			return array('Failed: Unable to reach Facebook servers.');
		}
		
	}
	
	public function getMyName()
	{
		
		$this->getMyData();
		return $this->_myData['name'];
		
	}

	public function getMyId()
	{
		
		$this->getMyData();
		return $this->_myData['id'];
	
	}
	
	public function getMyProfileImageUrl()
	{
		
		$this->getMyData();
		return Atmail_Provider_SocialNetwork_FacebookInterface::FB_URL . $this->_myData['id'] . "/picture";
		
	}
	
	public static function parseConfig($config, $requestParams)
	{
		/*
		 %to is target username
		 %from is current username
		 %email is current account email address
		 %timeout is total minutes link is valid
		*/
		
		$msgs = array('noLongerValid', 'ChatMessage');
		foreach($msgs as $msg)
		{		
			$config[$msg] = str_replace('%to', $requestParams['toDisplayName'], $config[$msg]);
			$config[$msg] = str_replace('%from', $requestParams['fromDisplayName'], $config[$msg]);
			$config[$msg] = str_replace('%email', $requestParams['fromEmailName'], $config[$msg]);
			$config[$msg] = str_replace('%timeout', $config['timeout'], $config[$msg]);
		}
		
		return $config;
	}
	
	public function &getContactsIds()
	{
		
		if( $this->_myContactsIds !== null )
			return $this->_myContactsIds;
			
		try {
			$response = $this->_get("me/friends");
			
			$this->_myContactsIds = $response['data'];
			
			return $this->_myContactsIds;

		} catch( Exception $e) {

			return array('Failed: Unable to reach Facebook servers. ' . $e->getMessage() );

		}
	}
	
	public function getContactsDetails()
	{
		
		if( $this->_myContactsDetails != null )
			return $this->_myContactsDetails;
			
		$this->getContactsIds();
		$this->_myContactsDetails = array();
		$count = 0;
		foreach( $this->_myContactsIds as $contact)
		{
			
			if( $count++ > 20 )
				break;
			try {
				$this->_myContactsDetails[] = $this->_get($contact['id']);
			} catch( Exception $e) {

				return array('Failed: Unable to reach Facebook servers.');

			}
			
		}
		return $this->_myContactsDetails;
		
	}
	
	public function &getContactsSummary( Array $args = array() )
	{
		
		//TODO: detailed details
		if( $this->_myContactsSummary !== null )
			return $this->_myContactsSummary;
		
		$this->_myContactsSummary = array();
		//$this->getContactsDetails();
		$this->getContactsIds();
		$host = $_SERVER['HTTP_HOST'];
		foreach( $this->_myContactsIds as &$contact )
		{
			
			$firstSpacePos = mb_strpos($contact['name'], " ");
			if( $firstSpacePos === false )
			{
			
				$UserFirstName = $contact['name'];
				$UserLastName = "";
			
			}
			else
			{
				
				$UserFirstName = mb_substr($contact['name'],0,$firstSpacePos);
				$UserLastName = mb_substr($contact['name'],$firstSpacePos+1);
				
			}
			
			$details = array(
				'FacebookId' => $contact['id'], 
				//'UserEmail' => $contact['id'] . "@" . $host, 
				'UserFirstName' => $UserFirstName, 
				'UserLastName' => $UserLastName, 
				//'Location' => $contact['location'], 
				//'Timezone' => $contact['time_zone'] 
			);
			$this->_myContactsSummary[$contact['id']] = $details;
			
		}
		
		return $this->_myContactsSummary;
		
	}
	
	public function post( Array $args)
	{
		            
		//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		$requiredParams = array('id', 'message');
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		
		if( !empty($args['folder']) )
			$folder = $args['folder'];
		else
			$folder = 'feed';
				
		if(isset($args['type']) && $args['type'] == 'Chat')
		{

			// do facetube chat post using xmpp
			//$result = $this->facebookInterface->api($args['id'] . '/' . $folder , array('method' => "POST", 'access_token' => $this->userAuthedToken, 'message' => $args['message']) );
			$result = $this->sendChatMessage( array("to" => $args['id'], "message" => $args['message']) );
			//Zend_Registry::get('log')->debug( "\n" . print_r($result, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$result \n");
			$result = true;
			
		}
		else
		{
		
			$url = $args['id'] . '/' . $folder;
			//Zend_Registry::get('log')->debug( "\n" . print_r($url, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$url \n");
			$result = $this->facebookInterface->api($url , array('method' => "POST", 'message' => $args['message']) );
			//Zend_Registry::get('log')->debug( "\n" . print_r($result, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$result \n");
		
		}
		return $result;
		
	}
	
	public function get( Array $args )
	{
		
		$requiredParams = array('id');
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		
		if( !empty($args['folder']) )
			$folder = $args['folder'];
		else
			$folder = 'feed';
		$callArgs = array('method' => "GET");
		if( array_key_exists('limit', $args) )
			$callArgs['limit'] = $args['limit'];
		
		$resultArray = $this->facebookInterface->api($args['id'] . '/' . $folder , $callArgs );
		//Zend_Registry::get('log')->debug( "\n" . print_r($resultArray, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$resultArray \n");
		return $resultArray;
		
	}
	
	public function getProfileImageUrl( Array $args )
	{
		$requiredParams = array('id');
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		if( !array_key_exists('type', $args) )
			$args['type'] = 'large';
		
		return Atmail_Provider_SocialNetwork_Facebook::FB_URL . $args['id'] . "/picture?access_token=" . $this->userAuthedToken . "&type=" . $args['type'];
		
	}
	
	public function getProfileImage( Array $args )
	{
		
		$requiredParams = array('id');
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		if( !array_key_exists('type', $args) )
			$args['type'] = 'large';
		try 
		{
			return $this->_get($args['id'] . "/picture", "type=" . $args['type'], false);
		} 
		catch( Exception $e) 
		{

			return 'Failed: Unable to reach Facebook servers.';

		}

	}
	
	public function getFriendPresence(  Array $args )
	{
		$requiredParams = array('id');

		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		
		if( is_array($args['id']) )
			$uids = $args['id'];
		else
			$uids = array($args['id']);
			
		try {
			$result = array();
			$uidStr = '';
			foreach($uids as $uid)
			{
				$uidStr = 'uid=' . $uid . '+OR+';
			}
			$uidStr = rtrim($uidStr, '+OR+');
			
			$response = $this->_get("me/fql", "q=SELECT+online_presence+FROM+user+WHERE+" . $uidStr);
			if($response !== false && isset($response['data']))
			{
				$a=0;
				foreach($response['data'] as $data)
				{
					$result[$uids[$a++]] = $data['online_presence'];
				}
				return $result;
			}
			return array();
		
		} catch( Exception $e) {
		
			return array('Failed: Unable to reach Facebook servers. ' . $e->getMessage() );
		
		}
		return;
	}
	
	public function getFriendsStatus(  Array $args  )
	{

		$requiredParams = array('id');
//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		
		if( is_array($args['id']) )
			$ids = $args['id'];
		else
			$ids = array($args['id']);
		$statuses = array();
		foreach( $ids as $id )
		{
			$resultArray = $this->get( array('id' => $id, 'folder' => 'posts', 'limit' => '1') );
//Zend_Registry::get('log')->debug( "\n" . print_r($resultArray, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$resultArray \n");
			$row = $resultArray['data'][0];
			$message = (!empty($row['message'])?$row['message']:(!empty($row['caption'])&&!empty($row['description'])?$row['caption'] . " " . $row['description']:(!empty($row['name'])?$row['name']:'')));
			$statuses[] = array(
				'id' => $id, 
				'oid' => $resultArray['data'][0]['id'], 
				'LastMessageType' => 'Facebook', 
				'LastMessage' => $message,
				'Presence' => 'Unknown',
				'LastMessageDatetime' => Unix_to_MySQL_DATETIME_Locale(strtotime($resultArray['data'][0]['updated_time'])), 
				'timestampISO8601' => $resultArray['data'][0]['updated_time'], 
				'timestampRaw' => $resultArray['data'][0]['updated_time']
			);
		}
//Zend_Registry::get('log')->debug( "\n" . print_r($statuses, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$statuses \n");

		if( is_array($args['id']) )
			return $statuses;
		else
			return $statuses[0];
		
	}
	
	public function sendChatMessage($args)
	{
		
		//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		$requiredParams = array('to','message');
		foreach( $requiredParams as $requiredParam )
			if( !array_key_exists($requiredParam, $args ) )
				throw new Exception( __CLASS__ . "::" . __METHOD__ . "#" . __LINE__ . ' Called without required param: ' . $requiredParam);
		
		$chatConfig = array(
			'app_id' => $this->appId, 
			'uid' => $this->username, 
			'access_token' => $this->userAuthedToken, 
			//'debug' => true
		);
		$chatAPI = new Atmail_Provider_SocialNetwork_FacebookSimpleChat($chatConfig);
		
		if( 
			   $chatAPI->open_connection() 
			&& $chatAPI->prepareAuthenticatedSession(true) 
			&& $chatAPI->sendMessage($args['to'], $args['message'])
			&& $chatAPI->closeConnection()
			
		)
		{
			
			Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": Done sending message.");
			
		
		}
		else
		{
			
			$chatAPI->closeConnection();
			Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": Failed sending message: " . $chatAPI->errNo . ": " . $chatAPI->errStr);
			
			
		}
		return array("result" => "success");
		
	}

}