<?php
/**
 * MAMS API
 *
 * A class to expose the MAMS API methods available
 * to all other modules.
 *
 * @since 1.1
 * @author Fernando Morgado  aka Jo Morg
 *
 * @package MAMS
 */

namespace MAMS;

class api
{
  /**
   * the error modes will be used only on methods that can throw exceptions
   * That won't be the case for all methods
   */
  /**
   * @const int NONE the api won't throw exceptions
   */
  public const ERROR_MODE_NONE = 0;
  /**
   * @const int EXCEPTION the api will throw exceptions
   */
  public const ERROR_MODE_EXCEPTION = 1;
  static private $_error_mode = self::ERROR_MODE_EXCEPTION;
  
  private static array $_error_modes = [
    self::ERROR_MODE_NONE,
    self::ERROR_MODE_EXCEPTION
  ];
  
  use \CMSMSExt\core\TSingleton;
  
  /**
   * The error modes will be used only on methods
   * that can throw exceptions.
   * That won't be the case for all methods
   *
   * @param $mode
   *
   * @return \MAMS\api
   */
  public function SetErrorMode($mode)
  {
    if( !\in_array($mode, self::$_error_modes) )
    {
      throw new \InvalidArgumentException('Invalid error mode');
    }
    
    self::$_error_mode = $mode;
    
    return $this;
  }
  
  /**
   * @return int
   */
  public function GetErrorMode()
  {
    return self::$_error_mode;
  }
  
  /**
   * @return \CmsModule MAMS
   */
  public function GetMams()
  {
    return utils::get_mod();
  }
  
  /**
   * Retrieves the User Manipulator from MAMS.
   *
   * Given the way MAMS works, the Manipulator can be extended
   * by external modules.
   * This returns the MAMS Manipulator currently in use.
   *
   * @return \MAMSManipulator
   */
  public function GetManipulator()
  {
    return $this->GetMams()->GetManipulator();
  }
  
  
  /**
   * from the abstract class
   */
  
  
  /**
   * end of from the abstract class
   */
  
  /**
   * from users manipulator
   */
  
  
  /**
   * @param $uid
   *
   * @return false|string
   */
  public function GetEncryptionKey($uid = -1)
  {
    return $this->GetManipulator()->GetEncryptionKey($uid);
  }
  
  /**
   * @param $uid
   * @param $data
   *
   * @return string
   */
  public function DecryptUserData($uid, $data)
  {
    return $this->GetManipulator()->DecryptUserData($uid, $data);
  }
  
  
  /**
   * @return mixed
   */
  public function CountTempCodeRecords()
  {
    return $this->GetManipulator()->CountTempCodeRecords();
  }
  
  /**
   * @param      $expirycode
   * @param null $return pass a variable to get the return from the manipulator
   *                     note: only works if not throwing exceptions
   *
   * @return \MAMS\api
   */
  public function ExpireTempCodes($expirycode, &$return = null)
  {
    $result = $this->GetManipulator()->ExpireTempCodes($expirycode);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not expire temp codes');
    }
    
    $return = $result;
    
