<?php

namespace Franzz\Spot;
use Franzz\Objects\PhpObject;
use Franzz\Objects\Db;
use \Settings;

class User extends PhpObject {

	//DB Tables
	const USER_TABLE = 'users';

	//Clearance Levels
	const USER_ACTIVE = 1;
	const USER_INACTIVE = 0;
	const CLEARANCE_USER = 0;
	const CLEARANCE_ADMIN = 9;
	const CLEARANCES = array('user'=>self::CLEARANCE_USER, 'admin'=>self::CLEARANCE_ADMIN);

	//Cookie
	const COOKIE_ID_USER = 'subscriber';
	const COOKIE_DURATION = 60 * 60 * 24 * 365; //1 year

	const DEFAULT_USER = array(
		'id'		=> 0,
		'id_user'	=> 0,
		'name'		=> '',
		'email'		=> '',
		'language'	=> '',
		'timezone'	=> '',
		'active'	=> self::USER_INACTIVE,
		'clearance'	=> self::CLEARANCE_USER
	);

	/**
	 * Database Handle
	 * @var Db
	 */
	private $oDb;

	//User Info
	private $iUserId;
	private $asUserInfo;

	public function __construct(Db &$oDb) {
		parent::__construct(__CLASS__);
		$this->oDb = &$oDb;
		$this->setUserId(0);
		$this->asUserInfo = self::DEFAULT_USER;
		$this->checkUserCookie();
	}

	public function getUserId() {
		return $this->iUserId;
	}

	public function setUserId($iUserId) {
		$this->iUserId = 0;

		if($iUserId > 0) {
			$asUser = $this->getActiveUserInfo($iUserId);
			if(!empty($asUser)) {
				$this->iUserId = $iUserId;
				$this->asUserInfo = $asUser;
			}
		}
	}

	public function getUserInfo() {
		return $this->asUserInfo;
	}

	public function getActiveUserInfo($iUserId) {
		$asUsersInfo = array();
		if($iUserId > 0) $asUsersInfo = $this->getActiveUsersInfo($iUserId);
		return empty($asUsersInfo)?array():array_shift($asUsersInfo);
	}

	public function getActiveUsersInfo($iUserId=-1) {

		//Mapping between user fields and DB fields
		$asSelect = array_keys($this->asUserInfo);
		$asSelect[array_search('id', $asSelect)] = Db::getId(self::USER_TABLE)." AS id";

		//Non-admin cannot access clearance info
		if(!$this->checkUserClearance(self::CLEARANCE_ADMIN)) unset($asSelect['clearance']);

		$asInfo = array(
			'select'	=> $asSelect,
			'from'		=> self::USER_TABLE,
			'constraint'=> array('active'=>self::USER_ACTIVE)
		);
		if($iUserId != -1) $asInfo['constraint'][Db::getId(self::USER_TABLE)] = $iUserId;

		return $this->oDb->selectRows($asInfo);
	}

	public function getLang() {
		return $this->asUserInfo['language'];
	}

	public function addUser($sEmail, $sLang, $sTimezone, $sNickName='') {
		$bSuccess = false;
		$sDesc = '';
		$sEmail = trim($sEmail);

		//Check Email availability
		$iUserId = $this->oDb->selectValue(self::USER_TABLE, Db::getId(self::USER_TABLE), array('email'=>$sEmail, 'active'=>self::USER_ACTIVE));

		if($iUserId > 0) {
			//Just log user in
			$sDesc = 'lang:newsletter.email_exists';
			$bSuccess = true;
		}
		else {
			//Add/Reactivate user
			$iUserId = $this->oDb->insertUpdateRow(
				self::USER_TABLE,
				array('email'=>$sEmail, 'language'=>$sLang, 'timezone'=>$sTimezone, 'active'=>self::USER_ACTIVE),
				array('email')
			);

			if($iUserId==0) $sDesc = 'lang:error.commit_db';
			else {
				$sDesc = 'lang:newsletter.subscribed';
				$bSuccess = true;
			}
		}
		
		if($bSuccess) {
			$this->setUserId($iUserId);

			//Set Cookie (valid 1 year)
			$this->updateCookie(self::COOKIE_DURATION);

			//Update Nickname if user has already posted
			$this->updateNickname($sNickName);

			//Retrieve Gravatar image
			$this->updateGravatar($iUserId, $sEmail);
		}

		return Spot::getResult($bSuccess, $sDesc);
	}

	public function removeUser($iUserId=0) {
		$iUserId = ($iUserId > 0)?$iUserId:$this->getUserId();
		$bSelf = ($iUserId == $this->getUserId());
		$bSuccess = false;
		$sDesc = '';

		if($bSelf || $this->checkUserClearance(self::CLEARANCE_ADMIN)) {
			if($this->getUserId() > 0) {
				$iUserId = $this->oDb->updateRow(self::USER_TABLE, $iUserId, array('active' => self::USER_INACTIVE));
				if($iUserId==0) $sDesc = 'lang:error.commit_db';
				else {
					$sDesc = 'lang:newsletter.unsubscribed';
					if($bSelf) $this->updateCookie(-60 * 60); //Set Cookie in the past, deleting it
					$bSuccess = true;
				}
			}
			else $sDesc = 'lang:newsletter.unknown_email';
		}
		else $sDesc = 'lang:error.no_auth';

		return Spot::getResult($bSuccess, $sDesc);
	}

	public function updateNickname($sNickname) {
		if($this->getUserId() > 0 && $sNickname!='') $this->oDb->updateRow(self::USER_TABLE, $this->getUserId(), array('name'=>$sNickname));
	}

	private function updateGravatar($iUserId, $sEmail) {
		$sImage = ($sEmail != '')?@file_get_contents('https://www.gravatar.com/avatar/'.md5($sEmail).'.png?d=404&s=24'):'';
		$this->oDb->updateRow(self::USER_TABLE, $iUserId, array('gravatar' => base64_encode($sImage)));
	}

	private function checkUserCookie() {
		if(isset($_COOKIE[self::COOKIE_ID_USER])){
			$this->setUserId($_COOKIE[self::COOKIE_ID_USER]);

			//Extend cookie life
			if($this->getUserId() > 0) $this->updateCookie(self::COOKIE_DURATION);
		}
	}

	public function checkUserClearance($iClearance)
	{
		return ($this->asUserInfo['clearance'] >= $iClearance);
	}

	public function setUserClearance($iUserId, $iClearance) {
		$bSuccess = false;
		$sDesc = '';

		if(!$this->checkUserClearance(self::CLEARANCE_ADMIN)) $sDesc = 'unauthorized';
		else {
			if(!in_array($iClearance, self::CLEARANCES)) $sDesc = 'Setting wrong clearance "'.$iClearance.'" to user ID "'.$iUserId.'"';
			else {
				$iUserId = $this->oDb->updateRow(self::USER_TABLE, $iUserId, array('clearance'=>$iClearance));
				if(!$iUserId) $sDesc = 'lang:error.commit_db';
				else $bSuccess = true;
			}
		}

		return Spot::getResult($bSuccess, $sDesc);
	}

	private function updateCookie($iDeltaTime) {
		setcookie(self::COOKIE_ID_USER, ($iDeltaTime < 0)?'':$this->getUserId(), array('samesite' => 'Lax', 'expires' => time() + $iDeltaTime));
	}
}
