<?php
/**
 * @category 	Atmail
 * @package 	Models
 * @subpackage	Admin
 * @copyright 	Copyright (c) 2009-2011 ATMAIL. All rights reserved
 * @license 	See http://atmail.com/license.php for license agreement
 * @author		Ben Duncan ben@staff.atmail.com
 * @author		Atmail (http://atmail.com)
 */
define('COUNT_TRIES',100);
class admin
{

	private $_session;
	private $_account;
	private $_tableNames;
	private $_namespaceName = 'admin';

	public function __construct()
	{

		$this->dbAdapter = Zend_Registry::get('dbAdapter');

		$this->log = Zend_Registry::get('log');

		//CONSIDER not being dependant on admin Controller config (can change) - should rather accept config args for own session namespace
		//this REST client shares session namespace with the admin controllers
		$this->_session = new Zend_Session_Namespace(ATMAIL_ADMIN_NAMESPACE);

		$this->_session->server = "";

		// If local server being admind then access the api class direct and dont go through the REST service
		if( empty($this->_session->server) )
		{

			require_once('api.php');
			$this->api = new api(array('Username' => $this->_session->Username, 'Password' => $this->_session->Password));

		}
		else
		{

			Zend_Rest_Client::getHttpClient()->setAuth($this->_session->Username, $this->_session->Password);
			$this->client = new Zend_Rest_Client( $this->_session->serverURI );

		}

	}

/**
 * Domain Methods
*/
	public function domainCheck( $name )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->domainCheck($name);
		    return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);

		}
		else
		{

			$result = $this->client->get($this->_session->serverBasePath . "/api/domain/check/name/" . $name);
			return array('response' => (string)$result->response->message, 'status' => (string)$result->status);

		}

	}

	public function domainCreate( $name )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->domainCreate($name);
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);

		}
		else
		{

			$result = $this->client->get( $this->_session->serverBasePath . "/api/domain/create/name/" . $name );
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status);

		}

	}

	public function domainDelete( $name )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->domainDelete($name);
            return array('response' => $result['response']['message'], 'status' => $result['status']);

		}
		else
		{
			$method = $this->_session->serverBasePath . "/api/domain/delete/name/" . $name;
			$result = $this->client->get($method);
            return array('response' => (string)$result->response->message, 'status' => (string)$result->status);

		}

	}

	public function domainList($optionalArgs = null)
	{

		if( empty($this->_session->server) )
		{

			$hostnames = $this->api->domainList($optionalArgs);
			if( isset($hostnames['status']) && $hostnames['status'] == 'failed' )
			{

				throw new Exception('Failed fetching domain list: ' . (string)$hostnames['response']['message'] );

			}

		}
		else
		{

			$result = $this->client->get( $this->_session->serverBasePath . '/api/domain/list' );

			if( !$result->isSuccess() )
			{

				throw new Exception('Failed fetching domain list: ' . (string)$result->response->message);

			}

			$hostnames = array();
			$i = 0;
			foreach ($result->domainList->children() as $child)
			{

				$added = 0;
				foreach ($child->children() as $field)
				{

					$name = $field->getName();
					if( (string)$field != '' )
					{

						// Use (string) else an object is returned if row is null
						$hostnames[$i][$name] = (string)$field;
						$added = 1;

					}

				}
				if($added == 1)
				{

					$i++;

				}
			}
		}

		return $hostnames;

	}

	public function groupCreate( $args = array() )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->groupCreate($args);
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/groups/create";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, $args);
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );

		}

	}

	public function groupGet( $groupName )
	{

		if( empty($this->_session->server) )
			return $this->api->groupGet( $groupName );
        else
		{

			$method = $this->_session->serverBasePath . "/api/groups/get";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post( $method, array('groupName' => $groupName) );
			$status = (string)$result->status;
			if( $status == 'success' )
				return array('response' => array('results' => (string)$result->response->results), 'status' => (string)$result->status );
            else
				return array('response' => array('message' => (string)$result->response->message), 'status' => (string)$result->status );
            
		}

	}

	public function groupsList( $type = 'all' )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->groupsList( $type );

			if( $result['status'] == 'failed' )
			{

				throw new Exception('Failed fetching groups list: ' . (string)$result['response']['message'] );

			}
			$result = $result['response']['results'];

		}
		else
		{

			$response = $this->client->get( $this->_session->serverBasePath . '/api/group/list/type/' . $type );

			if( !$response->isSuccess() )
			{

				throw new Exception('Failed fetching groups list: ' . (string)$response->response->message);

			}

			$result = array();
			$i = 0;
			foreach ($response->response->results->children() as $child)
			{

				foreach ($child->children() as $field)
				{

					// Use (string) else an object is returned if row is null
					$result[$i][$field->getName()] = (string)$field;

				}
				$i++;

			}
		}

		return $result;

	}
	
	public function domainGroupsList()
	{
		
		if( empty($this->_session->server) )
		{

			$result = $this->api->domainGroupsList();

			if( $result['status'] == 'failed' )
			{

				throw new Exception('Failed fetching groups list: ' . (string)$result['response']['message'] );

			}
			$result = $result['response']['results'];

		}
		else
		{

			$response = $this->client->get( $this->_session->serverBasePath . '/api/groups/domaingroupslist/namesOnly/false' );
			if( !$response->isSuccess() )
			{

				throw new Exception('Failed fetching groups list: ' . (string)$response->response->message);

			}

			$result = array();
			$i = 0;
			foreach ($response->response->results->children() as $child)
			{

				foreach ($child->children() as $field)
				{

					// Use (string) else an object is returned if row is null
					$result[$i][$field->getName()] = (string)$field;

				}
				$i++;

			}
		}

		return $result;
		
		
	}
	
	public function groupTotal( $groupName )
	{
		
		if( empty($this->_session->server) )
		{

			$result = $this->api->groupTotal( $groupName );

			if( $result['status'] == 'failed' )
			{

				throw new Exception('Failed fetching group total: ' . (string)$result['response']['message'] );

			}
			$result = $result['response']['total'];

		}
		else
		{

			$response = $this->client->get( $this->_session->serverBasePath . '/api/group/total/groupName/' . $groupName );

			if( !$response->isSuccess() )
			{

				throw new Exception('Failed fetching group total: ' . (string)$response->response->message);

			}

			$result = $response->response->total;
		}

		return $result;
		
	}

	public function groupsListTotals( $type = 'user')
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->groupsListTotals( $type );

			if( $result['status'] == 'failed' )
			{

				throw new Exception('Failed fetching groups list: ' . (string)$result['response']['message'] );

			}
			$result = $result['response']['results'];

		}
		else
		{

			$response = $this->client->get( $this->_session->serverBasePath . '/api/group/listtotals/type/' . $type );

			if( !$response->isSuccess() )
			{

				throw new Exception('Failed fetching groups list: ' . (string)$response->response->message);

			}

			$result = array();
			$i = 0;
			foreach ($response->response->results->children() as $child)
			{

				foreach ($child->children() as $field)
				{

					// Use (string) else an object is returned if row is null
					$result[$i][$field->getName()] = (string)$field;

				}
				$i++;

			}
		}

		return $result;

	}

	public function groupUpdate( $groupName, $data )
	{

		if( empty($this->_session->server) )
			return $this->api->groupUpdate( $groupName, $data);
		else
		{

			$method = $this->_session->serverBasePath . "/api/groups/update";
			$result = $this->client->post( $method, array('groupName' => $groupName, 'data' => $data) );
			object2array($response);
			return $response;

		}

	}
	
	public function groupUserAdd( $groupName, $Account )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->groupUserAdd( $groupName, $Account );
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/groups/useradd";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, array('groupName' => $groupName, 'name' => $Account) );
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );

		}
		
	}
	
	public function groupUsersAdd( $groupName, $Accounts )
	{
		
		if( empty($this->_session->server) )
			return $this->api->groupUsersAdd( $groupName, $Accounts );
		else
		{

			$method = $this->_session->serverBasePath . "/api/groups/usersadd";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, array('groupName' => $groupName, 'Accounts' => $Accounts) );
		    object2array($result);
			return $result;

		}
		
	}
	
	public function groupUserDelete( $groupName, $name )
	{
		
		if( empty($this->_session->server) )
		{

			$result = $this->api->groupUserDelete( $groupName, $name );
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/groups/userdelete";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, array('groupName' => $groupName, 'Account' => $name) );
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );

		}
		
		
	}

	public function groupUsersDelete( $groupName, $Accounts )
	{
		
		if( empty($this->_session->server) )
		{

			$result = $this->api->groupUsersDelete( $groupName, $Accounts );
			return $result;

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/groups/usersdelete";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, array('groupName' => $groupName, 'Accounts' => $Accounts) );
			return object2array($result);

		}
		
		
	}

	public function groupDelete( $groupName )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->groupDelete( $groupName );
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/groups/delete";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, array('groupName' => $groupName) );
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );

		}

	}



