<?php
/**
 * CrugeStoredUser
 *
 *  Modelo que realiza la persistencia de components.CrugeUser
 *
 * @property integer $iduser
 * @property string $username
 * @property string $email
 * @property string $password
 * @property string $authkey
 * @property integer $state
 * @property integer $totalsessioncounter
 * @property integer $currentsessioncounter
 * @property string $regdate    fecha de registro
 * @property string $actdate    fecha de activacion
 * @property string $logondate    ultimo login exitoso
 * @author: Christian Salazar H. <christiansalazarh@gmail.com> @salazarchris74
 * @license protected/modules/cruge/LICENSE
 */
class CrugeStoredUser extends CActiveRecord implements ICrugeStoredUser
{
    public $_fields = array();
    public $deleteConfirmation; // required on 'delete'
    public $newPassword; // declararlo 'safe'

    // terminos y condiciones, caso registration,
    public $terminosYCondiciones;
    public $verifyCode;

    // establecer a true si se quiere saltar la validacion de captcha.
    // ver acerca de: cruge\components\CrugeUserManager.php::createBlankUser
    public $bypassCaptcha;

	public function getCustomFieldValue($fieldname, $defValue=""){
		$field = $this->getCustomField($fieldname);
		if($field != null)
			return $field->getFieldValue();
		return $defValue;
	}

	public function getCustomField($fieldname){
		foreach($this->getFields() as $obj)
			if($fieldname == $obj->fieldname)
				return $obj;
		return null;
	}

	public function getUserDescription($boolLoadUserFields=false, $sep=','){
		$fieldNames = CrugeUtil::config()->userDescriptionFieldsArray;
		$tmp = "";
		if(in_array("username",$fieldNames))
			$tmp .= $sep.$this->username;
		if(in_array("email",$fieldNames))
			$tmp .= $sep.$this->email;
		if($fieldNames != null){
			if($boolLoadUserFields == true)
				$this->setFields(
					CrugeFactory::get()->getICrugeFieldListModels($this));
			foreach($fieldNames as $fname)
			if(($fname != "username") && ($fname != "email")){
				$tmp .= $sep.$this->getCustomFieldValue($fname,$fname);
			}
		}
		if($tmp == "")
			$tmp = $this->getUsername();
		return ltrim($tmp,$sep." ");
	}

    /* es un loadModel de uso multiple. $modo puede ser: 'iduser','username' o 'email' para
        indicar por cual campo se quiere cargar el modelo.
        @returns ICrugeStoredUser
    */
    public static function loadModel($id, $modo = 'iduser')
    {
        return self::model()->findByAttributes(array($modo => $id));
    }

    /* entrega un array con los nombres de los atributos clave para orden, de primero el userid */
    public static function getSortFieldNames()
    {
        return array('iduser', 'username', 'email', 'state', 'logondate');
    }

    public function getStateName()
    {
        return Yii::app()->user->um->getStateName($this->state);
    }

    /*
        recibe un array de instancias de ICrugeField previamente cargada de valores
    */
    public function setFields($arFields)
    {
        $this->_fields = $arFields;
    }

    public function getFields()
    {
        if ($this->_fields == null) {
            return array();
        }
        return $this->_fields;
    }

    public function setAttributes($values, $safeOnly = true)
    {

        if (count($this->getFields()) > 0) {
            $test = __CLASS__ . ".setAttributes:\n";
            foreach ($values as $k => $v) {
                $test .= "[{$k}={$v}]\n";
            }
            $test .= "\nparse field values:\n";
            foreach ($values as $fieldName => $value) {
                $test .= "{$fieldName}...";

                $boolFound = false;
                foreach ($this->getFields() as $f) {
                    if ($f->fieldname == $fieldName) {
                        $test .= " found. setfieldvalue:[{$value}]\n";
                        $f->setFieldValue($value);
                        $boolFound = true;
                        break;
                    }
                }
                if ($boolFound == false) {
                    $test .= " [not found]\n";
                }
            }
            Yii::log($test, "info");
        }

        parent::setAttributes($values);
    }

