<?php
 /**
 * @category   Atmail
 * @package	Carrier API model
 * @author	 Ben Duncan ben@staff.atmail.com
 * @license	Copyrighted by Atmail 2010
 */

/*
	TODO: split serviceprovider interfaces out into their own library/serviceprovider/ files as serviceprovider service plugins
	rather not use library or models folders, rather use custom serviceprovider plugins folder
*/

class serviceproviderapi
{

	private $directApi;
	private $dbTables;
	private $myAccounts = null;

	public function __construct( Array $args=array() )
	{

		$this->dbTables = new dbTables();
		$this->dbAdapter = Zend_Registry::get('dbAdapter');
		$this->config = Zend_Registry::get('config');
	    
		if( !empty($args['Account']) )
			$this->Account = $args['Account'];
		else
			$this->Account = null;
		
		$this->myAccounts = $this->listAccounts();
		
		//$this->myNumber = $this->myAccounts[0]['PhoneNumber'];
		$this->myNumber = $this->findFirstNumberOfType('SMS');
		
		//'61417375417';
		
	}

	public function index()
	{

		return array( 'response' => array('message' => 'This API does not have a default method. Refer to documentation.'), 'status' => 'failed' );

	}
	
	public function setUserAccount( $Account )
	{
		
		$this->Account = $Account;
		
	}

	public function authenticate()
	{

		//redundant. ACL handled by parent
		if( $this->adminInfo == null )
			return $this->authenticationFailed();
		//api protected by application level ACL so only have to respond with success and optionally store auth for internal use
		return array( 'response' => array('message' => "Authentication success") );

	}

	public function authenticationFailed()
	{

		return array( 'response' => array('message' => 'Authentication failed'), 'status' => 'failed' );

	}

	public function error($message)
	{

		return array( 'response' => array('message' => $message), 'status' => 'failed' );

	}

	/***
		Account functions
	***/

	public function listAccounts()
	{
		
		if( $this->myAccounts != null )
			return $this->myAccounts;
		$this->myAccounts = $this->dbAdapter->fetchAll("select * from ServiceAccounts where Account=? AND Data!='TESTING'", array($this->Account));
		return $this->myAccounts;
		
	}

	public function getAccount( $pid )
	{
		
//Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": \$pid: " . $pid);
//Zend_Registry::get('log')->debug( "\n" . print_r($this->Account, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$this->Account \n");
//TODO: replace with filtered by Account
//$result = $this->dbAdapter->fetchAll("SELECT * FROM ServiceAccounts WHERE Account=? AND id=?", array($this->Account, $pid) );
$result = $this->dbAdapter->fetchAll("SELECT * FROM ServiceAccounts WHERE id=?", array($pid) );
//Zend_Registry::get('log')->debug( "\n" . print_r($result, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$result \n");
		if( count($result) == 0 )
		{
			
			$this->errorCodes[] = 1;
			$this->errorMessages[] = "Provider account not found.";
			return false;
			
		}
		$this->myNumber = $result[0]['PhoneNumber'];
		return $result[0];
	}
	
	public function addAccount( Array $row )
	{
		
//Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": \$row: " . print_r($row,true) );
		
		$newAccount = array();
		$newAccount['Account'] = $this->Account;
		
		$allowedFields = array("Type" , "Provider" ,"PhoneNumber" ,"DateAdded" ,"UserId" ,"Domain" ,"AuthorizationName" ,"Password" ,"DisplayName" ,"Data");
		foreach( $allowedFields as $field )
			if( array_key_exists($field,$row) )
				$newAccount[$field] = $row[$field];
				
		$newAccount['DateAdded'] = new Zend_Db_Expr('NOW()');
		
		if( $newAccount['Type'] == 'SMS' )
			$newAccount['SMS'] = '1';
		else
			$newAccount['SMS'] = '0';
		
		if( $newAccount['Type'] == 'Voicemail' )
			$newAccount['Voicemail'] = '1';
		else
			$newAccount['Voicemail'] = '0';
		
		if( $newAccount['Type'] == 'SIP' )
			$newAccount['SIP'] = '1';
		else
			$newAccount['SIP'] = '0';
		
		if( array_key_exists('Provider', $newAccount) )
			if( $newAccount['Provider'] == 'Facebook' || $newAccount['Provider'] == 'Twitter' )
				$newAccount['Type'] = 'SocialNetwork';

		// Check existance
		$sql = "select id from ServiceAccounts where `Account`=" . $this->dbAdapter->quote($this->Account) .
				" AND `Type`=" . $this->dbAdapter->quote($newAccount['Type']) .
				" AND `Provider`=" . $this->dbAdapter->quote($newAccount['Provider']);

		$dbres = $this->dbAdapter->fetchAll($sql);
		if(count($dbres)>0)
		{
			$lastInsertId = $dbres[0]['id'];
		}
		else
		{
			$this->dbAdapter->insert("ServiceAccounts", $newAccount );
			$lastInsertId = $this->dbAdapter->lastInsertId();
		}

		//Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": \$lastInsertId = " . $lastInsertId);
		return $lastInsertId;
		
	}
	
