<?php
class Api_MailController extends Zend_Controller_Action 
{
	
	public function init()
	{
		//TODO: extend authentication to support multiple user levels/roles/groups 
		require_once 'application/models/api.php';
		$this->api = new api();
		
		$this->view->baseUrl = $this->_request->getBaseUrl();
		$this->view->appBaseUrl = $this->_request->getBaseUrl() . (strpos($this->_request->getBaseUrl(),'index.php')?'':'/index.php');
		$this->view->siteBaseUrl = Zend_Registry::get('siteBaseUrl');
		$this->view->moduleBaseUrl = $this->view->appBaseUrl . ($this->_request->module == 'default'?'':'/' . $this->_request->module);
		
		$this->_helper->viewRenderer->setNoRender();
		
		$this->restserver = new Zend_Rest_Server();
		$this->restserver->setClass('api');

		// Load all the params
		$this->requestParams = $this->getRequest()->getParams();

		// Use Cookie auth
		if( !Atmail_FormAuth::authenticated() )
		{
				return $this->_forward('timeout', 'mail', 'api', $this->requestParams);		
		}

		// Read from Zend-Auth
		$this->userData = Zend_Auth::getInstance()->getStorage()->read();
		$this->userData = Atmail_Password::processUser($this->userData);
			
		// Load the session
		$this->session = new Zend_Session_Namespace(ATMAIL_NAMESPACE);

		// Load the system settings
		$this->_globalConfig = Zend_Registry::get('config')->global;

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

		$this->log = Zend_Registry::get('log');
		
		// Used to determine the contact in the global addressbook
		$this->view->Account = $this->userData['Account'];

		// Load the mail class
		//handle folder change requests here (allowing change from all actions/events) so that correct cache can be loaded (correct folder)
		$this->_currentConfig = array();

		if( isset($this->view->requestParams['refresh']) )
		{
			$this->_currentConfig['cacheRefresh'] = $this->view->requestParams['refresh'];
		}

		if( isset($this->view->requestParams['selectFolder']) && $this->view->requestParams['selectFolder'] != 'undefined' )
		{
			$selectFolder = urldecode($this->view->requestParams['selectFolder']);
			$this->_currentConfig['folder'] = $selectFolder;
			if( isset($this->session->pageNumber) )
			{
				$this->session->pageNumber = 1;
			}
		}

		//set up mail store config to connect directly to correct folder if about to exec a move action
		if( isset($this->view->requestParams['fromFolder']) )
		{
			$fromFolder = urldecode($this->view->requestParams['fromFolder']);
			$this->_currentConfig['folder'] = $fromFolder;
			if( isset($this->session->pageNumber) )
			{
				$this->session->pageNumber = 1;
			}
		}

		$this->_mailStoreConfig = array_merge($this->_globalConfig, $this->userData, $this->_currentConfig, $this->view->UserSettings);
		if( isset($this->view->UserSettings['ThreadLimit']) )
		{

			$this->_mailStoreConfig['threadsLimitMonths'] = $this->view->UserSettings['ThreadLimit'];

		}

		//check if SSL enabled in UserSettings
		$this->_mailStoreConfig['ssl'] = ($this->_mailStoreConfig['UseSSL']=='1'?'SSL':'');

		$this->AtmailMailStorage = Atmail_Mail_Storage::getInstance($this->_mailStoreConfig);
		$this->AtmailMailStorageMain = &$this->AtmailMailStorage->getMailStore($this->_mailStoreConfig['namespaceName']);

		// Set thread support on/off from server response - Will be false if server does not support it
		$this->AtmailMailStorageMain->setThreadsEnabled( $this->view->UserSettings['ViewThreads'] );
						
	}

