<?php

/**
 * @category   Atmail
 * @package    Atmail_Controller
 * @subpackage Plugins
 * @copyright  Copyright (c) NetBased Software Pty Ltd
 * @license    http://atmail.com/wiki/doku.php?id=licensing:licensing
 * @author     Brad Kowalczyk <brad@staff.atmail.com>
 */
abstract class Atmail_Controller_Plugin extends Zend_Controller_Plugin_Abstract
{

    /**
     * @var Array List of events that the plugin is the final
     *            handler for
     */
    protected $_finalHandlerFor = array();

    
	/**
     * @var Array Array of PHP extension names that the
     *            plugin requires.
     */
    protected $_dependencies = array();
    
    
    /**
     * @var Array For future use. An array of features the plugin
     *            implements. In future releases there will be
     *            a set of "features" that a plugin can declare
     *            that it implements, allowing Atmail to ignore
     *            some of its core functionality as use the plugin
     *            instead.
     */
     
    protected $_pluginImplements = array();
    
    /**
     * @var String Human readable Plugin name
     */
    protected $_pluginFullName = '';
	
	/**
     * @var String Company (calculated from class name)
     */
    private $_pluginCompany = '';
    
    /**
     * @var String Plugin name (calculated from class name)
     */
    private $_pluginName = '';
	
    /**
     * @var String Author's name
     */
    protected $_pluginAuthor = '';

    /**
     * @var String URL for plugin webpage
     */
    protected $_pluginUrl = '';
    
    /**
     * @var String Description of plugin
     */
    protected $_pluginDescription = '';
    
    /**
     * @var String Copyright Info
     */
    protected $_pluginCopyright = '';
    
    /**
     * @var String Notes
     */
    protected $_pluginNotes = '';
    
    /** 
     * @var String Plugin's version string
     *             recommend x.x.x format but
     *             must be compatible with
     *             version_compare()
     */
    protected $_pluginVersion = '';
    
	/** 
     * @var String Plugin's compatibility with Atmail version
     *             recommend x.x.x format but
     *             must be compatible with
     *             version_compare()
     */
    protected $_pluginCompat = '';
    
	/**
     * @var String The Atmail module the plugin is for.
     *             Must be set to "mail", "admin" or "api"
     */
    protected $_pluginModule;
    
    protected $_controller;
    
    protected $_noAuthRequiredMethods = array();
    
    private $_atmailConfig;
    private $_atmailVersion;
    
    
    public function __construct( $pluginPathRelative = null )
	{

		if( $pluginPathRelative == null )
		{
			
			$pluginPathRelative = 'application' . DIRECTORY_SEPARATOR . 
								  'modules' . DIRECTORY_SEPARATOR . 
								  'mail' . DIRECTORY_SEPARATOR . 
								  'plugins' . DIRECTORY_SEPARATOR;
								
			
		}
		$className =  get_class($this);
		$_PluginPos = strpos($className, '_Plugin');
		if( $_PluginPos == false )
		{
			
			throw new Exception('Plugin does not contain expected _Plugin: ' . $className);
			
		}
		//split remainder into company and pluginName
		$firstPart = substr( $className, 0, $_PluginPos);
		$parts = explode( '_', $firstPart );
		
		if( count($parts) != 2 )
		{
			
			throw new Exception('Plugin class name does not meet expected format CompanyName_PluginName_Plugin: ' . $className);
			
		}
		//these plugins follow 2 naming conventions: standard Zend_Framework controller plugins (LibraryName_Controller_Plugin_PluginName) and also custom plugins ( CompayName_PluginName_Plugin )
		$this->_pluginCompany = $parts[0];
		$this->_pluginName = $parts[1];
		$this->_pluginUrl = $pluginPathRelative . 
							$this->_pluginCompany . DIRECTORY_SEPARATOR . 
							$this->_pluginName . DIRECTORY_SEPARATOR;
		
	}
	
	
	/**
	 * Loads the plugin's config file into $this->config
	 * The config file is searched for in /{atmail-web-root}/config/plugins/
	 *
	 * Available as of Atmail 6.1.9
	 *
	 * @param String (Optional) $section The name of the config section to fetch
	 *                                   Defaults to "main"
	 */
	protected function _loadConfig($section="main")
	{
	    // load plugin config if it exists
		$configPath = strtolower(APP_ROOT . "config/plugins/" 
		. $this->getPluginModule() . "." 
		. str_replace(array("_", "Plugin"), array(".", ""), get_class($this)) 
		. "ini");

		if (file_exists($configPath)) {
		    $this->config = new Zend_Config_Ini($configPath, $section);
		}
	}
	