	public function updateAccount( Array $row )
	{
		
//Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": \$row: " . print_r($row,true) );
		if( array_key_exists('DataAdded', $row) )
			unset($row['DataAdded']);
		$newAccount['Account'] = $this->Account;
		
		$allowedFields = array("Type", "Provider", "PhoneNumber", "UserId", "Domain", "AuthorizationName", "Password", "DisplayName", "Data");
		foreach( $row as $field )
			if( !array_key_exists($field,$allowedFields) )
				unset($row[$field]);
				
		//??
		//$result = $this->dbAdapter->query("select * from ServiceAccounts where UserID = " . $this->dbAdapter->quote($row['UserId']) . " and Account = " . $this->dbAdapter->quote($this->Account))->fetchAll();
		
		//??
		//delete duplicates
		//$this->dbAdapter->query('delete from ServiceAccounts where UserId = ' . $this->dbAdapter->quote($row['UserId']) . " and Account = " . $this->dbAdapter->quote($this->Account));

		$result = $this->dbAdapter->update("ServiceAccounts", $row, array($this->dbAdapter->quoteInto('id = ?', $row['id']), $this->dbAdapter->quoteInto('Account = ?', $this->Account))  );
		
		return true;
		
	}
	
	public function deleteAccount( $pid )
	{

		$result = $this->dbAdapter->delete("ServiceAccounts", array($this->dbAdapter->quoteInto('id = ?', $pid), $this->dbAdapter->quoteInto('Account = ?', $this->Account))  );
		return true;

	}

	/**
	 * SMS functions
	 */

	public function smsDelete( $params ) //deletes a conversation
	{
		$this->myNumber = $this->findFirstNumberOfType('SMS');
//file_put_contents("/usr/local/atmail/webmail/log/serviceprovider.log", " myNumber: " . $this->myNumber . "\n", FILE_APPEND);
//file_put_contents("/usr/local/atmail/webmail/log/serviceprovider.log", " SMSFrom: " . $params['SMSFrom'] . "\n", FILE_APPEND);
//Zend_Registry::get('log')->debug( "\n" . print_r($params, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$params \n");
//Zend_Registry::get('log')->debug( "\n" . print_r($this->myNumber, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$this->myNumber \n");
		
		//CONSIDER: changing how this works to to store a copy of incoming to each accountNumber owner so that each owner can delete their own copy of a specific incoming message without others going missing
		$numberOfAffectedRows = $this->dbAdapter->query("DELETE FROM SMS WHERE ( SMSFrom=? AND SMSTo=? ) OR ( SMSTo=? AND SMSFrom=? )", array( $this->myNumber, $params['SMSFrom'], $this->myNumber, $params['SMSFrom'] ));

		if( $numberOfAffectedRows == 1 )
			return array('response' => array('message' => "SMS conversation deleted"), 'status' =>'success');	
		else
			return array('response' => array('message' => "Failed deleted SMS " . $name), 'status' => 'failed' );
		
	}

