<?php  // vim:set et ts=4 sw=4 sts=4:
# Copyright (C) 2003-2014 hipplay Inc.
#
# This is UNPUBLISHED PROPRIETARY SOURCE CODE OF hipplay Inc.
# The copyright notice above does not evidence any actual or intended
# publication of such source code. The contents of this file may not
# be disclosed to third parties, copied or duplicated in any form, in
# whole or in part, without the prior written permission of
# hipplay Inc.
#
namespace HipPlayConnect\REST;


use HipPlayConnect\AxFatalErrorException;
use HipPlayConnect\AxRecoverableErrorException;
use HipPlayConnect\AxUnrecoverableErrorException;
use HipPlayConnect\Configuration\AxOERelease;

define('REST_NS', '\\HipPlayConnect\\REST');
define('REST_SERVICES_NS', REST_NS . '\\services\\');


class AxRESTController
{

    //
	// prefix of Web Services URIs
	//
	const URI_PREFIX = '/api/2.0/rest/';
	
    //
	// build the REST service class name and path
	// returns a resource in case of a success
	// returns an error response in case of a failure
	//
	public static function getResourceFromService($serviceName, $URIArray)
	{
	    $serviceClassName = 'Ax' . ucfirst( $serviceName ) . 'RESTService';
	 	$serviceClassFQN = REST_SERVICES_NS . $serviceName . '\\' . $serviceClassName;

	 	//
	 	// service not found
	 	//
        if ( !class_exists( $serviceClassFQN ) )
	 		return new AxRESTResponse( 404 );

	 	//
	 	// instantiate service
	 	//
	 	try
	 	{
            /** @var AxRESTServiceInterface $service */
	 		$service = new $serviceClassFQN();
	 	}
	 	catch ( AxUnauthorizedRESTException $e )
	 	{
	 		return new AxRESTResponse( 401 );
	 	}
	 	
	 	//
	 	// ask the service (factory) for the requested resource
	 	// return error 404 if not found
	 	//
	 	try
	 	{
            /** @var AxRESTResourceInterface $mResource */
	 	    $mResource = $service->getResource( $URIArray );
	 	}
	 	catch ( AxFatalErrorException $e )
	 	{
	 	    error_log("Caught fatal exception");
	 	    return new AxRESTResponse( 500 );	 	    
	 	}
	    catch ( AxUnrecoverableErrorException $e )
        {
            error_log("[AxUnrecoverableErrorException] " . $e->getMessage()  . " Trace: " . $e->getTraceAsString());
            return self::_getAxUnrecoverableErrorExceptionResponse( $e );
        }
        catch ( AxRecoverableErrorException $e )
        {           
            error_log("[AxRecoverableErrorException] " . (!is_null($e->getMessage())?$e->getMessage():'no details available') . " Trace: " . $e->getTraceAsString());
            return new AxRESTResponse( array( $e->getCode() ), array( $e->getParams() ) );
        }  
		catch ( AxForbiddenRESTException $e )
		{
			return new AxRESTResponse( 403 );
		}
		catch ( AxUnauthorizedRESTException $e )	 	
		{
			return new AxRESTResponse( 401 );
		}

	 	if ( is_null( $mResource ) ) {
	 	    error_log("Could not get resource object for " . implode('/', $URIArray));
	 	    return new AxRESTResponse( 404 );
	 	}
	 	
	 	return $mResource;
	}

    //
    // Process Web Services Requests
    //
    public static function processRequest()
    {
	    set_time_limit( 0 );        // PHP can run forever
        ignore_user_abort( true );  // PHP cannot be stopped
        
        if ( isset( $_GET[ 'release' ] ) )
        {
            if ( $_GET[ 'release' ] != AxOERelease::get('Version') )
                self::error( array( 15 ) );
        }
        
        $mResponse = self::getRequestResponse( $_SERVER[ 'PATH_INFO' ] );
	 	$mResponse->send();
	}

    /**
     * Locate the resource represented by the supplied URI, and use it to process the request
     * into a response.
     *
     * @param string $URI
     * @param string $requestMethod
     * @param array $queryParams
     * @param string $requestBody
     *
     * @return AxRESTResponse
     */
	public static function getRequestResponse( $URI, $requestMethod = null, array $queryParams = null, $requestBody = null )
	{ 
	  
	    //
        // parse the URI
        //
        $URIArray = explode( '/', $URI );

        //
        // need at least something
        //
        if ( count( $URIArray ) < 2 )
            self::error( 404 );

        $serviceName = $URIArray[ 1 ];
        $mResource = self::getResourceFromService( $serviceName,  array_slice( $URIArray, 2 ) );
        
        // error handling
        if ( get_class( $mResource ) == 'HipPlayConnect\\REST\\AxRESTResponse' )
            $mResponse = $mResource;
        else
        {
            /** @var AxRESTResourceInterface $mResource */
            try {
                $mResponse = $mResource->processRequest( $requestMethod, $queryParams, $requestBody );
            }
            catch ( AxRecoverableErrorException $e )
            {           
                error_log("[AxRecoverableErrorException] " . (!is_null($e->getMessage())?$e->getMessage():'no details available') . " Trace: " . $e->getTraceAsString());
                $mResponse = new AxRESTResponse( array( $e->getCode() ), array( $e->getParams() ) );
            }  
            catch ( AxUnrecoverableErrorException $e )
            {
                error_log("[AxUnrecoverableErrorException] " . $e->getMessage()  . " Trace: " . $e->getTraceAsString());
                $mResponse = self::_getAxUnrecoverableErrorExceptionResponse( $e );
            }
            catch ( AxFatalErrorException $e )
            {
                error_log("[AxFatalErrorException] " . $e->getMessage()  . " Trace: " . $e->getTraceAsString());
                $mResponse = new AxRESTResponse( 500 );
            }
            catch ( AxForbiddenRESTException $e )
            {
                $mResponse = new AxRESTResponse( 403 );
            }
        }
        
        return $mResponse;
	}
	
	
	//
	// Outputs an HTTP error or returns the error response
	//
	public static function error( $code, $body = '' )
	{
		$response = new AxRESTResponse( $code, $body );
		$response->send();
	}
	
	private static function _getAxUnrecoverableErrorExceptionResponse( AxUnrecoverableErrorException $mEx )
	{
	    return new AxRESTResponse( array( $mEx->getCode() ) );
	}

    public static function allowBrowserCaching($Date) {
        $Date = gmdate( 'D, d M Y H:i:s', $Date ).' GMT';
        header( 'Last-Modified:' );
        header( 'Expires:' );
        header( 'Pragma:' );
        header( 'Cache-Control:' );
        if( !empty( $_SERVER['HTTP_IF_NONE_MATCH'] ) &&
            strpos( $_SERVER['HTTP_IF_MODIFIED_SINCE'], $Date ) !== false )
        {
            header( 'HTTP/'.$_SERVER['SERVER_PROTOCOL'].' 304 Not Modified' );
            // caller should exit in order to make this header have much effect
            return TRUE;
        }
        else
        {
            //header( 'Etag: '.$Etag );
            header( 'Last-Modified: '.$Date );
            // Continue generating content here
            return FALSE;
        }
    }
}