	/**
	 * Get an Atmail config section or item
	 * Available as of Atmail 6.1.9
	 *
	 * @param String $section The section name to fetch
	 *                        Can be one of:
	 *                        admin, dovecot, exim, global or reg
	 * @param String $key (Optional) The array key for the item you want out
	 *                    of a particular config section.
	 * @return Mixed Bool on error, Array if no $key passed, String if $key
	 *               passed and it exists.
	 */
	private function _getAtmailConfig($section, $key=null)
	{
	    $config = Zend_Registry::get("config");
	    if (!isset($config->$section) || ($key && !isset($config->$section[$key]))) {
	        return false;
	    }
	    
	    if ($key) {
	        return $config->$section[$key];
	    } else {
	        return $config->$section;    
	    }
	}
	
	/**
	 * Convenience method that fetches the Atmail version
	 * Available as of Atmail 6.1.9
	 * @return String
	 */
	private function _getAtmailVersion()
	{
	    return $this->_getAtmailConfig("global", "version");    
	}
	
    /**
     * Returns formatted plugin information
     *
     * @param $useBr Boolean  If true use <br> as line delimiter, else use \n
     * @return String
     */
    public function getPluginInfoString($useBr=false)
    {
        $br = ($useBr) ? '<br>' : "\n"; 
        $info  = 'Name: ' . $this->getPluginFullName() . $br;
        $info .= 'Version: ' . $this->getPluginVersion() . $br;
        $info .= 'Company: ' . $this->getPluginCompany() . $br;
        $info .= 'Author: ' . $this->getPluginAuthor() . $br;
        $info .= 'URL: ' . $this->getPluginUrl() . $br;
        $info .= 'Description: ' . $this->getPuginDescription();
        $info .= 'Notes: ' . $this->getPuginNotes();

        return $info;
    }
    
    /**
     * Returns formatted plugin information
     *
     * @param $useBr Boolean  If true use <br> as line delimiter, else use \n
     * @return String
     */
    public function getPluginInfoArray()
    {
        $info = array(
            'name'        => $this->getPluginName(),
			'fullName'    => $this->getPluginFullName(),
			'company'     => $this->getPluginCompany(),
            'version'     => $this->getPluginVersion(),
            'author'      => $this->getPluginAuthor(),
            'url'         => $this->getPluginUrl(),
            'description' => $this->getPluginDescription(),
            'notes'       => $this->getPluginNotes(),
            'compat'      => $this->getPluginCompat(),
            'module'      => $this->getPluginModule(),
            'copyright'   => $this->getPluginCopyright(),
        );

        return $info;
    }
    
    
    /**
     * Return PHP extension dependency list
     *
     * @return Array
     */
    public function getDependencies()
    {
        return $this->_dependencies;
    }
    
    
    /**
     * Return the name of the plugin
     *
     * @return String
     */
    public function getPluginFullName()
    {
        return $this->_pluginFullName;
    }
    
	/**
     * Return the name of the plugin
     *
     * @return String
     */
    public function getPluginName()
    {
        return $this->_pluginName;
    }
    
	/**
     * Return the Atmail module the plugin is created for
     *
     * @return String
     */
    public function getPluginModule()
    {
        return $this->_pluginModule;
    }
    
    /**
     * Return the plugin's author
     *
     * @return String
     */
    public function getPluginAuthor()
    {
        return $this->_pluginAuthor;
    }
    
    
    /**
     * Return the plugin's URL (website)
     *
     * @return String
     */
    public function getPluginUrl()
    {
        return $this->_pluginUrl;
    }
    
    
    /**
     * Return the plugin description
     *
     * @return String
     */
    public function getPluginDescription()
    {
        return $this->_pluginDescription;
    }


    /**
     * Return the plugin copyright info
     *
     * @return String
     */
    public function getPluginCopyright()
    {
        return $this->_pluginCopyright;
    }
    
    
    /**
     * Return the plugin copyright info
     *
     * @return String
     */
    public function getPluginCompany()
    {
        return $this->_pluginCompany;
    }
    
    
    /**
     * Return plugin notes
     *
     * @return String
     */
    public function getPluginNotes()
    {
        return $this->_pluginNotes;
    }
    
    
    /**
     * Return the plugin's version string
     * 
     * @return String
     */
    public function getPluginVersion()
    {
    	return $this->_pluginVersion;
    }
    
    /**
     * Return the plugin's version string
     * 
     * @return String
     */
    public function getPluginCompat()
    {
    	return $this->_pluginCompat;
    }
    