/**
 * User Admin API calls
*/
	public function userCreate( $args = array() )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->userCreate($args);
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/users/create";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, $args);
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );

		}

	}

	public function userList( $domain=false, $limit=null, $searchQuery=null, $group = false, $args = false)
	{

		if( empty($this->_session->server) )
		{

			$users = $this->api->userList($domain, $limit[0], $limit[1], $searchQuery, $group, $args);
			if(isset($users['status']) && $users['status'] == 'failed')
			{

				throw new Exception('Failed fetching users list: ' . (string)$users['response']['message'] );

			}

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/users/list";
			if( $domain != false )
				$method .= "/domain/" . $domain;

			if ( is_array($limit) )
			    $method .= "/start/" . $limit[0] . "/volume/" . $limit[1];

			if ( !empty($searchQuery) )
				$method .= "/searchQuery/" . urlencode($searchQuery) . "/";

			if ( $group !== false )
				$method .= "/group/" . urlencode($group) . "/";

			$result = $this->client->get($method);

			if( !$result->isSuccess() )
				throw new Exception('Failed fetching users list: ' . (string)$result->response->message);

			$i=0;
			foreach ($result->userList->children() as $child)
			{

				foreach ($child->children() as $field)
				{
					$name = $field->getName();
					// Use (string) else an object is returned if row is null
					$users[$i][$name] = (string)$field;
				}
			    $i++;

			}

		}

		return $users;
	}

	public function userView($name = '', $id = '')
	{

		if( empty($this->_session->server) )
		{
			$user = $this->api->userView($name, $id);

			if($user['status'] == 'failed')
				throw new Exception('Failed fetching user: ' . (string)$user['response']);

		}
		else
		{
			if( !empty($id) )
				$method = $this->_session->serverBasePath . "/api/users/view/id/" . $id;
			else
				$method = $this->_session->serverBasePath . "/api/users/view/name/" . $name;

			$result = $this->client->get($method);

			if( !$result->isSuccess() )
				throw new Exception('Failed fetching user: ' . (string)$result->response->message);

			$user = array();
			foreach ($result->userView->children() as $field)
			{

				$name = $field->getName();
		    	$user[$name] = (string)$field;

			}
		}

		return $user;
	}

	public function userUpdate( $args = array() )
	{

		if( array_key_exists('Account', $args) )
		{
			
			$args['name'] = $args['Account'];
			
		}
		elseif( array_key_exists('id', $args) )
		{
			
			$args['userId'] = $args['id'];
			
		}
		else
		{
			
			throw new Exception('Account or id argument missing');
			
		}

		if( empty($this->_session->server) )
		{

			$result = $this->api->userUpdate($args);
			if($result['status'] == 'failed')
				throw new Exception('Failed updating user: ' . (string)$result['response']['message'] );
			return array('response' => $result['response']['message'], 'status' => $result['status']);

		}
		else
		{

			$method = $this->_session->serverBasePath . '/api/users/update';
		    $result = $this->client->post( $method, $args);
			return array('response' => (string)$result->response->message, 'status' => (string)$result->status);

		}

	}

	public function userDelete($name)
	{
		if( empty($this->_session->server) )
		{
			$result = $this->api->userDelete($name);
			return array('response' => $result['response']['message'], 'status' => $result['status']);
		}
		else
		{
			$url = $this->_session->serverBasePath . '/api/users/delete/name/' . $name;
			$hostnames = array();
		    $result = $this->client->get($url);
			return array('response' => (string)$result->response->message, 'status' => (string)$result->status);
		}
	}


	// General functions for users
	public function generateUserPassword($length=8)
	{

        require_once('Atmail/PasswordPolicy.php');

		// Start with a blank password
		$password = "";

        // Get the password policy rules
        $rules = Zend_Registry::get('config')->password;

        if($rules['use_password_policy'] == 1)
        {

            // Check that the default length (8) is long enough to meet password policy
            if( $rules['min_length'] > $length ) $length=$rules['min_length'];
            if( $rules['min_nonalphanumeric_chars'] > $length ) $length=$rules['min_nonalphanumeric_chars'];
            if( $rules['min_numeric_chars'] > $length ) $length=$rules['min_numeric_chars'];
            if( $rules['min_lowercase_chars'] > $length ) $length=$rules['min_lowercase_chars'];
            if( $rules['min_uppercase_chars'] > $length ) $length=$rules['min_uppercase_chars'];
            if( $rules['max_length'] < $length ) $length=$rules['max_length'];

            // Set up counter for number of generation attempts
            $count_tries = 0;

            // Create password policy object
            $policy = new PasswordPolicy($rules);

            $valid = false;

            while ( !$valid ) {
                //Set up counter
                $i = 0;
                //Copy length to be used in while loop
                $length_i = $length;

                // define possible characters, ensuring adheres to password policy rules
                $possible = "0123456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
                if($rules['disallow_numeric_chars'])
                    $possible = "abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
                if($rules['min_nonalphanumeric_chars'] > 0)
                    $possible = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()/~";

                //If disallow certain type of char first specified
                if(($rules['min_nonalphanumeric_chars'] > 0) && ($rules['disallow_nonalphanumeric_first']))
                {
                    $length_i -= 1;
                    $char = substr("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", mt_rand(0, 51), 1);
                    $password = $char;
                }
                if($rules['disallow_numeric_first'])
                {
                    $length_i -= 1;
                    $char = substr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", mt_rand(0, 51), 1);
                    $password = $char;
                }

                // If disallow certain type of char last specified
                if($rules['disallow_numeric_last'])
                    $length_i -= 1;
                if(($rules['min_nonalphanumeric_chars'] > 0) && ($rules['disallow_nonalphanumeric_last']))
                    $length_i -= 1;

                // Fill the password with randomly selected characters
                $count_i = 0;
                while ($i < $length_i)
                {
                    // Pick a random character from the possible ones
                    $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
                    // We don't want this character if it's already in the password
                    if (!strstr($password, $char))
                    {
                        $password .= $char;
                        $i++;
                    }
                    $count_i++;
                    if( $count_i > COUNT_TRIES )
                    {
                        $password = false;
                        break;
                    }
                }

                // If disallow certain type of char last specified
                if($rules['disallow_numeric_last'])
                {
                    $char = substr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", mt_rand(0, 51), 1);
                    $password .= $char;
                    $length_i += 1;
                }
                if(($rules['min_nonalphanumeric_chars'] > 0) && ($rules['disallow_nonalphanumeric_last']))
                {
                    $char = substr("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", mt_rand(0, 51), 1);
                    $password .= $char;
                    $length_i += 1;
                }

                // If minimum number of certain characters specified
                // Only attempt to meet requirement if specified minimum is less than half total length
                if( $rules['min_lowercase_chars'] <= (($length/2) + 1) )
                {
                    $count_min_tries = 0;
                    while (preg_match_all("/[a-z]/",$password,$x) < $rules['min_lowercase_chars'])
                    {
                        $count_min_tries++;
                        if($count_min_tries > COUNT_TRIES) break;
                        $possible = "abcdefghijklmnopqrstuvwxyz";
                        $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
                        $position = mt_rand(0, $length);
                        $password = substr_replace($password, $char, $position, 1);
                   }
                }
                if($rules['min_uppercase_chars'] <= (($length/2) + 1) )
                {
                    $count_min_tries = 0;
                    while (preg_match_all("/[A-Z]/",$password,$x) < $rules['min_uppercase_chars'])
                    {
                        $count_min_tries++;
                        if($count_min_tries > COUNT_TRIES) break;
                        $possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                        $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
                        $position = mt_rand(0, $length);
                        $password = substr_replace($password, $char, $position, 1);
                    }
                }
                if($rules['min_nonalphanumeric_chars'] <= (($length/2) + 1) )
                {
                    $count_min_tries = 0;
                    while (preg_match_all("/[\W]/",$password,$x) < $rules['min_nonalphanumeric_chars'])
                    {
                        $count_min_tries++;
                        if($count_min_tries > COUNT_TRIES) break;
                        $possible = "!@#$%^&*()/~";
                        $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
                        $position = mt_rand(0, $length);
                        $password = substr_replace($password, $char, $position, 1);
                    }
                }
                if($rules['min_numeric_chars'] <= (($length/2) + 1) )
                {
                    $count_min_tries = 0;
                    while (preg_match_all("/[0-9]/",$password,$x) < $rules['min_numeric_chars'])
                    {
                        $count_min_tries++;
                        if($count_min_tries > COUNT_TRIES) break;
                        $possible = "0123456789";
                        $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);
                        $position = mt_rand(0, $length);
                        $password = substr_replace($password, $char, $position, 1);
                    }
                }

                // Validate submitted password
                $valid = $policy->validate($password);
                $count_tries++;
                if( $count_tries > 300)
                {
                    $password = false;
                    break;
                }

            } //While not valid

        } //If using password policy
        else
        {
            $i = 0;
            // define possible characters
            $possible = "0123456789abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            //Not using password policy
            while ($i < $length)
            {
                // pick a random character from the possible ones
                $char = substr($possible, mt_rand(0, strlen($possible)-1), 1);

                // we don't want this character if it's already in the password
                if (!strstr($password, $char))
                {
                    $password .= $char;
                    $i++;
                }
            }
        }

		return $password;
	}

	// Sub Admin user CRUD

	public function subadminCreate( $args = array() )
	{

		if( empty($this->_session->server) )
	    {
			
			$result = $this->api->subadminCreate($args);
            return array('status' => $result['status'], 'response' => $result['response']['message']);

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/subadmin/create";
			$result = $this->client->post($method, $args);
			return array('response' => (string)$result->response->message, 'status' => (string)$result->status);

		}

	}

	public function subadminView( $args = array() )
	{

		if( empty($this->_session->server) )
		{
			$subadmin = $this->api->subadminView($args);
            if(isset($subadmin['status']) && $subadmin['status'] == 'failed')
				throw new Exception('Failed fetching Subadmin record: ' . (string)$subadmin['response']['message'] );
		}
		else
		{
			$method = $this->_session->serverBasePath . "/api/subadmin/view";

			$result = $this->client->post($method, $args);

			if( !$result->isSuccess() )
				throw new Exception('Failed fetching Subadmin record: ' . (string)$result->response->message);

			$subadmin = array();

			foreach ($result->subadminView->children() as $field)
			{
				$name = $field->getName();
				// Use (string) else an object is returned if row is null
				//unpack Domains if found else string
				if( $name == 'Domains' )
	{
					$subadmin['Domains'] = array();
					foreach ($field->children() as $domain)
						$subadmin['Domains'][] = (string)$domain;
				} else
					$subadmin[$name] = (string)$field;

			}

		}

		return $subadmin;
	}

	public function subadminList( $args = array() )
	{

		if( empty($this->_session->server) )
		{
			
			$subadmins = $this->api->subadminList($args);
			if( $subadmins['status'] == 'failed' && $subadmins['response']['message'] == 'No matches found' )
			{
			
				$subadmins = array();
			
			}
			elseif( $subadmins['status'] == 'failed' )
			{
			
				throw new Exception('Failed fetching Subadmins record: ' . (string)$subadmins['response']['message'] );
				
			}
			
		}
		else
		{
			$method = $this->_session->serverBasePath . "/api/subadmin/list";
			$result = $this->client->post($method, $args);

			if( !$result->isSuccess() )
				throw new Exception('Failed fetching Subadmin list: ' . (string)$result->response->message);

			$subadmins = array();
			$i = 0;
			foreach ($result->subadminList->children() as $child)
	{

				foreach ($child->children() as $field)
	{

					$name = $field->getName();
					// Use (string) else an object is returned if row is null
					$subadmins[$i][$name] = (string)$field;

				}
	 		    $i++;
			}
		}

		return $subadmins;
	}

	public function subadminUpdate( $args = array() )
	{

		if( empty($this->_session->server) )
	{
			$result = $this->api->subadminUpdate($args);
			return array('status' => $result['status'], 'success' => $result['success']);

		}
		else
		{
			$method = $this->_session->serverBasePath . "/api/subadmin/update";
			$result = $this->client->post($method, $args);
			return array('status' => (string)$result->status, 'response' => (string)$result->response->message);
		}

	}

	public function adminUpdateSettings( Array $args )
	{

		$result = $this->api->adminUpdateSettings($args);
		if($result['status'] == 'failed')
			throw new Exception('Failed updating admin settings: ' . (string)$result['response']['message'] );
		return array('status' => $result['status'], 'success' => $result['success']);

	}

	public function subadminDelete( $args = array() )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->subadminDelete($args);
			if($result['status'] == 'failed')
				throw new Exception('Failed deleting Subadmin(s): ' . (string)$result['response']['message'] );
			return array('status' => $result['status'], 'success' => $result['success']);

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/subadmin/delete";
			$result = $this->client->post($method, $args);
			if( !$result->isSuccess() )
				throw new Exception('Failed deleting Subadmin(s): ' . (string)$result->response->message);
			return array('status' => (string)$result->status, 'response' => (string)$result->response->message);

		}

	}