	public function authAction() {
		
		$status['failed'] = 0;
		$status['message'] = "OK";
		$status['Account'] = $this->view->Account;
		
		// Our message folder stat after select (new,total,unread)
		$status['folderStat'] = $this->AtmailMailStorageMain->_folderStat;
		
		// If we are a JSONP request, wrap in a function
		if( $this->requestParams['jsoncallback'] && !empty($this->_globalConfig['jsonpAPI']) )
			$json =  $this->requestParams['jsoncallback'] . '(' . Zend_Json::encode($status) . ')'; 
		else {
			// Otherwise return as a JSON array
			$json = '(' . Zend_Json::encode($status) . ')';
		}
		
		$this->getResponse()->setHeader('Content-Type','application/x-javascript')->appendBody($json);
		$this->_helper->viewRenderer->setNoRender();
		
		
	}
	
	
	public function indexAction() {
		//$this->restserver->handle( array('method' => 'index') );
			
	}
	
	public function createAction() {
		$params = $this->getRequest()->getParams();
		//$params['method'] = 'domainCreate';		
		//$this->restserver->handle($params);
	}

	public function searchAction() {

        $preparedSearchQuery = array( );
        $searchQueryUTF8 = urldecode( urldecode( $this->requestParams['searchQuery'] ) ); //POSTed (UT uses GET)
        $words = preg_split("[ ]", $searchQueryUTF8);

        foreach($words as $word)
        {
            $preparedSearchQuery[] = array('field' => 'text', 'value' => $word);
        }

        $searchResults = $this->AtmailMailStorageMain->search($preparedSearchQuery);
        if( is_array($searchResults) )
        {

            $searchResults = array_reverse($searchResults);
            $searchResultsChunks = array_chunk($searchResults,50);
            $searchResults = $searchResultsChunks[0];

        }
        else
        {

            $searchResults = array();

        }

        //get headers for the list of results
        if( count($searchResults) > 0 )
        {

            $results = $this->AtmailMailStorageMain->getBasicHeaders($searchResults);

        }
        else
        {

            $results = array();

        }


        $messagesC = count( $results );

        $arr = array();

        for($a=0 ; $a< $messagesC ; $a++ )
        {

            // Index, based on the users email ( from our contacts ) - Retrieve only one email thread currently
            $email = array();
            $email['UID'] = $results[$a]['UID'];
            $email['basicHeaders'] = $results[$a]['_basicHeaders'];
            $email['preview'] = $results[$a]['_preview'];

            $arr[] = $email;

        }

        $this->renderJson($arr);

	}

	public function listAction(){

		$limit = $this->view->UserSettings['MsgNum'];

		if(empty($limit))
			$limit = 3;

		$range = $this->requestParams['range'];

		if(empty($range))
			$range = 1;

		//if( !empty($this->requestParams['folder']) )
		//	$this->AtmailMailStorageMain->selectFolder($this->requestParams['folder']);

		$folder = $this->requestParams['folder'];

		if($folder)
		{
			try
			{
				$this->AtmailMailStorageMain->selectFolder($folder);
			}
			catch(Atmail_Exception $e)
			{
				$this->renderFail($e);
				return;
			}
		}
		$this->view->messages = $this->AtmailMailStorageMain->getBasicHeadersPage($range, $limit);

		$messagesC = count($this->view->messages);
		$arr = array();
		for($a = 0; $a < $messagesC; $a++)
		{
			// Index, based on the users email ( from our contacts )
			//$email = $this->view->messages[$a]['_basicHeaders']['email'];

			$arr[] = array(
				'basicHeaders' 	=> $this->view->messages[$a]['_basicHeaders'],
				'preview' 		=> $this->view->messages[$a]['_preview'],
				'UID' 			=> $this->view->messages[$a]['UID'],
			);

		}

		$this->renderJson($arr);

	}
	
