<?php

class Atmail_Provider_SMS_Virtualprovider1 extends Atmail_Provider_SMS_Abstract
{


	/* 
		For purposes of proof of concept we need a 3rd party service we can query for voice mails. 
		Twilio is suitable, except that they dont house the VM info for us, they want to call a partner script to 
		log the messages (they only host the VM file) so we will need to impliment a mini provider server to 
		answer queries for current VM, get, delete etc.
		
		N.B. with RAD parts of the client server seperation concept have become merger due to implimenting a virtual service (MySQL so made sense to talk to "server" via SQL layer for speed of development).
		Obviously in final implimentation of a real service, what has been learned in this process must be applied into a cleanly seperated client server model
		where Server will do all the communication to the external service, and client is the local cached/archived data acquired from such server layer 
		e.g. SWL table must be split or modded to server client purposes only (cached/archived VM content, transcriptions, readFlag etc.)

	*/
	public $fieldMap = array('oid' => 'id', 'from' => 'SMSFrom', 'to' => 'SMSTo', 'received' => 'MessageDate', 'message' => 'Message' ); //maps public field names to internal field names
	
	public function __construct( Array $configArray )
	{
		
//Zend_Registry::get('log')->debug( "\n" . print_r($configArray, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$configArray \n");
		
		$this->dbAdapter = Zend_Registry::get('dbAdapter');
		$this->PhoneNumber = $configArray['PhoneNumber'];
		$this->Account = $this->_config['Account'];
		//$this->userData = Zend_Auth::getInstance()->getStorage()->read();
		//$this->Account = $this->userData['Account'];
		if( !parent::__construct($configArray) )
			return false;

	}
	