    public function validate($attributes = null, $clearErrors = true)
    {
		// si el metodo de autenticacion es solo email, y, username es blanco
		// se genera uno automaticamente:
		if($this->scenario == 'insert'){
		$declared_authmodes = CrugeUtil::config()->availableAuthModes;
		if(count($declared_authmodes == 1)){
			if(($declared_authmodes[0] == 'email') && ($this->username=='')){
				$um = new CrugeUserManager();
				$this->username = $um->generateNewUserName($this->email);
			}else
			if(($declared_authmodes[0] == 'username') && ($this->email=='')){
				$this->email = $this->username.'@noemail.local';
			}
		}}

        // realiza la validacion normal sobre los atributos de este modelo
        $validateResult = parent::validate();

        // ahora realiza la validacion sobre aquellos campos personalizados
        // y copia todos los errores al objeto mayor ($this)
        //
        foreach ($this->getFields() as $f) {
            if ($f->validateField() == false) {
                $this->addErrors($f->getErrors());
                $validateResult = false;
            }
        }

        return $validateResult;
    }

    public function save($runValidation = true, $attributes = null)
    {
        Yii::log(__METHOD__, "info");
        if ($this->hasErrors()) {
            Yii::log(__METHOD__ . " return false, has errors.", "info");
            return false;
        }

        // importante aqui:
        // primero debe guardar el usuario (this) y luego los campos
        // si se hiciera al reves y el escenario fuese 'insert' entonces al crear el CrugeFieldValue // se generaria un error porque el user->iduser no existiria aun.
        //
        $ok = parent::save();
        $this->saveFields();

        Yii::log(__METHOD__ . " returns: [" . $ok . "]", "info");
        return $ok;
    }

    public function saveFields()
    {
        foreach ($this->getFields() as $f) {
            // buscar el objeto ICrugeFieldValue, darle valores y guardarlo
            $crugeFieldValueInst = Yii::app()->user->um->loadICrugeFieldValue($this, $f);
            $boolOk = false;
            if ($crugeFieldValueInst != null) {
                $crugeFieldValueInst->value = $f->getFieldValue();
                $boolOk = $crugeFieldValueInst->save();
            }
            Yii::log(
                "\n" . __METHOD__ . " \nfieldname='" . $f->fieldname . "'\nfieldvalue='" . $f->getFieldValue()
                    . "'\n boolOk=[" . $boolOk . "]\ncrugeFieldValueInst=[" . ($crugeFieldValueInst == null ? 'null' : 'not null') . "]\n\n",
                "info"
            );
        }
    }

    /**
    @retuns string nombre de usuario (para login).
     */
    public function getUserName()
    {
        return $this->username;
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function tableName()
    {
        return CrugeUtil::getTableName('user');
    }

    public function getPrimaryKey()
    {
        return $this->iduser;
    }

    public static function listModels($param = array())
    {
        return self::model()->findAllByAttributes($param);
    }

    public function getUpdateUrl()
    {
        return 'index.php?r=test' . $this->getPrimaryKey();
    }


    /**
     * Returns the static model of the specified AR class.
     * @return CrugeStoredUser the static model class
     */
    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }


    /**  hay un escenario llamado 'internal', que es puesto por CrugeUserManager::save()
     *   para poder guardar atributos especificos sin ser afectado por las reglas para formularios
     *
     *
     *
     * @return array validation rules for model attributes.
     */
    public function rules()
    {
        return array(
            array(
                'username',
                'match',
                'pattern' => '/^[a-zA-Z0-9\_\-\.]{3,45}$/'
            ,
                'message' => CrugeTranslator::t('logon', 'Invalid username')
            ),
            array('username,email', 'required'),
            array('newPassword', 'safe', 'on' => 'update'),
            array('newPassword', 'required', 'on' => 'insert, manualcreate'),
            array('newPassword', 'length', 'min' => 6, 'max' => 20),
            array(
                'newPassword',
                'match'
            ,
                'pattern' => '/^[a-zA-Z0-9@#$%\_\-\.]{6,20}$/'
            ,
                'message' => CrugeTranslator::t(
                    'logon',
                    'Password may contain numbers or symbols ({symbols}) and between {min} and {max} characters',
                    array('{symbols}' => '@#$%', '{min}' => 6, '{max}' => 20)
                )
            ),
            array('username, password', 'length', 'max' => 64),
            array('state', 'numerical', 'integerOnly' => true),
            array('authkey', 'length', 'max' => 100),
            array('email', 'email'),
            array('email', 'length', 'max' => 100),
            array('username,email', 'validate_unique'),
            array('deleteConfirmation', 'required', 'on' => 'delete'),
            array(
                'deleteConfirmation',
                'compare',
                'compareValue' => '1'
            ,
                'on' => 'delete',
                'message' => CrugeTranslator::t('logon', 'Please, confirm checking the checkbox')
            ),
            array(
                'terminosYCondiciones',
                'required'
            ,
                'requiredValue' => '1'
            ,
                'on' => 'insert'
            ,
                'message' => CrugeTranslator::t('logon', 'Please, check if you understand and accept the terms of use'),
            ),
            array(
                'verifyCode',
                $this->_getCaptchaRule(),
                'on' => 'insert',
                'message' => CrugeTranslator::t('logon', 'Security code is mandatory'),
            ),
            array(
                'verifyCode',
                'captcha',
                'on' => 'insert',
                'allowEmpty' => true,
                'message' => CrugeTranslator::t('logon', 'Security code is invalid'),
            ),
            array('iduser, username, email, state, logondate', 'safe', 'on' => 'search'),

        );
    }