	// View a message and thread
	public function viewAction() {

		// Open the requested folder
		$this->view->folderUTF7 = urldecode( $this->requestParams['folder'] );
		Zend_Registry::get('log')->debug( "\n" . print_r($this->requestParams, true) . "\n" . __METHOD__ . ' #' . __LINE__ . ": \$this->requestParams \n");

		$this->requestParams['threadsEnabled'] = false; //(array_key_exists('threadsEnabled', $this->requestParams) ? $this->requestParams['threadsEnabled'] : false);
		
		if($this->requestParams['threadsEnabled'])
		{
			// Retrieve the thread index for the selected message
			$this->AtmailMailStorageMain->threadsSupported(); //inits some thread related object vars
			$this->view->thread = $this->AtmailMailStorageMain->getThread( $this->requestParams['uniqueId'] );

			// Get all the UIDs in the message thread
			$allThreadUIDs = $this->AtmailMailStorageMain->recursivelyGetAllThreadUIDs($this->view->thread);

			// Reverse the order, from old > new ( to appear in the UI )
			$allThreadUIDs = array_reverse($allThreadUIDs);

			// Append the thread array, so we can determine if any new messages in the state
			// Output the list of messages related to the thread
			$this->log->debug( "UIDS = " . print_r($allThreadUIDs, 1));

			// Loop through each message in the conversation, and fetch the entire message content
			foreach($allThreadUIDs as $UID)	{
				// Retrieve the entire message
				$message = &$this->AtmailMailStorageMain->getMessage($UID);
				// Build the response into a format we can parse, body, text, attachments, usable data
				$arr[] = messageHandling::returnPreparedMessageArray($message, array('tmpFolderBaseName' => users::getTmpFolder(), 'folder' => $this->view->folderUTF7, 'uniqueId' => $UID, 'unpackAllAttachments' => true));
			}

			$arr[0]['currentThread'] = $allThreadUIDs;
		}
		else
		{
			require_once('class.html2text.inc');
			require_once('Mail/RFC822.php');
			$rfc822 = new Mail_RFC822;


			// no threads enabled
			// Retrieve the entire message
			$uniqueIds = $this->requestParams['uniqueId'];
			if(!is_array($uniqueIds)) {
				$uniqueIds = array($uniqueIds);
			}

			$arr = array();

			foreach($uniqueIds as $uniqueId) {
				try{
					$message = &$this->AtmailMailStorageMain->getMessage(  $uniqueId );
					// Build the response into a format we can parse, body, text, attachments, usable data
					$messageArray = messageHandling::returnPreparedMessageArray($message, array('tmpFolderBaseName' => users::getTmpFolder(), 'folder' => $this->view->folderUTF7, 'uniqueId' =>  $uniqueId, 'unpackAllAttachments' => true));

					$html2text = new html2text($messageArray['bodyPreparedHtml']);
					$messageArray['bodyPreparedText'] = $html2text->get_text();

					$messageArray['UID'] = $messageArray['headers']['uniqueid'];

					$to_display = array();
					$emailObject = $rfc822->parseAddressList(stripslashes($messageArray['headers']['to']), null, false);
					foreach($emailObject as $email)
					{
						$to_display[] = strlen(str_replace('"','',$email->personal))==0? $email->mailbox . '@' . $email->host : $email->personal;
					}

					$messageArray['headers']['to_display'] = $to_display;

					$arr[] = $messageArray;
				}
				catch(Atmail_Exception $e) {
					continue;
				}
			}

		}

		$this->renderJson($arr);
	}