	public function create( Array $args = array() )
	{
		
		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");
		Zend_Registry::get('log')->debug( "\n" . print_r($this->_config, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$this->_config \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['from']))
			$args['from'] = $this->PhoneNumber;
		$url = 'http://www.smsglobal.com/http-api.php?action=sendsms&user=' . rawurlencode($this->_config['AuthorizationName']) . '&password=' . rawurlencode($this->_config['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);
		Zend_Registry::get('log')->debug( "\n" . print_r($result, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$result \n");
		
		if( strpos($result, 'OK') !== false)
			return array_merge($args, array('response' => array('message' => $this->store( array('from' => $args['from'], 'to' => $args['to'], 'message' => $args['message'], 'Account' => $this->Account))), 'status' => 'success') );
		else
			return array_merge($args, array('response' => array('message' => "Failed sending SMS"), 'status' => 'failed' ) );
			

		// After sending an SMS, need to add to the index ( So Sent visible )
		//TODO: also store service used to send the message.
		return true;
		
	}
	
	public function getList( Array $args = array() )
	{

		//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		$whereExtra = "";
		if( !empty($args['from']) )
		{
			$whereExtra .= " AND (";
			if( !is_array($args['from']) )
				$args['from'] = array($args['from']);
			foreach( $args['from'] as $from )
			{
				
				$whereExtra .= "SMSFrom = " . $this->dbAdapter->quote($from) . " OR ";
			}
			$whereExtra .= "FALSE ) ";
			
		}
		$q = "SELECT *, UNIX_TIMESTAMP(MessageDate) AS MessageDateUnix 
		FROM SMS 
		WHERE ( SMSFrom = " . $this->dbAdapter->quote($this->PhoneNumber) . " OR SMSTo = " . $this->dbAdapter->quote($this->PhoneNumber) . " ) 
		" . $whereExtra . "
		GROUP BY id 
		ORDER BY id";
//Zend_Registry::get('log')->debug( "\n" . print_r($q, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$q \n");
		
		$rows = $this->dbAdapter->fetchAll($q);
		foreach( $rows as &$row )
		{
			
			$row['MessageDate'] = date('r',$row['MessageDateUnix']);
			$row['MessageDateISO8601'] = date('c',$row['MessageDateUnix']);
			foreach( $this->fieldMap as $public => $internal )
			{
				if( $public != $internal )
				{
					$row[$public] = $row[$internal];
					unset($row[$internal]);
				}
			}
			unset($row['Account']);
			unset($row['MessageDateUnix']);
		}
		return array_merge($args, array("status" => "success", "totalNumberOfItems" => count($rows), "page" => 1, "itemsPerPage" => count($rows), "serviceData" => $rows) );
		
	}
	
	public function getSummary( Array $args = array() )
	{

		//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		//Zend_Registry::get('log')->debug( "\n" . print_r($this->PhoneNumber, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$this->PhoneNumber \n");
		if( !empty($args['searchFuzzy']) )	
		{

			foreach( array('SMSFrom', 'SMSTo', 'Message') as $v )
				$searchTerms[] = "$v LIKE " . $this->dbAdapter->quote('%' . $args['query'] . '%');

			$searchTerms = implode(" OR ", $searchTerms);
		}
		else
			$searchTerms = "TRUE";
			//carriers will only know 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( $args['Account'], $args['Account'], $this->PhoneNumber ));
		$rows = $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->PhoneNumber,$this->PhoneNumber,$this->PhoneNumber) );

		foreach( $rows as &$row )
		{
			
			$row['MessageDate'] = date('r',$row['MessageDateUnix']);
			$row['MessageDateISO8601'] = date('c',$row['MessageDateUnix']);
			foreach( $this->fieldMap as $public => $internal )
			{
				if( $public != $internal )
				{
					$row[$public] = $row[$internal];
					unset($row[$internal]);
				}
			}
			unset($row['Account']);
			unset($row['MessageDateUnix']);
		}
		return array_merge($args, array("status" => "success", "totalNumberOfItems" => count($rows), "page" => 1, "itemsPerPage" => count($rows), "serviceData" => $rows) );
		
	}

	public function getThread( Array $args = array() )
	{
        
//Zend_Registry::get('log')->debug( "\n" . print_r($args, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$args \n");
		
		if( !array_key_exists('from', $args) )
			throw new Exception("Error: need (from phone number resolved from Abook.id) in order to get thread of messages sent to or from that number");
		
		
		$q = "SELECT *, UNIX_TIMESTAMP(MessageDate) AS MessageDateUnix 
		FROM SMS WHERE "; 
		
		if( !is_array($args['from']) )
			$args['from'] = array($args['from']);
		foreach( $args['from'] as $from )
		{
			$q .= "	( SMSFrom = " . $this->dbAdapter->quote($this->PhoneNumber) . " AND SMSTo = " . $this->dbAdapter->quote($from) . " ) OR 
				( SMSTo = " . $this->dbAdapter->quote($this->PhoneNumber) . " AND SMSFrom= " . $this->dbAdapter->quote($from) . ") OR ";
		}
		$q .= " FALSE 
		GROUP BY id 
		ORDER BY id";

//Zend_Registry::get('log')->debug( __METHOD__ . ' #' . __LINE__ . ": \$q = \n" . $q);
		
		$rows = $this->dbAdapter->fetchAll($q);
	    foreach( $rows as &$row )
		{
			
			$row['MessageDate'] = date('r',$row['MessageDateUnix']);
			$row['MessageDateISO8601'] = date('c',$row['MessageDateUnix']);
			
			foreach( $this->fieldMap as $public => $internal )
			{
				if( $public != $internal )
				{
					$row[$public] = $row[$internal];
					unset($row[$internal]);
				}
			}
			unset($row['Account']);
			unset($row['MessageDateUnix']);
		}
		return array_merge($args, array("status" => "success", "totalNumberOfItems" => count($rows), "page" => 1, "itemsPerPage" => count($rows), "serviceData" => $rows) );
		
	}
	
	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();
		foreach( $rows['serviceData'] as $row )
		{
			
			$ts = UnixGMTToISO8601TZ( strtotime($row['created_at']) );
			$stream[] = array(
				'pid' => $args['pid'], 
				'providerType' => 'SMS', 
				'providerName' => 'Virtualprovider1', 
				'providerDescription' => 'Main SMS Account', 
				'id' => $row['oid'], 
				'receivedDateISO8601' => $row['MessageDateISO8601'],
				'timeAgo' => timeago(strtotime($row['MessageDateISO8601'])),
				'seen' => 'false', 
				'from' => array(
					'id' => null,
					'name' => null, 
					'phoneNumber' => $row['from']
				),
				'subject' => null,
				'messageType' => 'SMS', 
				'summary' => $row['message'],
				'avatar' => null
			);
			
		}
		return $stream;
		
	}

	public function getInfo( Array $args = array() )
	{
		return null;
	}
	
	public function delete( Array $args )
	{
		
		//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
		if( array_key_exists('id', $args) )
			$numberOfAffectedRows = $this->dbAdapter->query("DELETE FROM SMS WHERE ( SMSFrom=? AND id=? ) OR ( SMSTo=? AND id=? )", array( $this->PhoneNumber, $args['id'], $this->PhoneNumber, $args['id'] ));
		else
			$numberOfAffectedRows = $this->dbAdapter->query("DELETE FROM SMS WHERE ( SMSFrom=? AND SMSTo=? ) OR ( SMSTo=? AND SMSFrom=? )", array( $this->PhoneNumber, $args['from'], $this->PhoneNumber, $args['from'] ));
		
		if( $numberOfAffectedRows == 0 )
			return array_merge($args, array('response' => array('message' => "Failed deleting SMS(s) " . $name), 'status' => 'failed' ) );
		else if( $numberOfAffectedRows == 1 )
			return array_merge($args, array('response' => array('message' => "SMS deleted"), 'status' =>'success') );
		else
			return array_merge($args, array('response' => array('message' => "SMS conversation deleted"), 'status' =>'success') );
		

	}
	
	private function store( $args = array() )
	{

//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");
		
		$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_merge($args, array('response' => array('message' => "SMS added"), 'status' =>'success') );
		else
			return array_merge($args, array('response' => array('message' => "Failed adding SMS"), 'status' => 'failed') );

	}
	
	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;
		
	}

	
}