// Admin functions
    public function adminSetPassword( $args = array() )
	{

		if( empty($this->_session->server) )
		{
			$result = $this->api->setPassword($args['id'], $args['Username'], $args['PasswordOld'], $args['PasswordNew']);
			return array('response' => $result['response']['message'], 'status' => $result['status']);

		}
		else
		{
			$method = $this->_session->serverBasePath . "/api/admin/setpassword";
			$result = $this->client->post($method, $args);
			return array('response' => (string)$result->response->message, 'status' => (string)$result->status);

		}

	}

// Aliases
	public function aliasesCreate( $args = array() )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->aliasesCreate($args);
			//return array('response' => array('message' => $result['response']['message']), 'status' => $result['status']);
			return $result;
		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/aliases/create";
		    $result = $this->client->get($method, $args);
            return array('response' => array('message' => (string)$result->response->message), 'status' => (string)$result->status);

		}

	}

	public function aliasesList($args = null)
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->aliasesList($args);
			if( is_array($result) && array_key_exists('status', $result) && $result['status'] == 'failed' )
				throw new Exception('Failed fetching aliases list: ' . $result['response']['message']);
			else
				return $result;

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/aliases/list";
		    $result = $this->client->get($method, $args);

			if( !$result->isSuccess() )
				throw new Exception('Failed fetching Aliases list: ' . (string)$result->response->message);

			$aliasesList = array();
			$i = 0;
			foreach ($result->aliasesList->children() as $child)
			{

				foreach ($child->children() as $field)
				{
					$name = $field->getName();
					// Use (string) else an object is returned if row is null
					$aliasesList[$i][$name] = (string)$field;

				}
	 		    $i++;

			}

			return $aliasesList;

		}

	}

	public function aliasesDelete( $id )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->aliasesDelete(array("id" => $id));
			return $result;

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/aliases/delete/id/" . $id;
			$result = $this->client->get($method);
            return array('response' => array('message' => (string)$result->response->message), 'status' => (string)$result->status);

		}

	}