    /**
    al establecer $_crugeStoredUser->bypassCaptcha = true;
    entonces el captcha no sera tomado en cuenta.

    esta funcion es util cuando se quiere crear un nuevo usuario de cruge por la via del API.
     */
    private function _getCaptchaRule()
    {
        if (Yii::app()->user->um->getDefaultSystem()->getn('registerusingcaptcha') == 1) {
            // el administrador decidio pedir captcha para registrar los usuarios,
            // 	pero quiza el flag bypassCaptcha este activo.
            if ($this->bypassCaptcha == true) {
                // captcha es requerido, pero sera no sera tomado en cuenta.
                $this->verifyCode = null;
                return 'safe';
            } else {
                return 'required';
            } // captcha es requerido
        } else {
            // el administrador ha deshabilitado el uso de captcha.
            $this->verifyCode = null;
            return 'safe';
        }
    }


    public function validate_unique($att, $params)
    {
        $model = self::model()->findByAttributes(array($att => $this[$att]));
        if ($model != null) {
            $duptext = CrugeTranslator::t('logon', '\'{attribute}\' already in use', array('attribute' => $att));
            if ($this->scenario == 'insert') {
                $this->addError($att, $duptext);
                return;
            }
            if ($this->scenario == 'update') {
                if ($this->iduser != $model->iduser) {
                    $this->addError($att, $duptext);
                }
                return;
            }
        }
    }

    /**
     * @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(
            'sessions' => array(self::HAS_MANY, 'crugesession', 'iduser'),
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels()
    {
        return array(
            'idusuario' => ucfirst(CrugeTranslator::t('usuario#')),
            'username' => ucfirst(CrugeTranslator::t('username')),
            'email' => ucfirst(CrugeTranslator::t('correo')),
            'password' => ucfirst(CrugeTranslator::t('clave')),
            'authkey' => ucfirst(CrugeTranslator::t('llave de autenticacion')),
            'state' => ucfirst(CrugeTranslator::t('estado de la cuenta')),
            'newPassword' => ucfirst(CrugeTranslator::t('clave')),
            'deleteConfirmation' => ucfirst(CrugeTranslator::t('confirmar eliminacion')),
            'regdate' => ucfirst(CrugeTranslator::t('registrado')),
            'actdate' => ucfirst(CrugeTranslator::t('activado')),
            'logondate' => ucfirst(CrugeTranslator::t('ultimo acceso')),
            'terminosYCondiciones' => ucfirst(CrugeTranslator::t('comprendo y acepto, por favor registrarme')),
        );
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
     */
    public function search()
    {
        // Warning: Please modify the following code to remove attributes that
        // should not be searched.

        $criteria = new CDbCriteria;

        $criteria->compare('iduser', $this->iduser);
        $criteria->compare('username', $this->username, true);
        $criteria->compare('email', $this->email, true);
        $criteria->compare('state', $this->state);
        $criteria->compare('logondate', $this->logondate);

        return new CActiveDataProvider($this, array(
            'criteria' => $criteria,
            'sort' => array(
                'defaultOrder' => array('iduser' => true),
            ),
        ));
    }


	public function searchByAuthItem($authItemName, $pageSize=20, $defaultOrder=null){
        $criteria = new CDbCriteria;
		$criteria->distinct = true;
		$authMan = new CrugeAuthManager();
		$table_assign = $authMan->getTableName("authassignment");
		$criteria->join = "left join ".$table_assign." ASG "
			."on ASG.userid = t.iduser";
		$criteria->compare("ASG.itemname",$authItemName);
		// extra optionals, for filtering:
        $criteria->compare('username', $this->username, true);
        $criteria->compare('email', $this->email, true);
        return new CActiveDataProvider($this, array(
            'criteria' => $criteria,
			'pagination' => array(
				'pageSize' => $pageSize,
			),
            'sort' => array(
                'defaultOrder' => (($defaultOrder==null) ? 
					array('username' => false) : $defaultOrder),
            ),
        ));
	}

}