    public function getActionController()
    {
        return $this->_controller;    
    }
    
    
    /**
     * Set required PHP extension dependencies
     */
    protected function _setDependencies($deps=array())
    {
        $this->_dependencies = $deps;
    }
    
    
    /**
     * Get the plugins settings from the DB
     *
     * @return Array
     */
    protected function _getPluginSettings()
    {
        $db = Zend_Registry::get("dbAdapter");
        $settings = $db->fetchOne("select settings from Plugins where name = ? and company = ? and module = ?",
            array($this->getPluginName(), $this->getPluginCompany(), $this->getPluginModule())
        );
        
        return unserialize($settings);
    }
    
    
    /**
     * Save  a plugin's settings to the DB
     *
     * @param Array  $settings Associative array of name => value pairs
     */
    protected function _setPluginSettings($settings)
    {
        $db = Zend_Registry::get("dbAdapter");
        $serialized = serialize($settings);
        $module = $db->quote($this->getPluginModule());
        $company = $db->quote($this->getPluginCompany());
        $name = $db->quote($this->getPluginName());
        $db->update("Plugins", array("settings" => $serialized), "module = $module and company = $company and name = $name");
    }
    
    /**
     * Takes the path to a file (relative to the plugin's root  dir)
     * and creates a URL that can be used to reference the file on
     * a webpage.
     *
     * Example from within a mail module plugin called "Bar" made by company "Foo"
     *
     * $path = $this->_makeUrl("images/logo.png");
     * echo "<img src=\"$path\" />";
     * 
     * This will output: <img src="application/modules/mail/plugins/Foo/Bar/images/logo.png" />
     *
     * @param String $path The path of the resource relative to the
     *                     plugin's root dir.
     * @return String A URL for the resource that can be used on a webpage to access it.
     */
    protected function _makeUrl($path)
    {
        // we pass $this to get_class() so as to get 
        // the name of the class that has extended from 
        // this one. If left out we will just get the name
        // of this class which we already know.
        $class = get_class($this);
        $pluginPath = str_replace('_', '/', $class);
        $pluginPath = preg_replace('|/Plugin$|', "", $pluginPath);
        $module = $this->getRequest()->getModuleName();
        $base = Zend_Registry::get('siteBaseUrl');
        $fullPath =  "{$base}application/modules/$module/plugins/$pluginPath/$path";
        return $fullPath;
    }
        
    /**
     * Creates an item in the Webmail Settings navigation bar
     *
     * @param Array $params Associative array of parameters.
     *                      title => title for the <a> tag
     *                      text => visible label for the item
     *                      icon => path (relative to your plugin's root dir) to an icon to use
     *
     * @access protected
     * @return String
     */
    protected function _createMailSettingsNavSection($params)
    {
        $class = get_class($this);
        $id = strtolower($class) . "_settings";
        
        $style = '';
        if (isset($params['icon'])) {
            $path = $this->_makeUrl($params['icon']);
            $style = "background: url($path) no-repeat 15px;display:block;height:19px;overflow:hidden;padding:11px 8px 6px 37px;white-space:nowrap;width:132px;";
        }
        
        $baseUrl = $this->_getModuleBaseUrl();

	    return "
	    <li id=\"$id\">
			<a href=\"$baseUrl/plugininterface/index/$class/settings\" title=\"{$params['title']}\">
				<span style=\"$style\">{$params['text']}</span>
			</a>
		</li>";
    }

    
    
    protected function _getModuleBaseUrl()
    {
        $baseUrl = Zend_Registry::get('siteBaseUrl');
        $baseUrl .= "index.php/" . $this->getPluginModule();
        return $baseUrl;
    }
    
    
    /**
     * Creates and sets up the view object for a plugin
     *
     * @access protected
     * return null
     */
    protected function _initView()
    {
        if (!isset($this->view)) {
            $class = get_class($this);
            $path = $this->getPluginModule() . "/plugins/" . dirname(str_replace("_", "/", $class));
            $this->view = new Zend_View();
	        $this->view->addHelperPath('library/Atmail/View/Helper/', 'Atmail_View_Helper');
	        $this->view->setBasePath(APP_ROOT . "application/modules/$path/views");
	        $this->view->addScriptPath(APP_ROOT . "application/modules/mail/views/scripts/global");
	        $this->view->moduleBaseUrl = $this->_getModuleBaseUrl();
        }
    }
    