// MailRelay
	public function mailrelayCreate( $args = array() )
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->mailrelayCreate($args);
            return array('response' => array('message' => $result['response']['message']), 'status' => $result['status']);

		}
		else
		{

			//$method = $this->_session->serverBasePath . "/api/aliases/create";
		    //$result = $this->client->get($method, $args);
			//return array('status' => (string)$result->status);

		}

	}

	public function mailrelayDelete( $id )
	{

		if( empty($this->_session->server) )
		{
			$result = $this->api->mailrelayDelete($id);

			return array('status' => $result['status']);
		}
		else
		{
			//$method = $this->_session->serverBasePath . "/api/aliases/delete/id/" . $id;
			//$result = $this->client->get($method);

			//return array('status' => (string)$result->status);
		}

	}

	public function getCurrentAdminData()
	{

		if( empty($this->_session->server) )
		{

			$result = $this->api->getCurrentAdminData();
			return $result;

		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/getcurrentadmindata";
			$result = $this->client->get($method);
            return $result;

		}

	}

	public function getDomainStatus($domain)
	{
		if( empty($this->_session->server) ) {
			$result = $this->api->getDomainStatus($domain);
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);
		} else {
			$method = $this->_session->serverBasePath . "/api/domain/status";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, $domain);
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );
		}
	}

	public function domainLock($domain)
	{
		if( empty($this->_session->server) ) {
			$result = $this->api->domainLock($domain);
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);
		} else {
			$method = $this->_session->serverBasePath . "/api/domain/lock";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, $domain);
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );
		}
	}

	public function domainUnlock($domain)
	{
		if( empty($this->_session->server) ) {
			$result = $this->api->domainUnlock($domain);
			return array('response' => (string)$result['response']['message'], 'status' => (string)$result['status']);
		} else {
			$method = $this->_session->serverBasePath . "/api/domain/unlock";
			//NB: $this->client->args = $args; //doesnt work
			$result = $this->client->post($method, $domain);
		    return array('response' => (string)$result->response->message, 'status' => (string)$result->status, );
		}
	}
	
	public function getUsedQuota()
	{
		
		if( empty($this->_session->server) )
		{
			$result = $this->api->getUsedQuota(array(Atmail_Quota::TYPE => Atmail_Quota::TYPE_SUBADMIN, Atmail_Quota::DATA => $this->api->subadminDomains));
			return $result;
		}
		else
		{

			$method = $this->_session->serverBasePath . "/api/subadmin/getUsedQuota";
			$result = $this->client->get($method);
            return $result;

		}
		
	}
	
	public function getDomainAndGroupUsers( $optionalFilters = null )
	{
		
		if( empty($this->_session->server) )
		{

			return $this->api->getDomainAndGroupUsers( $optionalFilters );

		}
		else
		{

			return $this->client->get( $this->_session->serverBasePath . "/api/domain/getdomainandgroupusers" );
            
		}
		
	}
	
	public function logsearch( $args = array() )
	{
	
		if( empty($this->_session->server) )
		{

			return $this->api->logsearch($args);

		}
		else
		{

			// Required to implement
			//return $this->client->get( $this->_session->serverBasePath . "/api/domain/getdomainandgroupusers" );
            
		}
			
	}

	public function getLicenseStatusExpired()
	{

		$dlid = Zend_Registry::get("config")->reg['downloadId'];
		return 'A license has expired. Renew anytime via the Atmail Store for continued software patches, new versions and support. <a href="https://secure.atmail.com/store/index.php/index/renewalinfo?clientId=' . $dlid . '" target="_blank">Renew now</a>';

	}
	public function getLicenseStatusApproachingExpired()
	{
		$dlid = Zend_Registry::get("config")->reg['downloadId'];
		return 'A license will expire soon. Renew anytime via the Atmail Store for continued software patches, new versions and support. <a href="https://secure.atmail.com/store/index.php/index/renewalinfo?clientId=' . $dlid . '" target="_blank">Renew now</a>';
	}

	// New stats for Webadmin
	public function getMobileDevice()
	{

	}

	// When the user last logged in
	public function lastLogin($name)
	{
		if( $this->checkAdminPrivs($name) )
        {

		    $logs = array();
		    if( Zend_Registry::get("config")->global['install_type'] == 'server' )
				$logType = array('IMAP' => 3, 'POP3' => 1, 'Webmail' => 5, 'CalDAV' => 6, 'CardDAV' => 8, 'ActiveSync' => 7);
			else
				$logType = array('Webmail' => 5, 'CalDAV' => 6, 'CardDAV' => 8, 'ActiveSync' => 7);

			foreach( $logType as $key => $value )
			{
                $sql = "SELECT UNIX_TIMESTAMP(LogDate) AS LogDate FROM Log_Login where id = (select max(id) from Log_Login where Account = ? AND LogType=?) limit 1";
   			    $logs[$key] = $this->dbAdapter->fetchOne($sql, array($name, $value));
			    $logs[$key] = timeago($logs[$key]);
		    }

			return $logs;

        }
        else
            return 0;

	}

	public function firstLogin($name)
	{
        // lets take avantage that the first entry in the table will most probably be the first
        $sql = "SELECT UNIX_TIMESTAMP(LogDate) AS LogDate FROM Log_Login WHERE Account = ? limit 1";
        return $this->dbAdapter->fetchOne($sql, array($name) );
	}

	// Data stats, how many contacts/calendar/msgs for a specified user
	public function dataStats($name)
	{

        if( $this->checkAdminPrivs($name) )
        {

		    $stats = array();

    		$stats['contacts'] = $this->dbAdapter->fetchOne("select count(id) from Abook where Account=?", array($name));
    		$stats['calendarEvents'] = $this->dbAdapter->fetchOne("select count(calendarObjects.id) from calendars, calendarObjects where calendars.principaluri = ? and calendars.id = calendarObjects.calendarid", array('principals/users/' . $name));

    		return $stats;
        }
        else
            return 0;
	}

	// Usage stats for incoming/outgoing mail
	public function usageStats($name)
	{

        if( $this->checkAdminPrivs($name) )
        {

            $usage = array();

			$usage['outgoing'] = $this->dbAdapter->fetchAll("select EmailTo as Account, MD5(EmailTo) as md5, count(id) as total from Log_SendMail where Account=? group by EmailTo order by total desc limit 10", array($name));

			if( Zend_Registry::get("config")->global['install_type'] == 'server' )
			$usage['incoming'] = $this->dbAdapter->fetchAll("select EmailFrom as Account, MD5(EmailFrom) as md5, count(id) as total from Log_RecvMail where Account=? and EmailFrom != ? group by EmailFrom order by total desc limit 10", array($name, $name));


		    return $usage;
        }
        else
            return 0;
	}

	// Get a list of devices the user has synced from
	public function mobileStats($name)
	{
        if( $this->checkAdminPrivs($name) )
		    return $this->dbAdapter->fetchAll("select * from Log_Device where id = (select max(id) from Log_Device where Account = ?) limit 1", array($name));
        else
            return 0;
		
	}

    // Check user permissions
    public function checkAdminPrivs($name)
    {

        $this->adminInfo = $this->getCurrentAdminData();
        if( $this->adminInfo['UMasterAdmin'] == true )
            return 1;
        else
        {
            // Check domains associated with $name
            $allowedDomains = $this->domainList();
            foreach( $allowedDomains as $domain )
            {
                if( strpos($name, $domain['DomainName']) !== false )
                    return 1;
            }
            return 0;
        }
    }

    public function getMetrics($_this, $name)
    {
        if(($stats = Atmail_Cache::fetch(Atmail_Cache::TYPE_GRAPH, $name)) === false)
        {
            $stats['getMobileDevice'] = $this->getMobileDevice();
            $stats['lastLogin'] = $this->lastLogin( $name );
            $stats['firstLogin'] = $this->firstLogin( $name );
            $stats['dataStats'] = $this->dataStats( $name );
            $stats['usageStats'] = $this->usageStats( $name );
            $stats['mobileStats'] = $this->mobileStats( $name );
            Atmail_Cache::store(Atmail_Cache::TYPE_GRAPH, $name, $stats);
        }
        $_this->view->mobileDevice = $stats['getMobileDevice'];
        $_this->view->lastLogin = $stats['lastLogin'];
        $_this->view->firstLogin = $stats['firstLogin'];
        $_this->view->dataStats = $stats['dataStats'];
        $_this->view->usageStats = $stats['usageStats'];
        $_this->view->mobileStats = $stats['mobileStats'];
    }

    public function prepareUserView($_this)
    {

        if( isset($_this->requestParams['domain']) && isset($_this->requestParams['group']) )
        {
            if( strlen($_this->requestParams['domain']) < 1 && strlen($_this->requestParams['group']) < 1 )
            {
                // All users selected
                $_this->view->currentGroup = 'all';
            }
            else if( $_this->requestParams['domain'] == 'external' )
            {
                // External group selected
                $_this->view->currentGroup = 'external';
            }
            else if( strlen($_this->requestParams['group']) > 0 && strlen($_this->requestParams['domain']) == 0 )
            {
                // Group selected
                $_this->view->currentGroup = 'group';
            }
            else
            {
                // Domain selected
                $_this->view->currentGroup = 'domain';
            }
        }
        else
        {
            // Group selected
            $_this->view->currentGroup = 'group';
        }

        if( strlen($_this->view->domain) > 0 && $_this->view->domain != "external" )
        {
            $enabledArray = $this->dbAdapter->fetchCol("select Enable from Domains where Hostname = '" . $_this->view->domain . "'");
            $_this->view->domainEnabled = $enabledArray[0];
        }
        else
            $_this->view->domainEnabled = 1;

        $name = $_this->requestParams['name'];
        $_this->view->contact = array();

        if($name == '') return;

        $_this->view->contact = $this->userView( $name );

        $_this->filter->setData($_this->view->contact);
        $_this->view->contact = $_this->filter->getEscapedData();

        $_this->view->isExternal = users::isExternal($_this->view->contact['Account']);
        $_this->view->group = isset($_this->requestParams['group'])?$_this->requestParams['group']:'';
        $_this->view->contact['emailName'] = $_this->view->contact['Account'];
        $_this->view->contact['emailDomain'] = '';
        if(strpos($_this->view->contact['Account'], '@') !== false)
        {
            list($_this->view->contact['emailName'], $_this->view->contact['emailDomain']) = explode('@', $_this->view->contact['Account']);
        }

        $_this->view->view = 'month';

        if ($_this->view->domain != 'external')
        {
            $_this->view->totalUsers = users::count($_this->view->contact['emailDomain'], $_this->requestParams['searchQuery'], $_this->view->adminDomains);
            $domStatus = $this->getDomainStatus($_this->view->contact['emailDomain']);
            $_this->view->contact['DomainStatus'] = $domStatus['response'];
        }

        if(($result = $this->domainCheck($_this->view->contact['emailDomain'])) && $result['status'] != 'failed')
        {
            $_this->view->contact['MailServer'] = 'localhost';
        }

        $_this->view->listType = 'user';
        if(($result = $this->domainCheck($_this->view->domain)) && $result['status'] != 'failed')
        {
            $_this->view->listType = 'domain';
        }

        // Get metrics for the user account
        $this->getMetrics($_this, $name);

        // Build the select box for the number of days/range of logs for the map view.
        $FirstLogEpochDays = round($_this->view->firstLogin / 86400);
        $NowEpochDays = round(time() / 86400);

        $_this->view->mapDayRange = round($NowEpochDays - $FirstLogEpochDays);

        // No more then 1 year for range
        if( $_this->view->mapDayRange > 365 )
            $_this->view->mapDayRange = 365;
		elseif( $_this->view->mapDayRange < 1 )
			$_this->view->mapDayRange = 1;

    }
	
}
