<?php

/**
 * Atmail Principals Backend
 *
 * Principals in WebDAV terms are users or groups. We're overriding the default 
 * SabreDAV backend because we need to inject delegation/proxy related stuff. 
 * 
 * @package Atmail
 * @subpackage Dav 
 * @copyright Copyright (C) 2011 Atmail. All rights reserved.
 * @author Evert Pot (http://www.rooftopsolutions.nl/) 
 */
class Atmail_Dav_Backend_Principals extends Sabre_DAVACL_PrincipalBackend_PDO {

    /**
     * Read mode
     */
    const READ = 1;

    /**
     * Read-write mode
     */
    const WRITE = 2;

	private $_authPlugin = NULL;

	public function __construct(PDO $pdo, $tableName = 'principals', $groupMembersTableName = 'groupMembers', Sabre_DAV_Auth_Plugin $authPlugin = NULL) {
		$this->pdo = $pdo;
		$this->tableName = $tableName;
		$this->groupMembersTableName = $groupMembersTableName;
		$this->_authPlugin = ($authPlugin == NULL ? false : $authPlugin);
	}

	public function getPrincipalsByPrefix($prefixPath) {
		if (!$this->_authPlugin) return array();

		$userName = $this->_authPlugin->getCurrentUser();

		// we need the logged in users principal account with delegates in order to return the correct secured results.
		$authed_principal = $this->getPrincipalByPath($prefixPath . '/' . $userName);
		if (!$authed_principal)
		{
			throw new Sabre_DAV_Exception('Authorized user principal not found');
		}
		$authed_principals = array();
		$authed_principals[] = $authed_principal;

		$stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM `'.$this->groupMembersTableName.'` AS groupmembers LEFT JOIN `'.$this->tableName.'` AS principals ON groupmembers.memberid = principals.id WHERE groupmembers.principalid = ?');
		$stmt->execute(array($authed_principal['id']));
		while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
			$authed_principals[] = $row['uri'];
		}

		$principals = array();

		foreach($authed_principals as $principal)
		{
			$result = $this->pdo->prepare('SELECT uri, email, displayname FROM `'. $this->tableName . '` where uri = ?');
			$result->execute(array($principal['uri']));

			while($row = $result->fetch(PDO::FETCH_ASSOC)) {

				// Checking if the principal is in the prefix
				list($rowPrefix) = Sabre_DAV_URLUtil::splitPath($row['uri']);
				if ($rowPrefix !== $prefixPath) continue;

				$principals[] = array(
					'uri' => $row['uri'],
					'{DAV:}displayname' => $row['displayname']?$row['displayname']:basename($row['uri']),
					'{http://sabredav.org/ns}email-address' => $row['email'],
				);

			}
		}
		return $principals;
	}

    /**
     * Returns the list of principals in a group.
     *
     * This is only supported for 
     * calendar-delegation/###/principal/calendar-proxy-* urls.
     * 
     * @param string $principal 
     * @return array 
     */
    public function getGroupMemberSet($principal) {

        // We only ever allow fetching the group-member-set for
        // calendar-delegation principals
        if (!preg_match('|^calendar-delegation/([0-9]+)/principal/calendar-proxy-(read|write)$|', $principal, $matches)) {
            return array();
        }

        $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM calendarDelegates LEFT JOIN principals ON calendarDelegates.principalid = principals.id WHERE calendarid = ? AND mode = ?');

        $stmt->execute(array(
            $matches[1], 
            $matches[2]==='read'?self::READ:self::WRITE
        ));
        $result = $stmt->fetchAll();

        $response = array();
        foreach($result as $row) {
            $response[] = $row['uri'];
        }

        return $response;

    }

    /**
     * Returns the list of groups a principal belongs to 
     * 
     * @param string $principal 
     * @return array 
     */
    public function getGroupMembership($principal) {
		$principal = $this->getPrincipalByPath($principal);
        if (!$principal) return array();
        Atmail_Cache::setUsername($this->_authPlugin->getCurrentUser());
   		$response = Atmail_Cache::fetch(Atmail_Cache::TYPE_DAV, $principal['uri'] . $principal['id']);
		if($response === false)
		{
	    $stmt = $this->pdo->prepare('SELECT calendarid, mode FROM calendarDelegates WHERE principalid = ?');
        $stmt->execute(array($principal['id']));
        $result = $stmt->fetchAll();

        $response = array();
        foreach($result as $row) {
            if ($row['mode'] == self::READ) {
                $response[] = 'calendar-delegation/' . $row['calendarid'] . '/principal/calendar-proxy-read';
            } else if ($row['mode'] == self::WRITE) {
                $response[] = 'calendar-delegation/' . $row['calendarid'] . '/principal/calendar-proxy-write';
            } else {
                throw new Sabre_DAV_Exception('Incorrect mode for principal in calendarDelegates table');
            }
        }
			// use a _very_ short cache timeout here, delegates can change without warning
			Atmail_Cache::store(Atmail_Cache::TYPE_DAV, $principal['uri'] . $principal['id'], $response, 2);
		}

        return $response;
    }

    /**
     * Updates the list of members for a group-principal
     * 
     * @param string $principal 
     * @param array $groupMembers 
     * @return void
     */
    public function setGroupMemberSet($principal, array $groupMembers) {

        // We only ever allow setting the group-member-set for
        // calendar-delegation principals
        if (!preg_match('|^calendar-delegation/([0-9]+)/principal/calendar-proxy-(read|write)$|')) {
            throw new Sabre_DAV_Exception_Forbidden('We don\'t allow setting the group-member-set for this principal');
        }
        throw new Sabre_DAV_Exception_NotImplemented('This method is currently not implemented');

    }

}
