<?php
/**
 * IMPORTANT NOTE
 * The code of this system is closed and a private proprietary of Flex Solutions.
 * A written authorization/license from Flex Solutions is required before using or modifying this code.
 * Email: sales@flexsolution.biz, Phone: +962795342585, Website: http://www.flexsolutions.biz
 */
 
/**
 * This is the model class for table "user".
 *
 * The followings are the available columns in table 'user':
 * @property integer $id
 * @property string $type
 * @property string $username
 * @property string $email
 * @property string $password
 * @property string $status
 * @property string $role
 * @property integer $location_id
 * @property integer $geomarket_id
 * @property integer $created_by
 * @property string $created_date
 * @property integer $last_edited_by
 * @property string $last_edited_date
 *  *
 * @author Amaney
 * @package application.models
 */
class User extends TidansActiveRecord {

    /**
     * @var String Password confirm value
     */
    public $password_repeat;
    /**
     * @var String The old password
     */
    public $old_password;
    /**
     * @var String The value of strength of password ('tooShort','Weak','Strong','Good')
     */
    public $password_strength;
    public $location_drop_down;

    const SYSTEM_ADMIN_ROLE = "System Admin";
    const LOGISTICS_ADMIN_ROLE = "Logistics Admin";

    /**
     * Returns the static model of the specified AR class.
     * Please note that you should have this exact method in all your CActiveRecord descendants!
     * @param string $className active record class name.
     * @return User the static model class
     */
    public static function model($className=__CLASS__) {
	return parent::model($className);
    }

    /**
     * The associated database table name
     * @return string the associated database table name
     */
    public function tableName() {
	return 'user';
    }

    /**
     * Validation rules for model attributes.
     * @return array validation rules for model attributes.
     */
    public function rules() {
	// NOTE: you should only define rules for those attributes that
	// will receive user inputs.
	return array(
	    array('type, username, status, role', 'required'),
	    array('type, status', 'length', 'max' => 8),
	    array('username, password', 'length', 'max' => 64),
	    array('email', 'length', 'max' => 255),
	    array('role', 'length', 'max' => 24),
	    array('email', 'email'),
	    array('password', 'compare'),
	    array('password_repeat,role,password_strength,location_drop_down', 'safe'),
	    array('password', 'passwordStrengthValidate'),
	    array('username', 'unique'),
	    array('username', 'checkForNonAllowedCharacter'),
	    array('email', 'unique'),
	    //Checking if username is found on LDAP system and return email if yes
	    array('username', 'usernameValidate', 'on' => 'ldap'),
	    //The Following two lines Check if user have password and email or just username
	    array('password', 'passwordNonLDAPValidate'),
	    array('email', 'emailNonLDAPValidate'),
	    // The following rule is used by search().
	    // @todo Please remove those attributes that should not be searched.
	    array('id, type, username, email, password, status', 'safe', 'on' => 'search'),
	);
    }

    /**
     * The available model relations
     * @return array relational rules.
     */
    public function relations() {
	// NOTE: you may need to adjust the relation name and the related
	// class name for the relations automatically generated below.
	return array(
	);
    }

