<?php

/**
 * Atmail Local WebDAV client
 *
 * This class acts just like Sabre_DAV_Client, but instead of it making a real 
 * connection to an HTTP / WebDAV server it requires an instance of 
 * Sabre_DAV_Server to do the requests.
 *
 * This allows us to 'fake' HTTP requests.
 * 
 * @package Atmail
 * @subpackage Dav 
 * @copyright Copyright (C) 2011 Atmail inc. All rights reserved.
 * @author Evert Pot (http://www.rooftopsolutions.nl/) 
 */
class Atmail_Dav_LocalClient extends Sabre_DAV_Client {

    /**
     * Server object 
     * 
     * @var string
     */
    protected $_server;

    /**
     * If this is turned on, all requests and responses will be logged to 
     * /tmp/davdebuglog
     * 
     * @var bool 
     */
    protected $debug = false; 

    /**
     * Constructor
     *
     * Settings are provided through the 'settings' argument. The following 
     * settings are supported:
     *
     *   * userName (optional)
     *   * password (optional)
     * 
     * @param array $settings 
     */
    public function __construct(array $settings) {

        $settings['baseUri'] = '';
        parent::__construct($settings);

    }


    /**
     * Sets the server object. 
     *
     * @param Sabre_DAV_Server $server 
     * @return void
     */
    public function setServer(Sabre_DAV_Server $server) {

        $this->_server = $server;

    }
    
    /**
     * Returns the server object.
     *
     * If no default server object is set, this class will attempt to 
     * instantiate the correct enviroment. 
     * 
     * @return Sabre_DAV_Server
     */
    public function getServer() {
        
        if ($this->_server) {
            return $this->_server;
        }

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

        $server = new Atmail_Dav_Server($pdo);
        $server->setBaseUri('/');

        // Grabbing the 'real' server.
        $this->_server = $server->getServer();
        return $this->_server;

    }

    /**
     * Performs an actual HTTP request, and returns the result.
     *
     * If the specified url is relative, it will be expanded based on the base 
     * url.
     *
     * The returned array contains 3 keys:
     *   * body - the response body
     *   * httpCode - a HTTP code (200, 404, etc)
     *   * headers - a list of response http headers. The header names have 
     *     been lowercased.
     *
     * @param string $method 
     * @param string $url 
     * @param string $body 
     * @param array $headers 
     * @return array 
     */
    public function request($method, $url = '', $body = null, $headers = array()) 
	{

        if ($this->debug) {
            ob_start();
        }

        $this->getServer();

        $serverArray = array(
            'REQUEST_METHOD' => $method,
            'REQUEST_URI' => '/' . $url,
        );

        foreach($headers as $key=>$value) {
            $serverArray['HTTP_' . strtoupper(str_replace('-','_', $key))] = $value;
        }

        // Assuming HTTP basic auth
        if ($this->userName && $this->password) {
            $serverArray['HTTP_AUTHORIZATION'] = 'basic ' . base64_encode($this->userName . ':' . $this->password); 
        }

        if ($this->debug) {
            echo "Request: \n";
            print_r($serverArray);
            echo "\n\n";
            echo $body, "\n";
        }



        $request = new Sabre_HTTP_Request($serverArray);
        $request->setBody($body);
        $response = new Atmail_Dav_LocalClientResponse();

        $this->_server->httpRequest = $request;
        $this->_server->httpResponse = $response;

        // Executing the actual request
        $this->_server->exec();

        $result = array(
            'body' => null,
            'statusCode' => null,
            'headers' => array(),
        );

        if (is_resource($response->body)) {
            $result['body'] = stream_get_contents($response->body);
        } else {
            $result['body'] = $response->body;
        }

        list(, $result['statusCode']) = explode(' ',$response->status);

        foreach($response->headers as $header) {
            $parts = explode(':',$header,2);
            $result['headers'][strtolower($parts[0])] = $parts[1];
        }

        // To comply with the original client, we're throwing exceptions if
        // HTTP status code > 400
        if ($result['statusCode'] >= 400) {

            throw new Sabre_DAV_Exception('HTTP error response. (errorcode ' . $result['statusCode'] . ')' . "\n" . $response->body);

        }

        return $result;

    }

}
