<?php

namespace EesyPHP\Auth;

use EesyPHP\App;
use EesyPHP\Auth;
use EesyPHP\I18n;
use EesyPHP\Log;
use EesyPHP\Tpl;
use EesyPHP\Url;
use function EesyPHP\vardump;

class Http extends Method {

  /**
   * Method to retreive HTTP credentials
   * @var string
   */
  private static $method;

  /**
   * HTTP realm string (use to compute WWW-Authenticate HTTP header)
   * @var string
   */
  private static $realm;

  /**
   * Initialize
   * @return boolean
   */
  public static function init() {
    // Set default config values
    App :: set_default(
      'auth.http',
      array(
        'method' => 'PHP_AUTH',
        'realm' => _('Authentication required'),
        'trust_without_password_challenge' => false,
      )
    );
    self :: $method = App::get('auth.http.method', null, 'string');
    self :: $realm = App::get(
      'auth.http.realm', null, 'string');
    return true;
  }

  /**
   * Retreive HTTP authentication data
   * @return array|false array('username' => '[login]', 'password' => '[password]') or false
   */
  private static function get_auth_data() {
    switch(self :: $method) {
        case 'AUTHORIZATION':
            Log :: debug("Auth HTTP: use AUTHORIZATION method");
            if (isset($_SERVER['HTTP_AUTHORIZATION']) && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
                $auth_data = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
                if (is_array($auth_data) && count($auth_data) == 2) {
                    return array(
                        'username' => $auth_data[0],
                        'password' => $auth_data[1],
                    );
                }
                else
                    Log :: error("Fail to parse HTTP_AUTHORIZATION environnement variable.");
            }
            break;
        case 'REMOTE_USER':
            Log :: debug("Auth HTTP : use REMOTE_USER method");
            if (isset($_SERVER['REMOTE_USER']) && !empty($_SERVER['REMOTE_USER'])) {
                return array(
                    'username' => $_SERVER['REMOTE_USER'],
                    'password' => false,
                );
            }
            break;
        case 'PHP_AUTH':
        default:
            Log :: debug("Auth HTTP : use PHP_AUTH method");
            if (isset($_SERVER['PHP_AUTH_USER']) && !empty($_SERVER['PHP_AUTH_USER'])) {
                return array(
                    'username' => $_SERVER['PHP_AUTH_USER'],
                    'password' => $_SERVER['PHP_AUTH_PW'],
                );
            }
            break;
    }
    Log :: trace("HTTP::get_auth_data(): no auth data found\n".vardump($_SERVER));
    return false;
  }

  /**
   * Log user
   * @param bool $force Force user authentication
   * @return \EesyPHP\Auth\User|null
   */
  public static function login($force=false) {
    $auth_data = self :: get_auth_data();
    if (!$auth_data) {
      if ($force) self :: force_login();
      return null;
    }

    if (App :: get('auth.http.trust_without_password_challenge', null, 'bool'))
      $user = Auth :: get_user($auth_data['username']);
    else
      $user = Auth :: authenticate($auth_data['username'], $auth_data['password']);

    if (!$user && $force)
      self :: force_login();

    return $user;
  }

  /**
   * Force HTTP user authentification
   * @return never
   */
  public static function force_login() {
    header('HTTP/1.1 401 Authorization Required');
    header(
      sprintf('WWW-Authenticate: Basic realm="%s"', addslashes(self :: $realm))
    );
    if (Tpl::initialized()) {
      Tpl :: display("must_login.tpl", I18n::_("Access denied"));
    }
    else {
      printf("<h1>%s</h1>", I18n::_("Access denied"));
      printf("<p>%s</p>", I18n::_("You must login to access this page."));
      printf(
        "<p><a href='%s'>%s</a></p>",
        Url :: public_root_url(),
        I18n::_("You must login to access this page.")
      );
    }
    exit();
  }

  /**
   * Logout
   * @return void
   */
  public static function logout() {
    self :: force_login();
  }

}
