<?php

namespace EesyPHP\Auth;

use EesyPHP\App;
use EesyPHP\Db as DbConnection;
use EesyPHP\Log;

use Exception;

class Db extends Backend {

  /**
   * Database connection object
   * @var \EesyPHP\Db|null
   */
  private static $db = null;

  /**
   * Database connection parameters
   */

  /**
   * @var string
   */
  private static $dsn;

  /**
   * @var string|null
   */
  private static $user;

  /**
   * @var string|null
   */
  private static $password;

  /**
   * @var array
   */
  private static $options;

  /**
   * Users table name
   * @var string
   */
  private static $users_table;

  /**
   * Username field name
   * @var string
   */
  private static $username_field;

  /**
   * Password field name
   * @var string
   */
  private static $password_field;

  /**
   * List of Db fields exposed in User object
   * @var array
   */
  private static $exposed_fields;

  /**
   * Initialize
   * @return boolean
   */
  public static function init() {
    // Set config default values
    App :: set_default(
      'auth.db',
      array(
        'dsn' => null,
        'user' => null,
        'password' => null,
        'options' => array(),
        'users_table' => 'users',
        'username_field' => 'username',
        'password_field' => 'password',
        'exposed_fields' => array('name', 'mail'),
      )
    );
    self :: $dsn = App::get('auth.db.dsn', null, 'string');
    if (!self :: $dsn) {
      Log :: warning('No database DSN configured, can not initialize this authentication backend');
      return false;
    }
    self :: $user = App::get('auth.db.user', null, 'string');
    self :: $password = App::get('auth.db.password', null, 'string');
    self :: $options = App::get('auth.db.options', null, 'array');
    self :: $users_table = App::get('auth.db.users_table', null, 'string');
    self :: $username_field = App::get('auth.db.username_field', null, 'string');
    self :: $password_field = App::get('auth.db.password_field', null, 'string');
    self :: $exposed_fields = App::get('auth.db.exposed_fields', null, 'array');
    return true;
  }

  /**
   * Connect to database
   * @return void
   */
  private static function connect() {
    if (!self :: $db)
      self :: $db = new DbConnection(
        self :: $dsn, self :: $user, self :: $password, self :: $options
      );
  }

  /**
   * Retreive a user by its username
   * @param string $username
   * @return \EesyPHP\Auth\User|null|false The user object if found, null it not, false in case of error
   */
  public static function get_user($username) {
    self :: connect();
    try {
      $query = self :: $db -> fpdo -> from(self :: $users_table)
        -> select(null)
        -> select(self :: $exposed_fields)
        -> where(self :: $username_field, $username);

      $result = $query -> execute();
      $info = $result -> fetch();
      if ($info === false)
        return null;
      return new User($username, '\\EesyPHP\\Auth\\Db', $info);
    }
    catch (Exception $e) {
      Log :: error("Error retreiving user %s info from database: %s", $username, $e->getMessage());
    }
    return false;
  }

  /**
   * Check a user password
   * @param \EesyPHP\Auth\User $user The user object
   * @param string $password The password to check
   * @return boolean
   */
  public static function check_password($user, $password) {
    self :: connect();
    try {
      $query = self :: $db -> fpdo -> from(self :: $users_table)
        -> select(null)
        -> select(self :: $password_field)
        -> where(self :: $username_field, $user->username);

      $result = $query -> execute();
      $info = $result -> fetch();
      if ($info === false)
        return false;
      return password_verify($password, $info['password']);
    }
    catch (Exception $e) {
      Log :: error("Error retreiving user %s password from database: %s", $user, $e->getMessage());
    }
    return false;
  }
}
