<?php
/*
* Copyright (c) 2009-2010 ATMAIL. All rights reserved
* See http://atmail.com/license.php for license agreement
*/

class Atmail_Mail_Storage
{
	private $_mailStoreConnections = array(); //Labled array of connections to mailstores
	private static $_instance;
   	
	public function __construct()
	{
		if( self::$_instance )
			throw new Exception('This ' . __CLASS__ . ' singleton class instance can only be created via getInstance()');
	}
	
	public function __clone()
	{
		throw new Exception('This ' . __CLASS__ . ' singleton class instance must not be cloned.');
	}   
	
	public function destroy()
	{
	    self::$_instance = null;
		$this->_mailStoreConnections = null; //TODO: make sure PHPs GC is running properly here when nulling stores  
	}
	
	public static function &getInstance($config)
	{
		// Zend_Registry::get('log')->info('getting Storage instance');
		if( !self::$_instance || array_key_exists('cacheRefresh', $config) ) {
		
			self::$_instance = new self();
			self::$_instance->singletonConstructor($config);
		}
		return self::$_instance;
	}
	
	private function singletonConstructor($config)
	{
		//makes connection to single mail store
		//to connect to multiple mail stores call setupMailStore multiple times with required config
		$this->setupMailStore($config);
	}
	
	/**
	*  factory to connect to required mailstores
	*  first try to load from cache else create new object and link
	*/
	public function setupMailStore($config)
	{
		// Zend_Registry::get('log')->info('setting up mailstore');

		//if UseSSL flag set
		if( isset($config['UseSSL']) )
			$config['ssl'] = ($config['UseSSL']=='1'?'SSL':'');
			
		if( isset($config['namespaceName']) )
		{
			$namespaceName = $config['namespaceName'];
		}
		$session = new Zend_Session_Namespace($namespaceName); // session used as seperate persistent store for if caching disabled
		if(!array_key_exists('folder', $config) || $config['folder'] == '') $config['folder'] = $session->folderNameCurrentGlobal;

		if( (!isset($config['cacheRefresh']) || (isset($config['cacheRefresh']) && $config['cacheRefresh'] != true) ) )
		{	    
			if($config['protocol'] == 'Maildir')
				$cachedObject = Atmail_Mail_Storage_Writable_Maildir::tryLoadFromCache($config); 
			elseif($config['protocol'] == 'POP3')
				$cachedObject = Atmail_Mail_Storage_Pop3LocalMaildir::tryLoadFromCache($config);
			elseif($config['protocol'] == 'IMAP')
				$cachedObject = Atmail_Mail_Storage_Imap::tryLoadFromCache($config);
			else
				throw new Atmail_Mail_Exception('Unable to create ' . $config['protocol'] . ' Mail store from cache. No handler exists.');
			if($cachedObject !== false) {
				
				Zend_Registry::get('log')->info('Found ' . $config['protocol'] . ' ' . (isset($config['folder'])?$config['folder']:'Storage') . ' in cache');
				$this->_mailStoreConnections[$config['namespaceName']] = $cachedObject;
				return $this->_mailStoreConnections[$config['namespaceName']];
			
			} else {
				
				// Zend_Registry::get('log')->info('No Cache found ' . $config['protocol'] . ' ' . (isset($config['folder'])?$config['folder']:'Storage'));
				
			}
		}
		// Zend_Registry::get('log')->debug('Unable to load from cache, so creating new');
				
		if($config['protocol'] == 'Maildir')
			$this->_mailStoreConnections[$config['namespaceName']] = new Atmail_Mail_Storage_Writable_Maildir($config); 
		elseif($config['protocol'] == 'IMAP')
			$this->_mailStoreConnections[$config['namespaceName']] = new Atmail_Mail_Storage_Imap($config);
		elseif($config['protocol'] == 'POP3') {
			//sometimes host temporary unavailable, try another 3 times to connect before failing
			for($a=0 ; $a < 4 ; $a++)
			{
				try {
					$this->_mailStoreConnections[$config['namespaceName']] = new Atmail_Mail_Storage_Pop3LocalMaildir($config);					 
				} catch (Exception $e) {
					if(strpos($e->getMessage(), 'cannot connect to host') !== false)
						continue; //go back to start of next for() pass
					else
						throw(new Atmail_Mail_Exception('Logon to email server failed: ' . $e->getMessage()));
				}
				break;
			}
		}
		else
			throw new Atmail_Mail_Exception('Unable to create ' . $config['protocol'] . ' Mail store. No handler exists.');
		if(!isset($this->_mailStoreConnections[$config['namespaceName']]))
			throw new Atmail_Mail_Exception('Unable to create ' . $config['protocol'] . ' Mail store: ' . $e->getMessage());// if throwing, will have $e
			
		// save the store
		$this->_mailStoreConnections[$config['namespaceName']]->saveCache();
				
		return $this->_mailStoreConnections[$config['namespaceName']]; 
	}
	
	public function &getMailStore($namespaceName = 0)
	{
		/*
		CONSIDER: 
		if(!isset($defaultNamespace->mailStoreConnections))
		{
			TODO: validate that config hasnt changed before getting stored session
			TODO: look at locking $_mailStoreConnections to prevent illegal access
		}
		*/
		if(isset($this->_mailStoreConnections[$namespaceName]))
			return $this->_mailStoreConnections[$namespaceName];
		else
			return $this->_mailStoreConnections;
	}
}
