<?php
/**
 * Created by PhpStorm.
 * User: giangnguyen
 * Date: 10/7/14
 * Time: 11:25 PM
 */

class Authentication {

    /**
     * @var OilApplication
     */
    protected $app;
    protected $entityManager;
    protected $userEntityClass = 'OilDatabase\Entity\User';


    protected $roles = array(

        'Metadata' => array('*'),
        'Lookups' => array('*'),
        'SaveChanges' => array('Administrator'),
        'Healths' => array('Administrator'),
        'Diseases' => array('Administrator'),
        'Tags' => array('Administrator'),
        'TagsOils' => array('Administrator'),
        'TagsDiseases' => array('Administrator'),
        'Health/:id' => array('Administrator'),
        'Oils' => array('Administrator'),
        'Oil/:id' => array('Administrator'),
        'Users' => array('Administrator'),
        'User/:id' => array('Administrator'),

        'account/userinfo' => array('*'),
        'account/externalLogins' => array('*'),
        'account/token' => array('*'),
        'account/logout' => array('*'),
        'account/login' => array('*')
    );


    public function __construct($app){
        session_start();
        $this->app = $app;
    }

    /**
     * @return \Doctrine\ORM\EntityManager
     */
    public function getEntityManager (){
        if(!$this->entityManager)
            $this->entityManager = $this->app->getObjectManager();

        return $this->entityManager;
    }

    public function run($action, Symfony\Component\HttpFoundation\Request $request){
        $return = array('message' => 'Login success.');
        switch($action){
            case 'token': $return = $this->token($request); break;
            case 'userinfo': $return = $this->userinfo($request->getContent()); break;
            case 'manageinfo': $return = $this->manageinfo($request->getContent()); break;
            case 'logout': $return = $this->logout($request->getContent()); break;
            case 'login': $return = $this->login($request->getContent()); break;
//            case 'register': $return = $this->register($request); break;
//            case 'lostPass': $return = $this->lostPass($request->getContent()); break;
            case 'externalLogins': $return = $this->externalLogins($request->getContent()); break;
            default: throw new ResourceNotFoundException('No resource found for "' . $request->getPathInfo()  . '"');

        }

        return $return;
    }

    protected function register($data){

    }

    protected function lostPass($data){

    }


    protected function logout($data){
        unset($_SESSION['userInfo']);
        return '';
    }


    public function check($request){
        $req = explode('/', $request);

        if(count($req) == 2){
            $permission = isset($this->roles[$request]) ? $this->roles[$request] : '';
            if(!$permission){
                $request = $req[0] .'/'. ':id';
                $permission = isset($this->roles[$request]) ? $this->roles[$request] : '';
            }
        }else{
            $permission = isset($this->roles[$request]) ? $this->roles[$request] : '';
        }

        if(!$permission) throw new Exception('No resource found for "' . $request . '" [1]');

        if(in_array('*', $permission)) return true;

        // Check by access_token
        if(isset($_GET['access_token'])){
            /**
             * @var $repository \Doctrine\ORM\EntityRepository
             */
            $entityManager = $this->getEntityManager();
            $repository    = $entityManager->getRepository('OilDatabase\Entity\Token');
            $token = $repository->findOneBy(array('token' => $_GET['access_token']));

            if(!$token){
                throw new Exception('No resource found for "' . $request . '" [4]');
            }

            // Get site refer
            if(isset($_SERVER["HTTP_REFERER"])){
                $site = parse_url($_SERVER["HTTP_REFERER"]);
                $site = $site['host'];

                $allow = false;
                // Do check
                $allowed = $token->getAllowed();
                if($allowed){
                    $allowed = explode("\n", $allowed);
                    if(in_array($site, $allowed) || in_array('*', $allowed)){
                        $allow = true;
                    }

                }else{
                    $allow = true;
                }

                $restricted = $token->getRestricted();
                if($restricted){
                    $restricted = explode("\n", $restricted);
                    if(in_array($site, $restricted)){
                        $allow = false;
                    }
                }

                if($allow){
                    return true;
                }else{
                    throw new Exception('No resource found for "' . $request . '"');
                }
            }

            return true;

        }

        // Check login status
        if(!isset($_SESSION['userInfo']))  throw new Exception('No resource found for "' . $request . '" [2]');

        // Check login info
//        $token = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
//
//        if(!$token) {
//            throw new Exception('No resource found for "' . $request . '" [3]');
//        }
//        $token = explode(' ', $token);
//
//        if(!AuthenticateJWS::checkToken($token[1])){
//            throw new Exception('No resource found for "' . $request . '" [4]');
//        }
//
//        $info = AuthenticateJWS::decode($token[1]);
//        $userInfo = $info->claims;
//
//        if($_SESSION['userInfo'] != $userInfo){
//            throw new Exception('No resource found for "' . $request . '" [5]');
//        }
        if(!isset($_SESSION['userInfo'])){
            throw new Exception('No resource found for "' . $request . '" [3]');
        }

        // Check role
        $allow = false;
        foreach($_SESSION['userInfo']['roles'] as $role){
            if(in_array($role, $permission)) $allow = true; break;
        }

        if($allow){
            return true;
        }

        throw new Exception('No resource found for "' . $request . '"');
    }