	public function smsList( $params )
	{
		
		$this->myNumber = $this->findFirstNumberOfType('SMS');
		if( !empty($params['searchFuzzy']) )	
		{
		
			foreach( array('SMSFrom', 'SMSTo', 'Message') as $v )
				$searchTerms[] = "$v LIKE " . $this->dbAdapter->quote('%' . $params['query'] . '%');
		
			$searchTerms = implode(" OR ", $searchTerms);

			//serviceproviders will only know to msisdn and wont know account ( msisdn can logically be the secure where clause) (also allows e.g. sales teal having access to all business sms shared boxes)//$arr = $this->dbAdapter->fetchAll("select SMS.SMSFrom as SMSFromCnt, SMS.*, (select count(id) from SMS where Account=? and SMSFrom=SMSFromCnt) as SMSCount from SMS where Account=? and SMSTo=? and ($searchTerms) Group by SMSFrom order by id desc", array( $params['Account'], $params['Account'], $this->myNumber ));
			//$arr = $this->dbAdapter->fetchAll("select SMS.SMSFrom as SMSFromCnt, SMS.*, (select count(id) from SMS where SMSFrom=SMSFromCnt) as SMSCount from SMS where SMSTo=? and ($searchTerms) Group by SMSFrom order by id desc", array( $this->myNumber ));
			//$arr = $this->dbAdapter->fetchAll("select SMS.SMSFrom as SMSFromCnt, SMS.*, (select count(id) from SMS where SMSFrom=SMSFromCnt AND SMSTo=?) as SMSCount from SMS where SMSTo=? and ($searchTerms) Group by SMSFrom order by id desc", array( $this->myNumber,  $this->myNumber ));
			//$arr = $this->dbAdapter->fetchAll("SELECT  `SMSFrom`, `SMSTo`, `Message`, UNIX_TIMESTAMP(MessageDate) AS MessageDateUnix, MessageDate FROM SMS WHERE id IN (SELECT MAX(id) FROM SMS WHERE SMSTo=? AND ($searchTerms) GROUP BY SMSFrom) ORDER BY MessageDate DESC", array($this->myNumber) );
			//  /*
			$arr = $this->dbAdapter->fetchAll("SELECT *, UNIX_TIMESTAMP(MessageDate) AS MessageDateUnix FROM SMS WHERE id IN ( 
SELECT MAX(id) AS id FROM SMS WHERE SMSTo=? AND ($searchTerms) GROUP BY SMSFrom 
UNION 
SELECT MAX(id) AS id FROM (SELECT id, SMSTo FROM SMS as S1 WHERE SMSFrom=? AND ($searchTerms) AND 0 = (SELECT COUNT(*) FROM SMS WHERE SMSFrom = S1.SMSTo AND SMSTo=?)) S2 GROUP BY SMSTo
)
ORDER BY MessageDate DESC", array($this->myNumber,$this->myNumber,$this->myNumber) );
			// */
			
		}
		else
		{
		
			//$arr = $this->dbAdapter->fetchAll("select SMS.SMSFrom as SMSFromCnt, SMS.*, (select count(id) from SMS where SMSFrom=SMSFromCnt) as SMSCount from SMS where SMSTo=? Group by SMSFrom order by id desc", array( $this->myNumber ));
			//$arr = $this->dbAdapter->fetchAll("select SMS.SMSFrom as SMSFromCnt, SMS.*, (select count(id) from SMS where SMSFrom=SMSFromCnt AND SMSTo=?) as SMSCount from SMS where SMSTo=? Group by SMSFrom order by id desc", array( $this->myNumber,  $this->myNumber ));
			//$arr = $this->dbAdapter->fetchAll("SELECT  `SMSFrom`, `SMSTo`, `Message`, UNIX_TIMESTAMP(MessageDate) AS MessageDateUnix, MessageDate FROM SMS WHERE id IN (SELECT MAX(id) FROM SMS WHERE SMSTo=? GROUP BY SMSFrom) ORDER BY MessageDate DESC", array($this->myNumber) );
			// /* 
			$arr = $this->dbAdapter->fetchAll("SELECT *, UNIX_TIMESTAMP(MessageDate) AS MessageDateUnix FROM SMS WHERE id IN (
SELECT MAX(id) AS id FROM SMS WHERE SMSTo=? GROUP BY SMSFrom
UNION
SELECT MAX(id) AS id FROM (SELECT id, SMSTo FROM SMS as S1 WHERE SMSFrom=? AND 0 = (SELECT COUNT(*) FROM SMS WHERE SMSFrom = S1.SMSTo AND SMSTo=?)) S2 GROUP BY SMSTo
)
ORDER BY MessageDate DESC", array($this->myNumber,$this->myNumber,$this->myNumber) );
			// */
		
		}
	
	
		return $arr;

	}

	public function smsFetch( $params )
	{
		
		
		$this->myNumber = $this->findFirstNumberOfType('SMS');
//Zend_Registry::get('log')->debug( "\n" . print_r($params, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$params \n");
		//serviceproviders will only know to msisdn and wont know account ( msisdn can logically be the secure where clause) (also allows e.g. sales teal having access to all business sms shared boxes)
		$arr = $this->dbAdapter->fetchAll("select * from SMS where ( SMSFrom=? and SMSTo=? ) or ( SMSTo=? and SMSFrom=? ) group by id order by id", array( $this->myNumber, $params['id'], $this->myNumber, $params['id'] ));
	
		return $arr;

	}