	// Return the number of messages in a thread, used for push notifications
	public function messagethreadAction() {
		
		// Open the requested folder
		$this->view->folderUTF7 = urldecode( $this->requestParams['folder'] );	
		
		// Retrieve the thread index for the selected message
		$this->AtmailMailStorageMain->threadsSupported(); //inits some thread related object vars
		$this->view->thread = $this->AtmailMailStorageMain->getThread( $this->requestParams['uniqueId'] );
		
		// Get all the UIDs in the message thread
		$allThreadUIDs = $this->AtmailMailStorageMain->recursivelyGetAllThreadUIDs($this->view->thread);

		// Reverse the order, from old > new ( to appear in the UI )
		$allThreadUIDs = array_reverse($allThreadUIDs);

		$currentThread = explode(",", $this->requestParams['currentThread']);
		
		// Compare the clients message index, compared to the server calculated index
		$diff = array_diff($allThreadUIDs, $currentThread);
		
		// If we have no new messages, do not return any new data
		if(count($diff) == 0) {
			
			//$this->getResponse()->setRawHeader('HTTP/1.1 304 Not Modified');

			// Build the JSON packet and return
			$arr = array();
			$arr = Zend_Json::encode($arr);
			$this->getResponse()->setHeader('Content-Type','application/x-javascript')->appendBody($arr);
			
		} else {
			
			// We have new messages, push them into the stack
			// Next, loop and push each new message into the stack
			
			// Loop through each message in the conversation, and fetch the entire message content
			foreach($diff as $UID)	{

				// Retrieve the entire message
				$message = &$this->AtmailMailStorageMain->getMessage($UID);

				// Build the response into a format we can parse, body, text, attachments, usable data
				$arr[] = messageHandling::returnPreparedMessageArray($message, array('tmpFolderBaseName' => users::getTmpFolder(), 'folder' => $this->view->folderUTF7, 'uniqueId' => $UID, 'unpackAllAttachments' => true));

			}

			$arr[0]['currentThread'] = $allThreadUIDs;

			// If we are a JSONP request, wrap in a function
			if( !empty($this->requestParams['jsoncallback']) && !empty($this->_globalConfig['jsonpAPI']) )
				$json =  $this->requestParams['jsoncallback'] . '(' . Zend_Json::encode($arr) . ')'; 
			else {
				// Otherwise return as a JSON array
				$json = Zend_Json::encode($arr);		
			}

			// Build the JSON packet and return
			$this->getResponse()->setHeader('Content-Type','application/x-javascript')->appendBody($json);
			
		}
		
		
		$this->_helper->viewRenderer->setNoRender();
		
	}

	// Send message action
	public function sendAction() {

		// Compose the email message, based on the arguments from the WebUI
		$compose = new compose( array('Account' => $this->userData['Account'], 'helper' => $this->_helper, 'view' => $this->view) );

		$arr = $compose->sendMessage( $this->requestParams );

		$this->renderJson($arr);

	}

	private function expandThread3($allThreadUIDs, $arr=array()) {

		if($allThreadUIDs['UID'])
			$this->log->debug("UID = " . $allThreadUIDs['UID']);

		foreach($allThreadUIDs as $child)	{
	
			if($child['_children'])
				return $this->expandThread3($child['_children']);

		}

}
	
	private function expandThread2($threadNode, $arr=array()) {
		
		if( isset($threadNode['_children']) ) { 
			foreach( $threadNode['_children'] as $child ) {

				//$this->log->debug("In another deep for " . print_r($child, 1));
				if( isset($child['UID']) )
					$arr[] = $child['UID'];
				
				$arr[] = $this->expandThread2($child, $arr);
		 
				//return $arr;
				
			}
		} 
		
		
		$arr[] = $threadNode['UID'];
		
		return $arr;
	}
	
	private function expandThread($threadNode) {
		
		$arr = array();
				
		if( count($threadNode['_children']) > 0 )
		{			
			// We have children beneth us
			return $this->expandThread($threadNode['_children']);
			
		} else {
			// We are one level deep
			foreach($threadNode as $name => $value)	{
				
				if($name == '_preview')
					$arr[]['_preview'] = $value;

				if($name == '_basicHeaders')
					$arr[]['_basicHeaders'] = $value;
				
			}

		}
		
		return $arr;
				
	}
	
	public function deleteAction() {
		// Delete a specific message
	
	}
    
	public function statusAction() {
		// Return total, new, unread messages ( In the Inbox )
		$status = array();

		// Connect to the IMAP server
		$arr = $this->AtmailMailStorageMain->connect();

		// If we are a JSONP request, wrap in a function
		if( isset($this->requestParams['jsoncallback']) && $this->requestParams['jsoncallback'] && !empty($this->_globalConfig['jsonpAPI']) )
			$json =  $this->requestParams['jsoncallback'] . '(' . Zend_Json::encode($arr) . ')'; 
		else {
			// Otherwise return as a JSON array
			$json = Zend_Json::encode($arr);		
		}
			
		// Build the JSON packet and return
		$this->getResponse()->setHeader('Content-Type','application/x-javascript')->appendBody($json);
		$this->_helper->viewRenderer->setNoRender();
		
	}

