<?php
  /**
   * Authentication Class
   *
   * @package Wojo Framework
   * @author wojoscripts.com
   * @copyright 2019
   * @version $Id: auth.class.php, v1.00 2019-06-05 10:12:05 gewa Exp $
   */

  if (!defined("_WOJO"))
      die('Direct access to this location is not allowed.');

  class Auth
  {

      public $logged_in = 0;
      public $uid = 0;
      public $username;
      public $sesid;
      public $email;
      public $name;
      public $fname;
      public $lname;
	  public $company;
	  public $country;
	  public $avatar;
      public $usertype = null;
      public $userlevel = 0;
      public $lastlogin;
      public $lastip;
	  public $acl = array();
	  public $access = null;
	  public static $userdata = array();
	  public static $udata = array();
	  
	  const cost = 10;

      /**
       * Auth::__construct()
       * 
       * @return
       */
      public function __construct()
      {
          $this->logged_in = $this->loginCheck();

          if (!$this->logged_in) {
              $this->username = App::Session()->set('WFM_username', '');
              $this->sesid = sha1(session_id());
              $this->userlevel = 0;
          }
      }

      /**
       * Auth::loginCheck()
       * 
       * @return
       */
      private function loginCheck()
      {
		  $session = App::Session();
          if ($session->isExists('WFM_username') and $session->get('WFM_username') != "") {
              $this->uid = $session->get('userid');
              $this->username = $session->get('WFM_username');
              $this->email = $session->get('email');
              $this->fname = $session->get('fname');
              $this->lname = $session->get('lname');
              $this->name = $session->get('fname') . ' ' . $session->get('lname');
			  $this->country = $session->get('country');
			  $this->company = $session->get('company');
			  $this->avatar = $session->get('avatar');
              $this->lastlogin = $session->get('lastlogin');
              $this->lastip = $session->get('lastip');
              $this->sesid = sha1(session_id());
              $this->usertype = $session->get('type');
              $this->userlevel = $session->get('userlevel');
		      $this->acl = $session->get('acl');
			  $this->access = $session->get('access');
			  self::$userdata = $session->get('userdata');
			  self::$udata = $this;
			  
              return true;
          } else {
              return false;
          }
      }

      /**
       * Auth::is_Admin()
       * 
       * @return
       */
      public function is_Admin()
      {
          $level = array(9,8,7);
          return (in_array($this->userlevel, $level));

      }

      /**
       * Auth::is_User()
       * 
       * @return
       */
      public function is_User()
      {
          $level = array(1);
          return (in_array($this->userlevel, $level) and $this->usertype == "member");

      }
	  
      /**
       * Auth::login()
       * 
       * @param mixed $username
       * @param mixed $password
	   * @param bool $auto
       * @return
       */
      public function login($username, $password, $auto = true)
      {
          if ($username == "" && $password == "") {
              $json['message'] = Lang::$word->LOGIN_R5;
          } else {
              $status = $this->checkStatus($username, $password);
			  
              switch ($status) {
                  case "e":
                      $json['message'] = Lang::$word->LOGIN_R1;
                      break;

                  case "b":
                      $json['message'] = Lang::$word->LOGIN_R2;
                      break;

                  case "n":
                      $json['message'] = Lang::$word->LOGIN_R3;
                      break;

                  case "t":
                      $json['message'] = Lang::$word->LOGIN_R4;
                      break;
              }
          }
          if (empty($json['message']) && $status == "y") {
			  $session = App::Session();
              $row = $this->getUserInfo($username);
              $this->uid = $session->set('userid', $row->id);
              $this->username = $session->set('WFM_username', $row->username);
              $this->fullname = $session->set('fullname', $row->fname . ' ' . $row->lname);
              $this->fname = $session->set('fname', $row->fname);
              $this->lname = $session->set('lname', $row->lname);
              $this->email = $session->set('email', $row->email);
			  $this->country = $session->set('country', $row->country);
			  $this->company = $session->set('company', $row->company);
              $this->userlevel = $session->set('userlevel', $row->userlevel);
              $this->usertype = $session->set('type', $row->type);
			  $this->avatar = $session->set('avatar', $row->avatar);
              $this->lastlogin = $session->set('lastlogin', Db::toDate());
              $this->lastip = $session->set('lastip', Url::getIP());

			  $result = self::getAcl($row->type);
			  $privileges = array();
			  for($i = 0; $i < count($result); $i++){
				  $privileges[$result[$i]->code] = ($result[$i]->active == 1) ? true : false;
			  }
		      $this->acl = $session->set('acl', $privileges);

              $data = array('lastlogin' => Db::toDate(), 'lastip' => Validator::sanitize(Url::getIP()));
              Db::run()->update(Users::mTable, $data, array('id' => $row->id));
			  self::$userdata = $session->set('userdata', $row);
			  $this->access = $session->set('access', self::getPermissions($row->id));
			  self::setUserCookies($session->get('WFM_username'), $session->get('fullname'), $session->get('avatar'));
			  
              $json['type'] = "success";
			  $json['title'] = Lang::$word->SUCCESS;
          } else {
              $json['type'] = "error";
			  $json['title'] = Lang::$word->ERROR;
		  }
		  ($auto == true) ? print json_encode($json) : null;
      }


      /**
       * Auth::checkStatus()
       * 
       * @param mixed $username
       * @param mixed $pass
       * @return
       */
      public function checkStatus($username, $pass)
      {

          $username = Validator::sanitize($username, "default", 60);
          $pass = Validator::sanitize($pass, "default", 20);

          $where = array('username =' => $username, 'or email =' => $username);
          $row = Db::run()->first(Users::mTable, array(
              'id',
              'hash',
              'active'), $where);

          if (!$row)
              return "e";

          $validpass = password_verify($pass, $row->hash);

          if (!$validpass)
              return "e";

          switch ($row->active) {
              case "b":
                  return "b";
                  break;

              case "n":
                  return "n";
                  break;

              case "t":
                  return "t";
                  break;

              case "y" and $validpass == true:
                    if (password_needs_rehash($row->hash, PASSWORD_DEFAULT, array('cost' => self::cost))) {
                        $hash = self::doHash($pass);
                        
						Db::run()->update($table, array("hash" => $hash), array('id' => $row->id));
                    }
                  return "y";
                  break;
          }

      }

	  /**
	   * Auth::getUserInfo()
	   * 
	   * @param mixed $username
	   * @return
	   */
	  public function getUserInfo($username)
	  {
		  $username = Validator::sanitize($username, "string");
		  $row = Db::run()->first(Users::mTable, null, array('username =' => $username, 'OR email =' => $username));

		  return ($row) ? $row : 0;
	  }

      /**
       * Auth::getPermissions()
       * 
       * @return
       */
	  public static function getPermissions($uid)
	  {
		  $sql = "
		  SELECT GROUP_CONCAT(project_id) as projects
		  FROM `" . Project::pxTable . "` 
		  WHERE user_id = ? 
		  GROUP BY user_id;";
		  
		  $row = Db::run()->pdoQuery($sql, array($uid))->result();
		  return ($row) ? $row : 0;

	  }
	  
      /**
       * Auth::getAcl() 
       * 
       * @param mixed $role
       * @return
       */
	  public static function getAcl($role = '')
	  {
		  $sql = "
		  SELECT 
			p.code,
			p.name,
			p.description,
			rp.active 
		  FROM `".Users::rpTable."` rp 
			INNER JOIN `".Users::rTable."` r 
			  ON rp.rid = r.id 
			INNER JOIN `".Users::pTable."` p 
			  ON rp.pid = p.id 
		  WHERE r.code = ? ;";
		  
		  return Db::run()->pdoQuery($sql, array($role))->results();
		  
	  }

      /**
       * Auth::hasPrivileges()
       * 
       * @param mixed $code
       * @param mixed $val
       * @return
       */
	  public static function hasPrivileges($code = '', $val = '')
	  {
		  $privileges_info = App::Session()->get('acl');
		  if (!empty($val)) {
			  if (isset($privileges_info[$code]) && is_array($privileges_info[$code])) {
				  return in_array($val, $privileges_info[$code]);
			  } else {
				  return ($privileges_info[$code] == $val);
			  }
		  } else {
			  return (isset($privileges_info[$code]) && $privileges_info[$code] == true) ? true : false;
		  }
	  }
	
      /**
       * Auth::logout()
       * 
       * @return
       */
      public function logout()
      {
          App::Session()->endSession();
          $this->logged_in = false;
          $this->username = "Guest";
          $this->userlevel = 0;
      }

      /**
       * Auth::usernameExists()
       * 
       * @param mixed $username
       * @return
       */
      public static function usernameExists($username)
      {
          $username = Validator::sanitize($username, "string");
          if (strlen($username) < 4)
              return 1;

          //Username should contain only alphabets, numbers, or underscores.Should be between 4 to 15 characters long
          $valid_uname = "/^[a-zA-Z0-9_]{4,15}$/";
          if (!preg_match($valid_uname, $username))
              return 2;

		  $row = Db::run()->select(Users::mTable, array('username'), array('username' => $username), 'LIMIT 1')->result();

          return ($row) ? 3 : false;
      }

      /**
       * Auth::emailExists()
       * 
       * @param mixed $email
       * @return
       */
      public static function emailExists($email)
      {
          $row = Db::run()->select(Users::mTable, array('email'), array('email' => $email), ' LIMIT 1')->result();

          if ($row) {
              return true;
          } else
              return false;
      }

      /**
       * Auth::checkAcl()
       * 
       * @return
       */
      public static function checkAcl()
      {

          $acctypes = func_get_args();
          foreach ($acctypes as $type) {
              $args = explode(',', $type);
              foreach ($args as $arg) {
                  if (App::Auth()->usertype == $arg)
                      return true;
              }
          }
          return false;
      }
	  
      /**
       * Auth::setUserCookies()
       * 
       * @param mixed $username
       * @param mixed $name
	   * @param mixed $avatar
       * @return
       */
      public static function setUserCookies($username, $name, $avatar)
      {
		  $avatar = empty($avatar) ? "blank.png" : $avatar;
		  setcookie("WFM_loginData[0]", $username, strtotime('+30 days'));
		  setcookie("WFM_loginData[1]", $name, strtotime('+30 days'));
		  setcookie("WFM_loginData[2]", $avatar, strtotime('+30 days'));
      }

      /**
       * Auth::getUserCookies()
       * 
       * @return
       */
      public static function getUserCookies()
      {
          if(isset($_COOKIE['WFM_loginData'])) {
			  $data = array(
				'username' => $_COOKIE['WFM_loginData'][0],
				'name' => $_COOKIE['WFM_loginData'][1],
				'avatar' => $_COOKIE['WFM_loginData'][2]
			  );
			  return $data;
		  } else {
			  return false;
		  }
          
      }
	  
      /**
         * Auth::doHash()
         *
         * @param string $password
         */
        public static function doHash($password)
        {
            return password_hash($password, PASSWORD_DEFAULT, array('cost' => self::cost));
            
        }
	  
      /**
       * Auth::generateToken()
       * 
       * @return
       */
      public static function generateToken($length = 24)
      {
          return bin2hex(openssl_random_pseudo_bytes($length));
          
      }

  }