	public function smsSend( $args )
	{

		$this->myNumber = $this->findFirstNumberOfType('SMS');
//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		//get first SMS enabled account if username and password not specified
//Zend_Registry::get('log')->debug( "\n" . print_r($this->myAccounts, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$this->myAccounts \n");
		if( empty($args['message']) && !empty($args['Message']) )
			$args['message'] = $args['Message'];
		if( empty($args['to']) && !empty($args['SMSTo']) )
			$args['to'] = $args['SMSTo'];
		if( empty($args['from']) && !empty($args['SMSFrom']) )
			$args['from'] = $args['SMSFrom'];
			
		if( empty($args['username']) || empty($args['password']) )
		{
			
			$foundSMSCapableAccount = false;
		        $args['username'] = '';
		        $args['password'] = '';
			foreach( $this->myAccounts as $myAccount )
				if( $myAccount['SMS'] == '1' )
				{
		                        $args['username'] = $myAccount['AuthorizationName'];
		                        $args['password'] = $myAccount['Password'];
		                        $args['Api'] = $myAccount['Provider'];
					$foundSMSCapableAccount = true;
					
				}
			if( !$foundSMSCapableAccount )
		                return array('response' => array('message' => "Failed sending SMS: Unable to find SMS capable account"), 'status' => 'failed' );
			
		}
		//according to SMSGlobal you must now drop the leading + from intle number format
		//if( substr($args['from'],0,1) == '+' )
		//	$args['from'] = substr($args['from'],1);
		//if( substr($args['to'],0,1) == '+' )
		//	$args['to'] = substr($args['to'],1);
		
		$url = 'http://www.smsglobal.com/http-api.php?action=sendsms&user=' . rawurlencode($args['username']) . '&password=' . rawurlencode($args['password']) . '&from=' . rawurlencode($args['from']) . '&to=' . rawurlencode($args['to']) . '&text=' . rawurlencode($args['message']);
//Zend_Registry::get('log')->debug( "\n" . print_r($url, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$url \n");
			$result = file_get_contents($url);
		//$result = '234';
//Zend_Registry::get('log')->debug( "\n" . print_r($result, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$result \n");
			

		//reclean up numbers
		if( substr($args['from'],0,1) != '+' )
			$args['from'] = "+" . $args['from'];
		if( substr($args['to'],0,1) != '+' )
			$args['to'] = "+" . $args['to'];
		
		// After sending an SMS, need to add to the index ( So Sent visible )
		//TODO: also store service used to send the message.
		$this->smsStore( array('from' => $args['from'], 'to' => $args['to'], 'message' => $args['message'], 'Account' => $this->Account ) );
		//TODO: propper responses
		return true;	

		}
	
	public function smsStore( $args = array() )
		{

			$this->myNumber = $this->findFirstNumberOfType('SMS');
//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		if( empty($args['message']) && !empty($args['Message']) )
			$args['message'] = $args['Message'];
		if( empty($args['to']) && !empty($args['SMSTo']) )
			$args['to'] = $args['SMSTo'];
		if( empty($args['from']) && !empty($args['SMSFrom']) )
			$args['from'] = $args['SMSFrom'];
//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		
		//clean up from and to
		if( substr($args['from'],0,1) != "+" )
			$args['from'] = "+" . $args['from'];
		if( substr($args['to'],0,1) != "+" )
			$args['to'] = "+" . $args['to'];
			
		$numberOfAffectedRows = $this->dbAdapter->insert("SMS", array(
			'Account' => $args['Account'], 
			'SMSTo' => $args['to'],
			'SMSFrom' => $args['from'],
			'Message' => $args['message'],
			'MessageDate' => new Zend_Db_Expr('NOW()')
						)
			);
			
		if( $numberOfAffectedRows == 1 )
			return array('response' => array('message' => "SMS added"), 'status' =>'success');
		else
			return array('response' => array('message' => "Failed adding SMS"), 'status' => 'failed' );

	}
	
	public function listAccountsOfType($type)
	{
		
		$this->listAccounts();
		$matches = array();
		foreach( $this->myAccounts as $row )
		{
			if( $type == $row['Type'] 
			|| ( $type == 'Voicemail' && $row['Voicemail'] == '1' )
			|| ( $type == 'SMS' && $row['SMS'] == '1' )
			|| ( $type == 'SIP' && $row['SIP'] == '1' )
			)
				$matches[] = $row;
		}   
		return $matches;
		
	}
	
	public function listAccountsOfProvider($provider)
	{
		
		$this->listAccounts();
		$matches = array();
		foreach( $this->myAccounts as $row )
		{
			if( $provider == $row['Provider'] )
				$matches[] = $row;
		}   
		return $matches;
		
	}
	
	private function findFirstNumberOfType($type)
	{
		
		//$this->myAccounts[0]['PhoneNumber']
		foreach( $this->myAccounts as $row )
		{
//Zend_Registry::get('log')->debug( "\n" . print_r($row, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$row \n");
				
			if( $type == 'Voicemail' && $row['Voicemail'] == '1' )
				return $row['PhoneNumber'];
			if( $type == 'SMS' && $row['SMS'] == '1' )
				return $row['PhoneNumber'];
			
				
		}   
		return '';
		
	}

}