    /**
     * Get the HTML portion of an JSON reponse
     *
     * Available as of Atmail 6.1.9
     *
     * @param Array $index An array of indexes to use to locate the HTML body in the JSON object
     * @return String
     */
    protected function _getJsonResponseHtml($index=null)
    {
        $body = Zend_Json::decode($this->getResponse()->getBody(), Zend_Json::TYPE_OBJECT);
        
		$controller = $this->getRequest()->getControllerName();
        $action = $this->getRequest()->getActionName();
		
		// If $index is an array then use the specified indexes
		if (is_array($index)) {
			return $body->q[$index[0]]->a[$index[1]][$index[2]];
		}
		
        if ($action == 'updatecontact') {
            return $body->q[3]->a[0][0];
        }
        
        if ($action == "viewcontact" || $action = "editcontact" || $action == "newcontact" || ($controller == "users" && $action == "edit")) {
            return (!is_array($body->q[0]->a[0][0])) ? $body->q[1]->a[0][0] : $body->q[0]->a[0][0];
        }

        return $body->q[1]->a[0][0];
    }
    
    /**
     * Set the HTML portion of an JSON reponse
     *
     * Available as of Atmail 6.1.9
     *
     * @param String $html The HTML to inject into the JSON response
     * @param Array  $index An array of indexes to use to locate the HTML body in the JSON object
     */
    protected function _setJsonResponseHtml($html, $index=null)
    {
        $body = Zend_Json::decode($this->getResponse()->getBody(), Zend_Json::TYPE_OBJECT);
        
        $action = $this->getRequest()->getActionName();
        
		// If $index is an array then use the specified indexes
		if (is_array($index)) {
			$body->q[$index[0]]->a[$index[1]][$index[2]] = $html;
		} elseif ($action == 'updatecontact') {
            $body->q[3]->a[0][0] = $html;
        } elseif ($action == "viewcontact" || $action = "editcontact" || $action == "newcontact") {
            $body->q[0]->a[0][0] = $html;
        } else {
            $body->q[1]->a[0][0] = $html;
        }
        
        $this->getResponse()->setBody(Zend_Json::encode($body));
    }
    
    /**
     * Copy a plugin's config file into the
     * Atmail config/ directory
     *
     * Available as of Atmail 6.1.9
     *
     * @param String Path to default config bundled
     *               with the plugin
     * @return Mixed String saved path on success, Bool false on failure
     */
    protected function _storeConfigFile($path)
    {
        $class = get_class($this);
        $name = strtolower($this->getPluginModule() . "." . str_replace(array("_", "Plugin"), array(".", ""), $class) . "ini");
        
        // backup any existing config file
        if (file_exists(APP_ROOT . "config/plugins/$name")) {
            rename(APP_ROOT . "config/plugins/$name", APP_ROOT . "config/plugins/$name.old");
        }
        
        if (copy($path, APP_ROOT . "config/plugins/$name")) {
            return APP_ROOT . "config/plugins/$name";    
        }
        
        return false;
    }
    
    
    public function setActionController(Zend_Controller_Action $controller)
    {
        $this->_controller = $controller;    
    }
    
    
    /**
     * Custom plugin hook allowing for adding attachment file previews
     * when viewing messages
     */
    public function filePreview($args=array())
    {}
    
    
    /**
     * Custom plugin hook for displaying any plugin settings
     * in webadmin
     */
    public function settings()
    {}

    /**
     * Custom plugin hook for saving any plugin settings
     * in webadmin
     */
    public function saveSettings($settings=array())
    {}
    
    
    /**
     * Custom plugin hook allowing processing/altering message body contents
     * before it is output.
     */
    public function processMessageBody($body)
    {}
     
     
    /**
     * Custom plugin hook for altering From address in outgoing email
     */
    public function emailFrom()
    {}
     
     
    /**
     * Implement this method in your plugin to perform any install
     * time setup required, such as creating new DB tables.
     */
    public function setup()
    {}
    
    /**
     * Find out if the plugin implements a feature
     *
     * @param String Feature name
     * @return String Class name if it does implement
     *                or empty if not.
     */
    public function pluginImplements($feature)
    {
       return (in_array($feature, $this->_pluginImplements)) ? get_class($this) : '';
    }
    
    
    /**
     * Find out whether or not the specified method requires user to be
     * authenticated.
     * 
     * @param String $method
     * @return Boolean
     */
    public function authRequired($method)
    {
		if (in_array($method, $this->_noAuthRequiredMethods)) {
			return false;
		}
		
		return true;
	}
	

    /**
     * Discover if the plugin should be treated as the final to be called for a particular event
     *
     * @param String event
     * @return Boolean
     */
    public function isFinal($event)
    {
        return in_array($event, $this->_finalHandlerFor);
    }

    
    /**
     * This event allows plugins to know when the page for viewing a contact
     * is about to be rendered. The plugin can then manipulate the view data
     * to alter what might be displayed.
     *
     * Available as of Atmail 6.1.9
     */
    public function preRenderContactView()
    {}
    
    public function preSignupProcess()
    {}
    
}
   
