<?php
/********************************************************************************
 * (c)1337 aheadware.com - All rights reserved
 ********************************************************************************/


class TB_Server_Core_Controller {

    /** @var TB_Server_Core_Request $request */
    private $request;
    /** @var TB_Server_Core_Response $response */
    private $response;

    public function __construct() {
        $this->request = NULL;
        $this->response = NULL;
    }

    /**
     * Process request
     *
     * @param TB_Server_Core_Request $request
     *
     * @return mixed|null
     */
    public function processRequest(  TB_Server_Core_Request $request ) {
        $this->request = $request;
        try {
            $this->checkVersion();
            $this->authorize();
            $this->execute();
        } catch ( Exception $e ) {
            // Something bad happened
            $code = TB_Server_Core_Response::CODE_GENERAL_ERROR;
            if ( in_array( $e->getCode(), TB_Server_Core_Response::getValidCodes() ) ) {
                $code = $e->getCode();
            }
            // Do not log everything
            if ( !in_array( $code, TB_Server_Utils_Log::$noLogCodes ) ) {
                TB_Server_Utils_Log::get()->log( $e );
            }
            $this->response = new TB_Server_Core_Response( $code );
        } finally {
            $this->processResponse();
            $this->send();
        }
    }

    /**
     * Sync's Version
     *
     * @throws Exception
     */
    protected function checkVersion() {
        $version = Francis_Utils_Config::get( 'version' );
        $authData = $this->request->data->get( 'auth' );
        if ( $version != $authData[ 'version' ] ) {
            $profileId = isset( $authData[ 'account_id'] ) ? $authData[ 'account_id'] : 0;
            throw new Exception( 'Client outdated ' . $profileId, TB_Server_Core_Response::CODE_OUTDATED_VERSION );
        }
    }

    /**
     * Authorize request
     *
     * @throws Exception
     */
    protected  function authorize()
    {
        // Try to resolve session
        $session = NULL;
        $authData = $this->request->data->get( 'auth' );
        if ( isset( $authData ) && isset( $authData['token'] ) && isset( $authData['account_id'] ) ) {
            $session = TB_Shared_Ent_Core_Session::getByAccountIdAndToken( $authData['account_id'], $authData['token'] );
            if ( $session ) {
                // Update timestamp
                $session->last_update = date("Y-m-d H:i:s");
                $session->save( true );
                TB_Server_Core_Session::get()->init( $session );
            } else {
                TB_Server_Core_Session::get()->destory();
            }
        }

        // If current request is about authorization
        if ( 'Auth' === $this->request->controller ) {
            return;
        }

        // If no session exists
        if ( is_null( $session ) ) {
            throw new Exception( 'Not logged in', TB_Server_Core_Response::CODE_NOT_LOGGED_IN );
        } else {
            $account = TB_Server_Core_Session::get()->getAccount();
            $team = TB_Server_Core_Session::get()->getTeam();
            $profile = TB_Server_Core_Session::get()->getProfile();

            // If account or profile is invalid
            if ( is_null( $account ) || is_null( $profile ) ) {
                // DB seems to be corrupt
                TB_Server_Core_Session::get()->getEntCoreSession()->delete();
                throw new Exception( 'Something is wrong with your session.' );
            } else if ( false === TB_Server_Core_AccessControl::hasRight( $team, $profile, $this->request ) ) {
                throw new Exception( 'No right to perform the controller action: ' . $this->request->controller . " " . $this->request->action );
            }

            $pts = $profile->getTimestamps();
            $pts->last_online = time();
            $pts->save();
        }
    }

    /**
     * Execute request
     *
     * @return Francis_Response_Abstract
     *
     * @throws Exception
     */
    protected function execute() {
        // Resolve action controller class
        $controllerPath = TB_Server_Utils_Config::get( 'path.server.controller' );
        $controllerClass = NULL;

        // Check if controller class and action exists
        if ( file_exists( $controllerPath . '/' . basename( 'TB_Server_Control_' . $this->request->controller ) . '.php' ) ) {
            $controllerClass = basename( 'TB_Server_Control_' . $this->request->controller );
            if ( !method_exists( $controllerClass, $this->request->action ) ) {
                $controllerClass = NULL;
            }
        }

        // If given action does not exsits
        if ( is_null( $controllerClass ) ) {
            // 404 - invalid call
            $this->response = new TB_Server_Core_Response( TB_Server_Core_Response::CODE_INVALID_DATA );
        } else {
            $this->response = call_user_func( $controllerClass . '::' . $this->request->action, $this->request->data );
        }
    }

    public function processResponse() {
        try {
            if ( !( $this->response instanceof Francis_Response_Abstract ) ) {
                $this->response = new TB_Server_Core_Response( TB_Server_Core_Response::CODE_GENERAL_ERROR );
                TB_Server_Utils_Log::get()->log( "Process response encountered an invalid response." );
            }
        } catch ( Exception $e ) {
            TB_Server_Utils_Log::get()->log( $e );
        }
    }

    public function send() {
        header( "Access-Control-Allow-Origin: *" );
        header( "Access-Control-Allow-Headers: application/x-www-form-urlencoded" );
        header( "Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS" );
        header( "Access-Control-Allow-Credentials: true" );
        header("Content-Type: text/plain");
        echo $this->response->get();
    }
}