    return $this;
  }
  
  /**7
   * @param      $uid
   * @param null $return pass a variable to get the return from the manipulator
   *                     note: only works if not throwing exceptions
   *
   * @return \MAMS\api
   */
  public function RemoveUserTempCode($uid, &$return = null)
  {
    $result =  $this->GetManipulator()->RemoveUserTempCode($uid);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not remove temp codes');
    }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $uid
   *
   * @return int
   */
  public function GetUserTempCode($uid)
  {
    return (int)$this->GetManipulator()->GetUserTempCode($uid);
  }
  
  
  /**
   * @param $uid
   * @param $code
   *
   * @return \MAMS\api
   */
  public function SetUserTempCode($uid, $code, &$return = null)
  {
    $result = $this->GetManipulator()->SetUserTempCode($uid, $code);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not set temp code');
    }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $name
   * @param $newname
   * @param $prompt
   * @param $length
   * @param $type
   * @param $maxlength
   * @param $attribs
   * @param $force_unique
   * @param $encrypt
   *
   * @return \MAMS\api
   */
  public function SetPropertyDefn(
    $name,
    $newname,
    $prompt,
    $length,
    $type,
    $maxlength = 0,
    $attribs = '',
    $force_unique = 0,
    $encrypt = 0
  )
  {
    $result = $this->GetManipulator()->SetPropertyDefn($name, $newname, $prompt, $length, $type, $maxlength, $attribs, $force_unique, $encrypt, $return = null);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not set property definition');
    }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $name
   *
   * @return \MAMS\api
   */
  public function DeletePropertyDefn($name, &$return = null)
  {
    $result = $this->GetManipulator()->DeletePropertyDefn($name);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not delete property ' . $name);
    }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $title
   *
   * @return array
   */
  public function GetPropertyGroupRelations($title)
  {
    $result =  $this->GetManipulator()->GetPropertyGroupRelations($title);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException($result[1]);
    }
    
    if(self::ERROR_MODE_NONE === self::$_error_mode)
    {
      return $result;
    }
    
    return $result[1];
  }
  
  
  /**
   * Return the unix timestamp of the user's expiry date
   * or false;
   *
   * @param $uid
   *
   * @return false|int
   */
  public function GetExpiryDate($uid)
  {
    $result = $this->GetManipulator()->GetExpiryDate($uid);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not get expiry date');
    }
    
    return $result;
  }
  
  /**
   * @param $uid
   *
   * @return bool
   */
  public function CanUserLogin($uid)
  {
    return $this->GetManipulator()->CanUserLogin($uid);
  }
  
  /**
   * @param $uid
   *
   * @return bool
   */
  public function IsAccountExpired($uid)
  {
    return $this->GetManipulator()->IsAccountExpired($uid);
  }
  
  /**
   * @param $uid
   *
   * @return array
   */
  public function GetUserPropertyRelations($uid)
  {
    return (array)$this->GetManipulator()->GetUserPropertyRelations($uid);
  }
  
  
  /**
   * @param $grpid
   *
   * @return array
   */
  public function GetGroupPropertyRelations($grpid)
  {
    return $this->GetManipulator()->GetGroupPropertyRelations($grpid);
  }
  
  /**
   * @param      $grpid
   * @param      $propname
   * @param      $sortkey
   * @param      $lostun
   * @param      $val
   * @param null $return
   *
   * @return \MAMS\api
   */
  public function AddGroupPropertyRelation($grpid, $propname, $sortkey, $lostun, $val, &$return = null)
  {
    $result = $this->GetManipulator()->AddGroupPropertyRelation($grpid, $propname, $sortkey, $lostun, $val);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException($result[1]);
    }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $grpid
   *
   * @return \MAMS\api
   */
  public function DeleteAllGroupPropertyRelations($grpid, &$return = null)
  {
    $result = $this->GetManipulator()->DeleteAllGroupPropertyRelations($grpid);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    { throw new \RuntimeException($result[1]); }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $grpid
   * @param $propname
   *
   * @return \MAMS\api
   */
  public function DeleteGroupPropertyRelation($grpid, $propname, &$return = null)
  {
    $result = $this->GetManipulator()->DeleteGroupPropertyRelation($grpid, $propname);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    { throw new \RuntimeException($result[1]); }
    
    $return = $result;
    
    return $this;
  }
  
  
  /**
   * Add a single property definition
   *
   * @param $name
   *                  The name of the property
   * @param $prompt
   *                  The prompt to display to the user
   *                  note, this will be Langified
   * @param $type
   *                  The type of the property
   *                  0 = text, 1 = checkbox, 2 = email
   * @param $length
   * @param $maxlength
   * @param $attribs
   * @param $force_unique
   * @param $encrypt
   *
   * @return \MAMS\api
   */
  public function AddPropertyDefn(
    $name, $prompt, $type, $length, $maxlength = 0, $attribs = '', $force_unique = 0, $encrypt = 0, &$result = null
  )
  {
    $result= $this->GetManipulator()->AddPropertyDefn($name, $prompt, $type, $length, $maxlength, $attribs, $force_unique, $encrypt);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode) { throw new \RuntimeException($result[1]); }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $name
   * @param $extra
   *
   * @return \MAMS\api
   */
  public function SetPropertyDefnExtra($name, $extra)
  {
    $this->GetManipulator()->SetPropertyDefnExtra($name, $extra);
    
    return $this;
  }
  
  /**
   * Add a single property definition
   *
   * @param $name
   * @param $options
   *
   * @return \MAMS\api
   */
  public function AddSelectOptions($name, $options, &$result = null)
  {
    $result = $this->GetManipulator()->AddSelectOptions($name, $options);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    { throw new \RuntimeException('Could not expire temp codes');}
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @return \MAMS\api
   */
  public function DeletePropertyDefns(&$result = null)
  {
    $result = $this->GetManipulator()->DeletePropertyDefns();
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    { throw new \RuntimeException($result[1]); }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $name
   *
   * @return \MAMS\api
   */
  public function DeleteSelectOptions($name, &$result = null)
  {
    $result = $this->GetManipulator()->DeleteSelectOptions($name);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    { throw new \RuntimeException($result[1]); }
    
    $return = $result;
    
    return $this;
  }
  
  /**
   * @param $prefix
   *
   * @return string
   */
  public function GenerateRandomUsername($prefix = 'user', &$result = null)
  {
    $result = $this->GetManipulator()->GenerateRandomUsername($prefix);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not generate random username');
    }
    
    $return = $result;
    
    return $result;
  }
  
  /**
   * @return \MAMS\api
   */
  public function ClearPropertyCache()
  {
    $this->GetManipulator()->ClearPropertyCache();
    
    return $this;
  }
  
  /**
   * @param $name
   *
   * @return array
   */
  public function GetPropertyDefn($name, &$result = null)
  {
    $result = $this->GetManipulator()->GetPropertyDefn($name);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not get property definition');
    }
    
    $return = $result;
    
    return $result;
  }
  
  public function GetPropertyDefns(&$result = null)
  {
    $result = $this->GetManipulator()->GetPropertyDefns();
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not get property definitions');
    }
    
    $return = $result;
    
    return $result;
  }
  
  /**
   * Returns select options as one simple or 2 dimensional array
   *
   * @param String $controlname - name of the dropdown as in the propdefn table
   * @param int    $dim         - dimension of the array
   *                            if $dim == 1, returns a 1 dimensional array text=>name
   *                            if $dim == 2, returns a 2 dimensional array, each item being an
   *                            array with properties 'option_name', 'option_text', 'control_name'.
   *
   * @return array|bool
   */
  public function GetSelectOptions($controlname, $dim = 1, &$result = null)
  {
    $result = $this->GetManipulator()->GetSelectOptions($controlname, $dim);
    
    if(!$result && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    {
      throw new \RuntimeException('Could not get select options');
    }
    
    $return = $result;
    
    return $result;
  }
  
  /**
   * Log the user into the site.
   * This checks the user password, and preferences about duplicate logins and other things then marks the user
   * as logged in with the appropriate database change.  It does not send events.
   *
   * @param string $username
   * @param string $password     The plaintext password
   * @param string $groups       A comma separated list of group names that the user must be a member of.
   * @param string $ignored
   * @param bool   $force_logout Optionally force the user to logout before logging him in again.
   *
   * @return int
   */
  public function Login($username, $password, $groups = '', $ignored = FALSE, $force_logout = FALSE, &$result = null)
  {
    $result = $this->GetManipulator()->Login($username, $password, $groups, $ignored, $force_logout);
    
    if(!$result[0] && self::ERROR_MODE_EXCEPTION === self::$_error_mode)
    { throw new \RuntimeException($result[1]); }
    
    $return = $result;
    
    return $result[0];
  }
  
  /**
   * userid api method
   *
   * @param $uid
   * @param $gid
   *
   * @return \MAMS\api
   */
  public function AssignUserToGroup($uid, $gid)
  {
    $result = $this->GetManipulator()->AssignUserToGroup($uid, $gid);
    
    if(!$result)  { throw new \RuntimeException('Could not assign user to group'); }
    
    return $this;
  }
  
  /**
   * userid api method
   *
   * @param $password
   *
   * @return bool
   */
  public function IsValidPassword($password)
  {
    return $this->GetManipulator()->IsValidPassword($password);
  }
  
  /**
   * userid api method
   *
   * @param $id
   *
   * @return \MAMS\api
   */
  public function DeleteUserFull($id)
  {
    $result = $this->GetManipulator()->DeleteUserFull($id);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $this;
  }
  
  /**
   * userid api method
   * @param $gid
   * @return array
   */
  public function GetGroupInfo($gid)
  {
    $result = $this->GetManipulator()->GetGroupInfo($gid);
    
    if(!$result) { throw new \RuntimeException('Could not get group info'); }
    
    return $result;
  }
  
  /**
   * // userid api method
   *
   * @param      $uid
   * @param bool $deep
   *
   * @return array
   */
  public function GetUserInfo($uid, $deep = FALSE)
  {
    $result = $this->GetManipulator()->GetUserInfo($uid, $deep);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $result[0];
  }
  
  /**
   * // userid api method
   * @param $username
   *
   * @return array
   */
  
  public function GetUserInfoByName($username)
  {
    $result = $this->GetManipulator()->GetUserInfoByName($username);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $result[0];
  }
  
  /**
   * @param        $uid
   * @param string $action
   * @param int    $count
   *
   * @return array
   */
  public function GetUserHistory($uid, $action = '', $count = -1)
  {
    return $this->GetManipulator()->GetUserHistory($uid, $action, $count);
  }
  
  /**
   * @param string $not_active_since
   *
   * @return array
   */
  public function GetLoggedInUsers($not_active_since = '')
  {
    return $this->GetManipulator()->GetLoggedInUsers($not_active_since);
  }
  
  /**
   * userid api method
   * returns an array or false
   *
   * @param $groupid
   *
   * @return bool|array
   */
  public function CountUsersInGroup($groupid)
  {
    $result = $this->GetManipulator()->CountUsersInGroup($groupid);
    
    if(!$result) { throw new \RuntimeException('Could not count users in group'); }
    
    return $result;
  }
  
  /**
   * @param $gid
   *
   * @return array
   * @throws \RuntimeException|\CmsException
   */
  public function GetFullUsersInGroup($gid)
  {
    $result = $this->GetManipulator()->GetFullUsersInGroup($gid);
    
    if(!$result) { throw new \RuntimeException('Could not get users in group'); }
    
    return $result;
  }
  
  
  /**
   * userid api method
   * @param $gid
   *
   * @return bool
   */
  public function GroupExistsByID($gid)
  {
    return $this->GetManipulator()->GroupExistsByID($gid);
  }
  
  /**
   * userid api method
   *
   * @param $name
   *
   * @return bool
   */
  public function GroupExistsByName($name)
  {
    return $this->GetManipulator()->GroupExistsByName($name);
  }
  
  /**
   * @return string
   */
  function LoggedInEmail()
  {
    $result = $this->GetManipulator()->LoggedInEmail();
    
    if(!$result) { throw new \RuntimeException('Could not get logged in email'); }
    
    return $result;
  }
  
  /**
   * @param $uid
   *
   * @return bool|string
   */
  public function GetEmail($uid)
  {
    $result = $this->GetManipulator()->GetEmail($uid);
    
    if(!$result) { throw new \RuntimeException('Could not get email from ' . $uid); }
    
    return $result;
  }
  
  
  /**
   * @return string
   */
  public function GetUsernamePrompt()
  {
    $consumer = utils::get_auth_consumer();
    
    if(!\is_object($consumer) )
    {
      throw new \RuntimeException('Could not get an authentication consumer object');
    }
    
    return $consumer->get_username_prompt();
  }
  
  
  /**
   * @param      $username
   * @param bool $check_email
   * @param int  $uid
   *
   * @return bool
   */
  public function IsValidUsername($username, $check_email = TRUE, $uid = -1)
  {
    $consumer = utils::get_auth_consumer();
    
    if(!\is_object($consumer) )
    {
      throw new \RuntimeException('Could not get an authentication consumer object');
    }
    
    return $consumer->validate_username($username, $check_email, $uid);
  }
  
  /**
   * userid api method
   *
   * @param $uid
   * @param $gid
   *
   * @return \MAMS\api
   */
  public function RemoveUserFromGroup($uid, $gid)
  {
    $result = $this->GetManipulator()->RemoveUserFromGroup($uid, $gid);
    
    if(!$result[0]) { throw new \RuntimeException ($result[1]); }
    
    return $this;
  }
  
  /**
   * userid api method
   *
   * @param      $id
   * @param      $name
   * @param null $desc
   *
   * @return \MAMS\api
   */
  public function SetGroup($id, $name, $desc = NULL)
  {
    $result = $this->GetManipulator()->SetGroup($id, $name, $desc);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $this;
  }
  
  /**
   * @param $uid
   * @param $plain_password
   *
   * @return string
   */
  public function EncryptPassword($uid, $plain_password)
  {
    try
    {
      $result = $this->GetManipulator()->EncryptPassword($uid, $plain_password);
      
      if(!$result) { throw new \RuntimeException('Could not encrypt password'); }
    }
    catch(\Exception $e)
    {
      throw new \RuntimeException($e->getMessage());
    }
    
    return $result;
  }
  
  /**
   * @param $uid
   * @param $password
   *
   * @return \MAMS\api
   */
  public function SetUserPassword($uid, $password)
  {
    $result = $this->GetManipulator()->SetUserPassword($uid, $password);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $this;
  }
  
  /**
   * @param      $uid
   * @param bool $flag
   *
   * @return \MAMS\api
   */
  public function SetUserDisabled($uid, $flag = TRUE)
  {
    try
    {
      $this->GetManipulator()->SetUserDisabled($uid, $flag);
    }
    catch(\Exception $e)
    {
      throw new \RuntimeException($e->getMessage());
    }
    
    return $this;
  }
  
  /**
   * @param      $uid
   * @param bool $flag
   *
   * @return \MAMS\api
   */
  public function ForcePasswordChange($uid, $flag = TRUE)
  {
    try
    {
      $this->GetManipulator()->ForcePasswordChange($uid, $flag);
    }
    catch(\Exception $e)
    {
      throw new \RuntimeException($e->getMessage());
    }
    
    return $this;
  }
  
  /**
   * @param      $uid
   * @param bool $flag
   *
   * @return \MAMS\api
   */
  public function ForceChangeSettings($uid, $flag = TRUE)
  {
    try
    {
      $this->GetManipulator()->ForceChangeSettings($uid, $flag);
    }
    catch(\Exception $e)
    {
      throw new \RuntimeException($e->getMessage());
    }
    
    return $this;
  }
  
  /**
   * @param      $uid
   * @param bool $flag
   *
   * @return \MAMS\api
   */
  public function ForceVerify($uid, $flag = TRUE)
  {
    try
    {
      $this->GetManipulator()->ForceVerify($uid, $flag);
    }
    catch(\Exception $e)
    {
      throw new \RuntimeException($e->getMessage());
    }
    
    return $this;
  }
  
  
  /**
   * userid api method
   *
   * @param      $uid
   * @param      $username
   * @param      $password
   * @param bool $expires
   *
   * @return \MAMS\api
   */
  public function SetUser($uid, $username, $password, $expires = FALSE)
  {
    
    $result = $this->GetManipulator()->SetUser($uid, $username, $password, $expires);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $this;
  }
  
  /**
   * Set the user group memberships
   * does not alter any user properties.
   * does not validate group ids, but does validate uid
   *
   * @param int userid
   * @param array array of integer group ids
   *
   * @return \MAMS\api (status,msg)
   */
  public function SetUserGroups($uid, $grpids)
  {
    $result = $this->GetManipulator()->SetUserGroups($uid, $grpids);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $this;
  }
  
  /**
   * @param $uid
   * @param $gid
   *
   * @return \MAMS\api
   */
  public function AddUserToGroup($uid, $gid)
  {
    return $this->AssignUserToGroup($uid, $gid);
  }
  
  /**
   * userid api method
   *
   * @param $uid
   * @param $props
   *
   * @return \MAMS\api
   */
  public function SetUserProperties($uid, $props)
  {
    $result = $this->GetManipulator()->SetUserProperties($uid, $props);
    
    # todo: revisit if needed - not sure if json_encode is the best option here (JM)
    if(!$result) { throw new \RuntimeException('Could not set user '. $uid .' properties ' . \json_encode($props)); }
    
    return $this;
  }
  
  /**
   * userid api method
   * @param $uid
   *
   * @return bool
   */
  public function UserExistsByID($uid)
  {
    return $this->GetManipulator()->UserExistsByID($uid);
  }
  

  /**
   * userid api method
   *
   * @param $uid
   *
   * @return array
   */
  public function GetUserProperties($uid)
  {
    $result = $this->GetManipulator()->GetUserProperties($uid);
    
    if(!$result) { throw new \RuntimeException(' Could not get user '. $uid .' properties'); }
    
    return $this->GetManipulator()->GetUserProperties($uid);
  }
  
  
  /**
   * userid api method
   * returns an array of records or false
   *
   * @param $userid
   *
   * @return array
   */
  public function GetMemberGroupsArray($userid)
  {
    $result = $this->GetManipulator()->GetMemberGroupsArray($userid);
    
    if(!$result) { throw new \RuntimeException(' Could not get user '. $userid .' groups'); }
    
    return $result;
  }
  
  //
  // end of rc functions
  //
  
  /**
   * userid api method
   *
   * @param      $title
   * @param bool $defaultvalue
   *
   * @return mixed
   */
  public function GetUserProperty($title, $defaultvalue = FALSE)
  {
    $result = $this->GetManipulator()->GetUserProperty($title, $defaultvalue);
    
    if(!$result) { throw new \RuntimeException(' Could not get property '. $title . ' for current user'); }
    
    return $result;
  }
  
  
  /**
   * userid api method
   *
   * @param      $title
   * @param      $userid
   * @param bool $defaultvalue
   *
   * @return bool|mixed
   */
  public function GetUserPropertyFull($title, $userid, $defaultvalue = FALSE)
  {
    $result = $this->GetManipulator()->GetUserPropertyFull($title, $userid, $defaultvalue);
    
    if(!$result) { throw new \RuntimeException(' Could not get property '. $title . ' for user '. $userid); }
    
    return $result;
  }
  
  /**
   * userid api method
   *
   * @param $uid
   * @param $title
   * @param $data
   *
   * @return bool
   */
  public function IsUserPropertyValueUnique($uid, $title, $data)
  {
    return $this->GetManipulator()->IsUserPropertyValueUnique($uid, $title, $data);
  }
  
  
  /**
   * userid api method
   *
   * @param $title
   * @param $data
   *
   * @return \MAMS\api
   */
  public function SetUserProperty($title, $data)
  {
    
    $result = $this->GetManipulator()->SetUserProperty($title, $data);
    
    if(!$result) { throw new \RuntimeException(' Could not set property '. $title . ' for current user'); }

    return $this;
  }
  
  
  /**
   * userid api method
   *
   * @param $title
   * @param $data
   * @param $userid
   *
   * @return \MAMS\api
   */
  public function SetUserPropertyFull($title, $data, $userid)
  {
    $result = $this->GetManipulator()->SetUserPropertyFull($title, $data, $userid);
    
    if(!$result) { throw new \RuntimeException(' Could not set property '. $title . ' for user '. $userid); }
    
    return $this;
  }
  
  
  /**
   * delete all occurrences of the userproperty by name
   *
   * @param $title
   *
   * @return \MAMS\api
   */
  public function DeleteUserPropertyByName($title)
  {
    $result = $this->GetManipulator()->DeleteUserPropertyByName($title);
    
    if(!$result) { throw new \RuntimeException(' Could not delete property '. $title . ' for current user'); }
    
    return $this;
  }
  
  
  /**
   * userid api method
   *
   * @param      $title
   * @param bool $all
   *
   * @return \MAMS\api
   */
  public function DeleteUserProperty($title, $all = FALSE)
  {
    $result = $this->GetManipulator()->DeleteUserProperty($title, $all);
    
    if(!$result) { throw new \RuntimeException(' Could not delete property '. $title . ' for current user'); }
    
    return $this;
  }
  
  /**
   * userid api method
   *
   * @param      $title
   * @param      $userid
   * @param bool $all
   *
   * @return \MAMS\api
   */
  public function DeleteUserPropertyFull($title, $userid, $all = FALSE)
  {
    $result = $this->GetManipulator()->DeleteUserPropertyFull($title, $userid, $all);
    
    if(!$result) { throw new \RuntimeException('Could not delete property '. $title . ' for user '. $userid); }
    
    return $this;
  }
  
  /**
   * userid api method
   *
   * @return \MAMS\api
   */
  public function DeleteAllUserProperties()
  {
    $result = $this->GetManipulator()->DeleteAllUserProperties();
    
    if(!$result) { throw new \RuntimeException('Could not delete all user properties'); }
    
    return $this;
  }
  
  /**
   * userid api method
   *
   * @param $userid
   *
   * @return \MAMS\api
   */
  public function DeleteAllUserPropertiesFull($userid)
  {
    $result = $this->GetManipulator()->DeleteAllUserPropertiesFull($userid);
    
    if(!$result) { throw new \RuntimeException('Could not delete all user properties'); }
    
    return $this;
  }
  
  /**
   * TODO: revisit - the manipulator CheckPassword is way too convoluted and should be simplified (JM)
   *
   * @param        $username
   * @param        $password
   * @param string $groups
   *
   * @return int|mixed
   */
  public function CheckPassword($username, $password, $groups = '')
  {
    return $this->GetManipulator()->CheckPassword($username, $password, $groups);
  }
  
  /**
   * userid api method
   *
   * @return string
   */
  public function LoggedInName()
  {
    return (string)$this->GetManipulator()->LoggedInName();
  }
  
  /**
   * @param $uid
   * @param $message
   *
   * @return \MAMS\api
   */
  public function Logout($uid = '', $message = 'logout')
  {
    $this->GetManipulator()->Logout($uid, $message);
    
    return $this;
  }
  
  /**
   * this deletes the entry from the loggedin table, and adds a history entry.
   * it also sets some cache data used to force logout the user
   * designed to programmatically log out a user from the admin panel.
   * so that the next time a user does anything on this site, and as long as cache is not cleared
   * the next time he does a request on the website, his cookies and session data will be cleared
   * another option here would be to use a flag in the database that indicates the user should be logged out.
   *
   * @param $uid
   * @param $eventmsg
   *
   * @return \MAMS\api
   */
  public function LogoutUser($uid, $eventmsg = 'logout')
  {
    $this->GetManipulator()->LogoutUser($uid, $eventmsg);
    
    return $this;
  }
  
  // userid api method
  
  /**
   * @return \MAMS\api
   */
  public function ExpireUsers()
  {
    $this->GetManipulator()->ExpireUsers();
    
    return $this;
  }
  
  // userid api method
  
  /**
   * @return int|FALSE
   */
  public function LoggedInId()
  {
    $result = $this->GetManipulator()->LoggedInId();
    
    if(!$result) { throw new \RuntimeException('user not logged in'); }
    
    return $result;
  }
  
  // userid api method
  
  /**
   * Tests whether the current user is logged in or not
   *
   * @return bool
   */
  public function LoggedIn()
  {
    return $this->GetManipulator()->LoggedIn();
  }
  
  /**
   * Determine if the user id is a member of the group(s) specified.
   *
   * @param integer $userid  userid
   * @param mixed   $groupid integer (positive) group id, or an array of positive integer group ids.
   *
   * @return boolean
   */
  public function MemberOfGroup($userid, $groupid)
  {
    return $this->GetManipulator()->MemberOfGroup($userid, $groupid);
  }
  
  /**
   * userid api method
   *
   * @param $userid
   *
   * @return string
   */
  public function GetUserName($userid)
  {
    return $this->GetManipulator()->GetUserName($userid);
  }
  
  
  /**
   * userid api method
   *
   * even though previous methods return -1 if user doesn't exist
   * the system will never allow for the existence of a user 0,
   * so we return zero as a user not found result
   *
   * @param $username
   *
   * @return int
   */
  public function GetUserID($username)
  {
    $result = $this->GetManipulator()->GetUserID($username);
    
    return \max($result, 0);
  }
  
  /**
   * Adds a new group with the supplied name and description
   *
   * @param $name
   *              The new group name
   * @param $description
   *                      the group description
   *
   * @return \MAMS\api
   */
  public function AddGroup($name, $description)
  {
    $result = $this->GetManipulator()->AddGroup($name, $description);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $this;
  }
  
  /**
   * Add the specified user to the database
   *
   * @param $name
   *                  The desired username
   * @param $password
   *                  The desired password (unencrypted)
   * @param $expires
   *                  The expiry date
   * @param bool $nonstd
   * @param null $createdate
   * @param null $return if we have a valid return value (in this case it's a userid), a variable can be passed here
   *
   * @return \MAMS\api
   */
  public function AddUser($name, $password, $expires, $nonstd = FALSE, $createdate = NULL , &$return = NULL)
  {
    $result = $this->GetManipulator()->AddUser($name, $password, $expires, $nonstd, $createdate);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    $return = $result[0];
    
    return $this;
  }
  
  /**
   * userid api method
   *
   * @param $gid
   *
   * @return string
   */
  public function GetGroupName($gid)
  {
    return $this->GetManipulator()->GetGroupName($gid);
  }
  
  
  /**
   * userid api method
   *
   * @param $gid
   *
   * @return string
   */
  public function GetGroupDesc($gid)
  {
    return $this->GetManipulator()->GetGroupDesc($gid);
  }
  
  /**
   * userid api method
   *
   * @param $id
   *
   * @return \MAMS\api
   */
  public function DeleteGroupFull($id)
  {
    $result = $this->GetManipulator()->DeleteGroupFull($id);
    
    if(!$result[0]) { throw new \RuntimeException($result[1]); }
    
    return $this;
  }
  
  /**
   * userid api method
   *
   * @return array
   */
  public function GetGroupList()
  {
    return $this->GetManipulator()->GetGroupList();
  }
  
  // userid api method
  /**
   * userid api method
   *
   * @param bool $with_count
   *
   * @return array
   */
  public function GetGroupListFull($with_count = FALSE)
  {
    return $this->GetManipulator()->GetGroupListFull($with_count);
  }
  
  /**
   * old userid api method
   *
   * even though previous methods return -1 if the group doesn't exist
   * the system will never allow for the existence of a group 0,
   * so we return zero as a group not found result
   *
   * @param $groupname
   *
   * @return int
   */
  public function GetGroupID($groupname)
  {
    $result = $this->GetManipulator()->GetGroupID($groupname);
    
    return \max($result, 0);
  }
  
  /**
   * Return a list of groups that the user is a member of
   *
   * @param integer $userid The user identifier
   *
   * @return string A comma delimited string containing member group names.  or 'none'
   */
  function GetMemberGroups($userid)
  {
    return $this->GetManipulator()->GetMemberGroups($userid);
  }
  
  /**
   * old userid api method
   *
   * @param $id
   *
   * @return \MAMS\api
   */
  public function DeleteUser($id)
  {
    $this->GetManipulator()->DeleteUser($id);
    
    return $this;
  }
  
  /**
   * @param int $uid
   *
   * @return \MAMS\api
   */
  public function SetPermanentCookie(int $uid)
  {
    $this->GetManipulator()->SetPermanentCookie($uid);
    
    return $this;
  }
  
  /**
   * end of api methods from users manipulator
   */
}

?>