    protected function userinfo(){
        $token = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
        if(!$token) return false;
        $token = explode(' ', $token);
        $info = AuthenticateJWS::decode($token[1]);
        $entityManager = $this->getEntityManager();
        $repository    = $entityManager->getRepository($this->userEntityClass);
        $userInfo = $info->claims;

        unset($userInfo['expired']);

        // Check token
        if(isset($_SESSION['userInfo']))
        if($_SESSION['userInfo'] != $userInfo){
            throw new Exception('Authenticate fail.');
        }

        $user = $repository->findOneBy(array('name' => $userInfo['userName']));

        $roles = array();
//        foreach($user->getRoles() as $userRole){
//            /**
//             * @var $userRole \OilDatabase\Entity\UserRole
//             */
//            $roles[] = 'Administrator';// $userRole->getRole()->getName();
//        }

        $roles[] = 'Administrator';// $userRole->getRole()->getName();

        $info =  array(
            'userName' => $user->getName(),
            'roles'    => $roles,
            'emailConfirmed' => $user->getEmailConfirmed() ? 'true' : 'false'
        );

        return $info;
    }

    protected function token($request){
        /**
         * @var $repository \Doctrine\ORM\EntityRepository
         */
        $entityManager = $this->getEntityManager();
        $repository    = $entityManager->getRepository($this->userEntityClass);

        // Find user
        $user = $repository->findOneBy(array('email' => $request->get('username'), 'password' => $request->get('password')));

        if(!$user){
            throw new Exception('Login invalid.', 403);
        }

//        $repositoryRole    = $entityManager->getRepository($this->userEntityClass);
//        foreach($user->getRoles() as $userRole){
//            /**
//             * @var $userRole \OilDatabase\Entity\UserRole
//             */
//            $roles[] = 'Administrator';// $userRole->getRole()->getName();
//        }

        $roles = array('Administrator');
        $info =  array(
            'userName' => $user->getName(),
            'roles'    => $roles,
            'emailConfirmed' => $user->getEmailConfirmed() ? 'true' : 'false'
        );

        // Store info to session
        $_SESSION['userInfo'] = $info;

        $info['access_token'] = AuthenticateJWS::createToken($info);

        return $info;
    }

    protected function externalLogins($data){
//        $services = '[{"name":"Google","url":"/api/Account/ExternalLogin?provider=Google&response_type=token&client_id=self&redirect_uri=https%3A%2F%2Fdurandalauth.azurewebsites.net%2F&state=4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1","state":"4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1"},{"name":"Facebook","url":"/api/Account/ExternalLogin?provider=Facebook&response_type=token&client_id=self&redirect_uri=https%3A%2F%2Fdurandalauth.azurewebsites.net%2F&state=4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1","state":"4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1"},{"name":"Twitter","url":"/api/Account/ExternalLogin?provider=Twitter&response_type=token&client_id=self&redirect_uri=https%3A%2F%2Fdurandalauth.azurewebsites.net%2F&state=4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1","state":"4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1"},{"name":"Microsoft","url":"/api/Account/ExternalLogin?provider=Microsoft&response_type=token&client_id=self&redirect_uri=https%3A%2F%2Fdurandalauth.azurewebsites.net%2F&state=4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1","state":"4uS5GmdLyD6Ap891w2jO9kgRAZqrIWVKSRltfiWkIKM1"}]';


        return array();//json_decode($services, true);
    }

    protected function manageinfo($data){
       return $this->userinfo();
    }

} 