	public function timeoutAction() {
		$status['failed'] = 1;
		$status['message'] = "Cannot login - Session expired";
		
		// If we are a JSONP request, wrap in a function
		if( isset($this->requestParams['jsoncallback']) && $this->requestParams['jsoncallback'] && !empty($this->_globalConfig['jsonpAPI']) )
			$json =  $this->requestParams['jsoncallback'] . '(' . Zend_Json::encode($status) . ')'; 
		else {
			// Otherwise return as a JSON array
			$json = Zend_Json::encode($status);		
		}
		
		$this->getResponse()->setHeader('Content-Type','application/x-javascript')->appendBody($json);
		$this->_helper->viewRenderer->setNoRender();
		
	}

	// MOBILE UI FUNCTIONS

    public function renderJson($arr)
    {
        if( isset($this->requestParams['jsoncallback']) && $this->requestParams['jsoncallback'] && !empty($this->_globalConfig['jsonpAPI']) )
            $json =  $this->requestParams['jsoncallback'] . '(' . Zend_Json::encode($arr) . ')';
        else {
            // Otherwise return as a JSON array
            $json = Zend_Json::encode($arr);
        }

        $this->getResponse()->setHeader('Content-Type','application/x-javascript')->appendBody($json);
        $this->_helper->viewRenderer->setNoRender();
    }

    public function renderSuccess()
    {
        $this->renderJson(array(
            "result" => "success",
        ));
    }

    public function renderFail(Atmail_Exception $e)
    {
        $this->renderJson(array(
            "result" => "failed",
            "error" => $e->getMessage(),
        ));
    }
	
	public function doJsonResponse($arr, $needJSONP) {
		// If we are a JSONP request, wrap in a function
		if( $needJSONP )
			$json =  $this->requestParams['jsoncallback'] . '(' . Zend_Json::encode($arr) . ')';
		else {
			// Otherwise return as a JSON array
			$json = Zend_Json::encode($arr);
		}

		// Build the JSON packet and return
		$this->getResponse()->setHeader('Content-Type','application/x-javascript')->appendBody($json);
		$this->_helper->viewRenderer->setNoRender();
	}

	public function listfolderAction()
	{
		$foldersObject = $this->AtmailMailStorageMain->getFolders();
		$folders = new RecursiveIteratorIterator($foldersObject, RecursiveIteratorIterator::SELF_FIRST);

		$arr = array();

		$key = "";

		foreach($folders as $c => $v) {

			$arr[] = array(
				'localName' => $v->getLocalName(),
				'globalName' => $v->getGlobalName(),
				'selectable' => $v->isSelectable(),
				'isMainFolder' => in_array($v->getLocalName(), array('INBOX','Drafts','Sent','Spam','Trash'))? 1 : 0,
			);

			if($folders->hasChildren()) {
				$folders->getChildren();

			}

		}

		$this->renderJson($arr);
	}

	public function folderinfoAction()
	{
		$folder = $this->requestParams['folder'];
		if($folder)
		{
			try
			{
				$this->AtmailMailStorageMain->selectFolder($folder);
				$info = $this->AtmailMailStorageMain->countMessages();
				$this->renderJson($info);
				return;
			}
			catch(Atmail_Exception $e)
			{
				$this->renderFail($e);
				return;
			}
		}
	}

    public function settingsAction()
    {
        $UserSettings = Zend_Registry::get('UserSettings');

		require_once('class.html2text.inc');
		$html2text = new html2text($UserSettings['Signature']);
		$UserSettings['Signature'] = $html2text->get_text();
        $this->renderJson($UserSettings);
    }
}
