<?php
	require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'class.api.php');
	require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'class.group.php');

	class API_USER extends API
	{
		var $userid = 0;
		var $username = '';
		var $pass = '';
		var $firstname = '';
		var $lastname = '';
		var $email = '';
		var $status = 0;
		var $groups = '';
		var $forgotpasscode = '';
		var $sessionid = '';
		var $tokencode = '';

		var $fields = array (
			'userid',
			'username',
			'pass',
			'firstname',
			'lastname',
			'status',
			'email',
			'forgotpasscode',
			'sessionid',
			'tokencode'
		);

		var $pk = 'userid';
		
		/**
		* NumUsers
		* Get a count of the number of the users in the system
		*
		* @return integer The number of users in the current system
		*/
		function NumUsers()
		{
			if (!$this->db) {
				return -1;
			}

			$query = 'SELECT COUNT(*)
				FROM `'.$this->table.'`';

			return $this->db->FetchOne($query);
		}

		/**
		* create
		* create the user
		* the parent is overriden here so we can set the pass to the md5 of
		* password, forgotpasscode and initialise the groups variable
		*
		* @return bool was the creation a success ?
		*/
		function create()
		{
			if (!isset($_POST['groups']) || !is_array($_POST['groups'])) {
				$_POST['groups'] = array();
			}
			$_POST['forgotpasscode'] = '';
			if (!isset($_POST['sessionid'])) {
				$_POST['sessionid'] = '';
			}

			$_POST['tokencode'] = generateTokenCode($_POST['username']);
			if (isset($_POST['password'])) {
				$_POST['pass'] = md5(md5($_POST['tokencode']) . md5($_POST['password']));
			}
			
			if (!AKB_HELPER::valid_username($this->NumUsers()+1)) {
				$this->error = sprintf(GetLang('UserLimitReached'), $this->NumUsers());
				return false;
			}

			return parent::create();
		}

		// dont delete the user if its the last one
		// dont delete the current user
		/**
		* delete
		* delete the user
		* the parent is overriden so that we can put some restrictions on which
		* users can be deleted and by who
		*
		* @param int $id the id of the user to delete
		*
		* @return bool was the deletion a success or not ?
		*/
		function delete($id=0)
		{
			// Stop if this is the last user
			if ($this->NumUsers() < 2) {
				return false;
			}

			// Stop if we are trying to delete ourselves
			if ($this->userid == $id) {
				return false;
			}

			// Stop if we are trying to delete the admin user
			if ($this->userid == 1) {
				return false;
			}

			// Perform the LDAP operation to save ldap details.
			$user = new API_USER();
			$user ->load($id);
			if (isset($GLOBALS['AKB_LDAP']) && isset($GLOBALS['ldapEnabled']) && $GLOBALS['ldapEnabled'] 
			&& API_LDAP::isLdapUser($user->pass)) {
				if (isset($GLOBALS['ldapRemoveUser']) && $GLOBALS['ldapRemoveUser'] == '1') {
					API_LDAP::updateUserDetails($user->username, array('status' => 0));
				}
			}
			
			if (!parent::delete($id)) {
				return false;
			}

			// Delete the assocaitions in the members table
			$query = "DELETE FROM `".$this->tablePrefix."members`
			WHERE `userid` IN (".((int) $id).")";
			
			$this->db->Query($query);

			
			return true;
		}

		/**
		* multiDelete
		* delete multiple users in one go
		*
		* @param array $ids an array of user ids to delete
		*
		* @return bool were the users deleted ok ?
		*/
		function multiDelete($ids=0)
		{
			// Stop if we are trying to delete ourselves
			if (in_array($this->userid, array_keys($ids))) {
				return false;
			}

			// Stop if we are trying to delete the admin user
			if (in_array(1, array_keys($ids))) {
				return false;
			}

			// Stop if this is the last user
			if (($this->NumUsers() - count($ids)) < 1) {
				return false;
			}

			// Perform the LDAP operation to save ldap details.
			foreach (array_keys($ids) as $id) {
				$user = new API_USER();
				$user->load($id);
				
				if (isset($GLOBALS['AKB_LDAP']) && isset($GLOBALS['ldapEnabled']) && $GLOBALS['ldapEnabled'] 
				&& API_LDAP::isLdapUser($user->pass)) {
					if (isset($GLOBALS['ldapRemoveUser']) && $GLOBALS['ldapRemoveUser'] == '1') {
						API_LDAP::updateUserDetails($user->username, array('status' => 0));
					}
				}
			}
			
			if (!parent::multiDelete($ids)) {
				return false;
			}

			// Delete the assocaitions in the members table
			$query = "DELETE FROM `".$this->tablePrefix."members`
			WHERE `userid` IN (".(implode(',', array_keys($ids))).")";
			$this->db->Query($query);

			return true;
		}

		/**
		* multiUpdateUserType
		* Update the user's account type
		*
		* @param array $ids an array of user ids to delete
		*
		* @return bool were the users deleted ok ?
		*/
		function multiUpdateUserType($ids=0, $type='@LDAP')
		{

			// Stop if we are trying to delete ourselves
			if (in_array($this->userid, array_keys($ids))) {
				return false;
			}

			// Stop if we are trying to delete the admin user
			if (in_array(1, array_keys($ids))) {
				return false;
			}

			// Stop if this is the last user
			if (($this->NumUsers() - count($ids)) < 1) {
				return false;
			}
			
			if (!parent::multiUpdateField('pass', '@LDAP', $ids)) {
				return false;
			}

			return true;
		}

		/**
		* checkPass
		* Is the password for this user correct and are they enabled
		*
		* @param string $pass The password to check
		*
		* @return bool If the password correct and the user enabled returns true
		*/
		function checkPass($pass)
		{
			if (strlen($pass) == 32) {
				return ($this->pass == md5(md5($this->tokencode) . $pass) && $this->status == 1);
			}
			else {
				return ($this->pass == md5(md5($this->tokencode) . md5($pass)) && $this->status == 1);
			}
		}

		/**
		* join
		* Have this user join a group
		*
		* @param $groupid the id of the group for the user to join
		*
		* @return bool was the join a success ?
		*/
		function join($groupid)
		{
			if (!$this->is_positive_int($groupid)) {
				return false;
			}

			if (!$this->is_positive_int($this->userid)) {
				return false;
			}

			if (is_array($this->groups) && !empty($this->groups)) {
				// Stop if we are already in that group
				foreach ($this->groups as $group) {
					if ($group->groupid == $groupid) {
						return true;
					}
				}
			}

			// Stop if we dont have access to the database
			if (!$this->db) {
				return false;
			}

			$query = 'INSERT INTO `'.$this->tablePrefix.'members`
				(`userid`, `groupid`) values ('.$this->userid.', '.$groupid.')';

			if ($this->db->Query($query)) {
				return true;
			} else {
				return false;
			}
		}

		/**
		* part
		* Have this user leave a group
		*
		* @param $groupid the id of the group for the user to leave
		*
		* @return bool was the part a success ?
		*/
		function part($groupid)
		{
			if (!$this->is_positive_int($groupid)) {
				return false;
			}

			if (!$this->is_positive_int($this->userid)) {
				return false;
			}

			// We can't part a group if we arn't a member of it so check to
			// ensure we are a member of the group first
			$amAMember = false;
			if (is_array($this->groups) && !empty($this->groups)) {
				foreach ($this->groups as $group) {
					if ($group->groupid == $groupid) {
						$amAMember = true;
						break;
					}
				}
			}

			if (!$amAMember) {
				return true;
			}

			// Stop if we dont have access to the database
			if (!$this->db) {
				return false;
			}

			$query = 'DELETE FROM `'.$this->tablePrefix.'members`
				WHERE `userid` = '.$this->userid.' AND `groupid` = '.$groupid.'';

			if ($this->db->Query($query)) {
				return true;
			} else {
				return false;
			}
		}

		/**
		* loadPerms
		* load the permissions for the user from the database
		*
		* @return bool was the load a success ?
		*/
		function loadPerms()
		{
			// reset current group.
			$this->groups = array();
			
			// Stop if the userid isnt an int
			if ($this->userid != (int) $this->userid) {
				return false;
			}

			// Stop if the userid isnt positive
			if ($this->userid <= 0) {
				return false;
			}

			$query = 'SELECT `groupid` FROM `'.$this->tablePrefix.'members`
				WHERE `userid` = '.$this->userid;

			$result = $this->db->Query($query);
			while ($group = $this->db->Fetch($result)) {
				$g = new API_GROUP();
				$g->load($group['groupid']);
				$this->groups[] = $g;
			}
			return true;
		}

		/**
		* load
		* load the user by userid
		*
		* @param int $id the id of the user to load
		*
		* @return bool was the load a success ?
		*/
		function load($id)
		{
			return (parent::load($id) && $this->loadPerms());
		}

		/**
		* find
		* find a user using a field with a unique index on it
		*
		* @param string $field the name of the field to check
		* @param string $val the value to search for
		*
		* @return bool did we find what we were looking for ?
		*/
		function find($field, $val)
		{
			return (parent::find($field, $val) && $this->loadPerms());
		}

		/**
		* verify
		* Verify if this user has a particular type of access to an area
		*
		* @param string $area the name of the area to check (questions, cats etc)
		* @param string $perm the name of the permission to check (del, create etc)
		*@param int $id The specific ids of $area they can access if they are
		* restricted to only certain parts of the area
		*
		* @return bool do they have access ?
		*/
		function verify($area, $perm, $id=0)
		{
			// If they are the super user allow access
			if ($this->userid == 1) {
				return true;
			}

			if (!is_array($this->groups) || empty($this->groups)) {
				return false;
			}

			foreach ($this->groups as $group) {
				if ((isset($group->perms[$area][$perm])) && ($group->perms[$area][$perm]) && ((!isset($group->applies['feonly'])) || ((isset($group->applies['feonly'])) && ($group->applies['feonly'] == 0)))) {
					if (!isset($group->applies[$area])) {
						// Handle the case where there is no applies for that area
						return true;
					} else if (!is_array($group->applies[$area])) {
						// Handle the case where its been set to all
						return true;
					} else if (in_array($id, $group->applies[$area]) || $id == 0) {
						// Handle the case where its been set to specific ids
						return true;
					}
				}
			}
			return false;
		}

		/**
		* save
		* save the user to the database
		*
		* @return bool was the save a success ?
		*/
		function save()
		{
			// Stop if the password doesnt match the confirmation
			if (isset($_POST['password1'])) {
				if ($_POST['password'] != $_POST['password1']) {
					return false;
				}
			}

			if (!isset($_POST['forgotpasscode'])) {
				$_POST['forgotpasscode'] = '';
			}

			// Setup the encrypted password
			if (!empty($_POST['password'])) {
				$_POST['pass'] = md5(md5($this->tokencode) . md5($_POST['password']));
			} else {
				$_POST['pass'] = $this->pass;
			}
			// Perform the LDAP operation to save details.
			if (isset($GLOBALS['AKB_LDAP']) && isset($GLOBALS['ldapEnabled']) && $GLOBALS['ldapEnabled'] 
			&& API_LDAP::isLdapUser($this->pass)) {
				if (isset($GLOBALS['ldapAllowUserUpdateDetails']) && $GLOBALS['ldapAllowUserUpdateDetails']) {
					if(!API_LDAP::updateUserDetails($_POST['username'], $_POST)) {
						return false;
					}
				}
			}
			
			return parent::save();
		}

		/**
		* __sleep
		* php magic function to define which member vars to include when this
		* class is serialized
		*
		* @return array the names of the vars to serialize
		*/
		function __sleep()
		{
			return array_merge(parent::__sleep(), $this->fields, array('groups'));
		}

		/**
		* validate_userid
		*
		* Ensure the userid is a pos int
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_userid($var)
		{
			return $this->is_positive_int($var);
		}

		/**
		* validate_name
		*
		* Ensure the name isn't blank or too long
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_name($var)
		{
			if (empty($var)) {
				return false;
			}

			if (strlen($var) > 50) {
				return false;
			}

			return true;
		}

		/**
		* validate_username
		*
		* Ensure the name isn't blank or too long
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_username($var)
		{
			if (empty($var)) {
				return false;
			}

			if (strlen($var) > 50) {
				return false;
			}

			return true;
		}

		/**
		* validate_pass
		*
		* Ensure the password is in a valid format
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_pass($var)
		{
			// if this is LDAP password
			if ($var == '@LDAP') {
				return true;
			}
			// The md5 of something is 32 chars long
			if (strlen($var) != 32) {
				return false;
			}

			return preg_match('/[0-9a-f]+/', $var);
		}

		/**
		* validate_firstname
		*
		* Ensure the firstname isnt too long
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_firstname($var)
		{
			return strlen($var) <= 50;
		}

		/**
		* validate_lastname
		*
		* Ensure the lastname isnt too long
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_lastname($var)
		{
			return strlen($var) <= 50;
		}

		/**
		* validate_status
		*
		* Ensure the status of a user is a 0 or a 1
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_status($var)
		{
			// The super user status cannot be changed
			if ($this->userid == 1) {
				return false;
			}

			return ($var == 0 || $var == 1);
		}

		/**
		* validate_email
		*
		* Ensure the email of a user, if specified, is in a valid format
		*
		* @param string $var
		*
		* @return bool
		*/
		function validate_email($var)
		{
			if (empty($var)) {
				return true;
			}

			return is_email_address($var);
		}
		
		/**
		* isLdapUser
		*
		*/
		function isLdapUser()
		{
			if ($this->pass == '@LDAP') {
				return true;
			}
			return false;
		}
	}

?>