    /**
     * The customized attribute labels
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels() {
	return array(
	    'username' => yii::t('default', 'Username'),
	    'password' => yii::t('default', 'Password'),
	    'email' => yii::t('default', 'Email'),
	    'status' => yii::t('default', 'Status'),
	    'role' => yii::t('default', 'Role'),
	    'password_repeat' => yii::t('default', 'Confirm Password'),
	    'type' => yii::t('default', 'Type'),
	);
    }

    /**
     * The customized attribute labels Tooltips
     * @return array customized attribute labels Tooltips (name=>label tooltips)
     */
    public function attributeLabelsPopover() {
	return array(
	    'username' => yii::t('default', 'tooltip_username'),
	    'password' => yii::t('default', 'tooltip_password'),
	    'email' => yii::t('default', 'tooltip_email'),
	    'status' => yii::t('default', 'tooltip_status'),
	    'role' => yii::t('default', 'tooltip_role'),
	    'password_repeat' => yii::t('default', 'tooltip_password_repeat'),
	    'type' => yii::t('default', 'tooltip_type'),
	);
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     *
     * Typical usecase:
     * - Initialize the model fields with values from filter form.
     * - Execute this method to get CActiveDataProvider instance which will filter
     * models according to data in model fields.
     * - Pass data provider to CGridView, CListView or any similar widget.
     *
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search() {
	// @todo Please modify the following code to remove attributes that should not be searched.

	$criteria = $this->ModelCriteria();
	$pageSize = $this->yiiparam('pageSize');

	$sort = new CSort();
	$sort->attributes = array(
//	    'role' => array(
//		'asc' => 'concat(role)',
//		'desc' => 'concat(role) desc',
//	    ),
	    '*'
	);

	return new CActiveDataProvider($this, array(
	    'pagination' => array('pageSize' => $pageSize,),
	    'criteria' => $criteria,
	    'sort' => $sort
	));
    }

    /**
     * Get the query used to get the current report to be used in export to excel action
     * @return CDbCriteria the criteria used to get the current report
     */
    public function ModelCriteria() { // @todo Please modify the following code to remove attributes that should not be searched.
	$criteria = new CDbCriteria;

	//$criteria->compare('id',$this->id);
	$criteria->compare('username', $this->username, true);
	$criteria->compare('type', $this->type, false);
	$criteria->compare('email', $this->email, true);
	$criteria->compare('password', $this->password, true);
	$criteria->compare('t.status', $this->status);
	$criteria->compare('role', $this->role, true);


	return $criteria;
    }

    /**
     * Get all user models
     * @param String $status the status of the user (Active or Inactive)
     * @return User[] array of User models
     */
    public static function getAll($status=null) {
	if ($status == "Active") {
	    return User::model()->active()->findAll(array('order' => 'username'));
	} else {
	    return User::model()->findAll(array('order' => 'username'));
	}
    }

    /**
     * The Following function is responsible for getting roles
     * @return String[] array of users
     */
    public static function getAllForView() {
	return array(
	    User::SYSTEM_ADMIN_ROLE => User::SYSTEM_ADMIN_ROLE,
	    User::LOGISTICS_ADMIN_ROLE => User::LOGISTICS_ADMIN_ROLE,
	);
    }

    /**
     * Perform one-way encryption on the password before we store it in the database
     */
    protected function afterValidate() {
	parent::afterValidate();

	if (!$this->hasErrors()) {
	    if (isset($this->password) && ($this->password != "")) {
		if (isset($this->old_password) && ($this->old_password != "")) {
		    //check if the password has been changed
		    if ($this->password != $this->old_password) {
			// encryption the new password
			$this->password = $this->encrypt($this->password); // note that we add a salt to the password "the user email"
		    }
		} else {
		    //If it is new User there is not old password
		    $this->password = $this->encrypt($this->password); // note that we add a salt to the password "the user email"
		}
	    }
	}
    }

    /**
     * The encryption function
     * @param String $value The value to encrypt
     * @return String The encrypted value
     */
    public static function encrypt($value) {
	return md5(sha1($value));
    }

    /**
     * Set user role after adding or updating the user
     */
    protected function afterFind() {
	parent::afterFind();
	$this->role = User::getAssignedRolesNames($this->id);
	return true;
    }

    /**
     * Get the current assigned roles to a user
     * @param Integer $id The id of the user
     * @return String The assigned roles for the user or "Non Role" if the user has no roles
     */
    public function getAssignedRolesNames($id) {
	$assigned_roles = Yii::app()->authManager->getRoles($id);
	if (isset($assigned_roles) && (count($assigned_roles) > 0)) {
	    foreach ($assigned_roles as $role) {
		return $role->name;
	    }
	} else {
	    return yii::t('default', 'Non Role');
	}
    }

    /**
     * The followitng function will return all defined roles
     * @return String[] array of names of roles
     */
    public static function getUserRoleOptions() {

	return CHtml::listData(Yii::app()->authManager->getRoles(), 'name', 'name');
    }

    /**
     *  Checking if username is found on LDAP system and return email if yes
     */
    public function usernameValidate($attribute, $params) {
	if (isset($this->username) && ($this->username != "")) {
	    // Get user email from LDAP based on the username (i.e. based on the user alias)
	    $error_message = LDAP::getUserEmailByAlias($this->username, $email);
	    if ($error_message != "") {
		$this->addError($attribute, $error_message);
	    } else {
		$this->email = $email;
	    }
	}
    }

    /**
     *  Check if user has a password and an email or just a username
     */
    public function emailNonLDAPValidate($attribute, $params) {
	if (!isset($this->username) || ($this->username == "")) {
	    if ((!isset($this->email)) || ($this->email == "")) {
		$this->addError($attribute, Yii::t('default', "The Email can not be blank, either the username or the email and password shoud be entered."));
	    }
	}
    }

    /**
     *  Check if user has a password and an email or just a username
     */
    public function passwordNonLDAPValidate($attribute, $params) {

	if (isset($this->type) && ($this->type != "") && ($this->type == "Non LDAP")) {
	    if ((!isset($this->password)) || ($this->password == "")) {
		$this->addError($attribute, Yii::t('default', "The Password can not be blank"));
	    }
	}
    }

    /**
     *  validate the password strength
     */
    public function passwordStrengthValidate($attribute, $params) {
	if (!isset($this->username) || ($this->username == "")) {
	    if ($this->password_strength == "too short" || $this->password_strength == "weak") {
		$this->addError("password", Yii::t('default', "The password should not be weak."));
	    }
	}
    }

    /**
     * Check if username contain # character, and return false if yes
     * This character indicate that the request is from mobile device, and the username and password is get by scanning user credinional barcode
     */
    public function checkForNonAllowedCharacter($attribute, $params) {
	if (isset($this->username) || ($this->username != "")) {
	    if (strpos($this->username, '#') !== false) {
		$this->addError("username", Yii::t('default', "Username should not contain # character"));
	    }
	}
    }

    /**
     *  Assign role to this user and revoke All other
     *
     */
    public function setRole($selected_role) {
	try {
	    $authManager = Yii::app()->authManager;
	    foreach ($authManager->getRoles() as $role) {
		$authManager->revoke($role->name, $this->id);
	    }

	    $authManager->assign($selected_role, $this->id);
	} catch (Exception $e) {
	    Yii::app()->user->setFlash('error', Yii::t('default', 'The Role has not been updated successfully'));
	}
    }

    /**
     * The following function is resposible for checking if user can change his password or not
     * @return boolean true if user can change his password, false otherwise
     */
    public static function canChangePassword($id) {
	$user = User::model()->findByAttributes(array('id' => $id));
	if (isset($user->password) && ($user->password != "")) {
	    return true;
	} else {
	    return false;
	}
    }

    /**
     * Get the type of the user    
     * @return String Type of user
     */
    public function getType() {
	return $this->type;
    }

    /**
     * The following function will return all user types
     * @return String[] array of user types
     */
    public static function getTypeOption() {
	return array(
	    "LDAP" => Yii::t('default', 'LDAP'),
	    "Non LDAP" => Yii::t('default', 'Non LDAP')
	);
    }

    /**
     * Get the username of a specific user
     * @param Integer $id The id of the user
     * @return String the user name of the specified user
     */
    public static function getUsernameById($id) {
	$user = User::model()->findByPk($id);
	return ($user != null) ? $user->username : '';
    }

}
