<?php

namespace common\models;

use Yii;
use common\components\Helper;

/** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */

/**
 * This is the model class for table "card".
 *
 * @property integer $id_card
 * @property string $number
 * @property integer $status
 * @property integer $type
 * @property integer $flag
 * @property string $created_at
 * @property string $updated_at
 * @property int flag_out
 * @property  \common\models\Customer  $customer  relation
 * @property mixed validity
 * @property string inactivated_at
 */
class Card extends \common\models\BaseFitnessActiveRecord
{

	const STATUS_DELETED = 0;
	const STATUS_ACTIVE = 10;
	const STATUS_INACTIVE = 20;

	const TYPE_RFID = 10;
	const TYPE_QRCODE = 20;
	const TYPE_BARCODE = 30;
	const TYPE_OLD = 40;
	const TYPE_EMPLOYEE = 50;


	public static $FLAG_TICKET = 0; //has valid ticket
	public static $FLAG_DOOR = 1;   //door in/out order
	public static $FLAG_KEY = 2;    //key status
	public static $FLAG_STATUS = 3; //allowed/disabled
	public static $FLAG_DOOR_ALLOWED = 4;  //ticket type allows door

    /**
     * This script is used in daily scripts, to clear the flag door log status
     *
     * @var string
     */
	public static $SQL_CLEARS_STATUS_DOOR = " 
      UPDATE card set flag = ( flag & ~(1 << 1 )  ), flag_out= ( flag_out & ~(1 << 1 )  ) where card.type <> 50 
 ";

        public static $SQL_FIX_KEY_STATUS = " 
                        update card as c1  
                          left join   card_key_assignment k 
                          on k.id_card = c1.id_card
                        set flag = CASE WHEN k.id_key   is null then    (c1.flag | 1 << 2)  else  ( c1.flag & ~(1 << 2 ) )    end,
                            flag_out = CASE WHEN k.id_key   is null then ( c1.flag_out & ~(1 << 2 ))  else   (c1.flag_out | 1 << 2 ) end
                        WHERE c1.type <> 50
      ";

    public static $SQL_CLEAR_KEY_STATUS = " 
      UPDATE card set flag = ( flag & ~(1 << 2 )  )  , flag_out = ( flag_out & ~(1 << 2 )  )   WHERE card.type <> 50 
 ";

    public static $SQL_CLEARS_STATUS_DOOR_IN = " 
      UPDATE card set flag = ( flag & ~(1 << 1 )  )    WHERE card.type <> 50 and card.id_card = :id
 ";

    public static function SQL_CLEAR_STATUS_DOOR_ALLOWED_FLAG(){
        return "UPDATE card set flag = ( flag & ~(1 << " . Card::$FLAG_DOOR_ALLOWED. " )  )    WHERE card.type <> 50 ";
    }

    public static function SQL_CLEAR_STATUS_DOOR_ALLOWED_FLAG_FOR_CARD(){
        return  Card::SQL_CLEAR_STATUS_DOOR_ALLOWED_FLAG() . " and card.id_card = :id ";
    }


    public static $SQL_UPDATE_FLAG_STATUS_ACTIVE = '
 update card set flag = CASE WHEN status = 20   then    (flag | 1 << 3)  else  ( flag & ~(1 << 3 ) )    end    
';


    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'card';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['number', 'type','status'], 'required'],
            [['status', 'type'], 'integer'],
            [['number'], 'string', 'max' => 20],
            [['rfid_key'], 'string', 'max' => 25],
            [['number'], 'unique' ],
        	[['rfid_key','number'] , 'validateAscii']
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        /** @noinspection PhpUndefinedClassInspection */
        return [
            'id_card' => Yii::t('common/card', 'Id Card'),
            'number' => Yii::t('common/card', 'Number'),
            'rfid_key' => Yii::t('common/card', 'RFID key'),
            'status' => Yii::t('common/card', 'Status'),
            'type' => Yii::t('common/card', 'Type'),
            'created_at' => Yii::t('common/card', 'Created At'),
            'updated_at' => Yii::t('common/card', 'Updated At'),
        ];
    }


    public function validateAscii($attribute, /** @noinspection PhpUnusedParameterInspection */
                                  $params){
    	if ( !$this->hasErrors($this->$attribute)){
    		$this->$attribute = Helper::fixAsciiChars($this->$attribute);
            /** @noinspection PhpUndefinedClassInspection */
            Yii::info(" $attribute converted to: " . $this->$attribute);
    	}
    }

    static function statuses() {
        /** @noinspection PhpUndefinedClassInspection */
        return [
    			self::STATUS_ACTIVE => 'Aktív',
    			self::STATUS_DELETED => 'Törölve',
    			self::STATUS_INACTIVE => 'Inaktív',
    	];
    }

    public function getStatusHuman(){
    	$result = null;
    	$s = self::statuses();
    	if ( array_key_exists($this->status, $s)){
    		$result = $s[$this->status];
    	}
    	return $result;
    }
    public static function toStatusName($status , $def = ""){
    	return Helper::getArrayValue(self::statuses(), $status, $def);
    }
    public static function toTypeName($type , $def = ""){
    	return Helper::getArrayValue(self::types(), $type, $def);
    }

    static function types() {
        /** @noinspection PhpUndefinedClassInspection */
        return [
    			self::TYPE_RFID => Yii::t('common/card', 'RFID'),
    			self::TYPE_QRCODE => Yii::t('common/card', 'QRCODE'),
    			self::TYPE_BARCODE => Yii::t('common/card', 'BARCODE'),
    			self::TYPE_OLD => Yii::t('common/card', 'OLD'),
    			self::TYPE_EMPLOYEE => Yii::t('common/card', 'Munkatárs'),
    	];
    }

    public function getTypeHuman(){
    	$result = null;
    	$s = self::types();
    	if ( array_key_exists($this->type, $s)){
    		$result = $s[$this->type];
    	}
    	return $result;
    }

    public function isInactive(){
    	return $this->status == self::STATUS_DELETED;
    }

    /**
     * Load card from the DB , where the number equals with card number or RFID number
     * @param number|string $number           the card number or the RFID number
     * @param null|boolean $free        optional. if set, append free or not free condition.
     * @return \common\models\Card|null  the card or null, if not found with given conditions
     */
    public static function readCard($number,$free = null){
    	$card = null;
    	$query = Card::find()
    			->leftJoin(Customer::tableName(), 'card.id_card = customer.id_customer_card ' );

    	Card::addCardNumberCondition($query, $number);

    	if ( isset($free) ){
    		if ( $free == true){
    			$query->andWhere('customer.id_customer  is null');
    		}else{
    			$query->andWhere('customer.id_customer  is not null');
    		}
    	}

    	$cards = $query->all();

    	if ( count($cards) == 1){
    		$card = $cards[0];
    	}
    	return $card;
    }


    public function getCustomer(){
    	return $this->hasOne(Customer::className(), ['id_customer_card' => 'id_card']);
    }

    public function getCustomerName(){
    	$name = null;
    	if ( $this->customer != null){
    		$name = $this->customer->name;
    	}
    	return $name;
    }

    /** @noinspection PhpUndefinedClassInspection */

    /**
     * @param   \yii\db\Query    $query
     * @param number $number
     * @param string $field_number
     * @param string $field_rfid_key
     */
    public static function addCardNumberCondition($query, $number, $field_number = "card.number", $field_rfid_key = "card.rfid_key"){
    	$query->andWhere(['or',
    			['and',[ 'in',$field_number , [$number]],"trim(coalesce(card.number, '')) <>'' " ],
    			['and', ['in',$field_rfid_key ,[ $number ] ],"trim(coalesce(card.rfid_key, '')) <>'' "],
    	]);
    }

    public static function updateCardFlagTicket($id){
    	if ( !isset($id)){
    		return ;
    	}
        /** @noinspection PhpUndefinedClassInspection */
        $db = \Yii::$app->db;

    	$command = $db->createCommand(Ticket::$SQL_UPDATE_CARD,[':id' => $id]);
    	$command->execute();

        $command = $db->createCommand(Card::$SQL_CLEARS_STATUS_DOOR_IN,[':id' => $id]);
    	$command->execute();

        if ( Helper::isTicketTypeDoorAllowedCheckOn()) {
            $command = $db->createCommand(Ticket::SQL_UPDATE_DOOR_ALLOWED_FLAG_FOR_CARD(), [':id' => $id]);
            $command->execute();
        }else{
            $command = $db->createCommand(Card::SQL_CLEAR_STATUS_DOOR_ALLOWED_FLAG_FOR_CARD(), [':id' => $id]);
            $command->execute();
        }

    }

    public  function beforeSave($insert) {
    	if (parent::beforeSave($insert)){
	    	$this->flag = Helper::setBit( $this->flag , Card::$FLAG_STATUS, ( $this->status != Card::STATUS_ACTIVE ) );
	    	return true;
    	}
    	return false;
    }


    public function getFlagText(){
    	return Helper::getArrayValue(DoorLog::getCardFlagTexts(), $this->validity, "Ismeretlen");
    }

	public function setFlagsHasKey($hasKey){
        if (Helper::isKeyRequired()){
            $this->flag = $hasKey ? ( $this->flag & ~(1 << Card::$FLAG_KEY)  )  :  ( $this->flag | 1 << Card::$FLAG_KEY );
            $this->flag_out = $hasKey ?   ( $this->flag_out | 1 << Card::$FLAG_KEY ) : ( $this->flag_out & ~(1 << Card::$FLAG_KEY)  );
            /** @noinspection PhpUndefinedClassInspection */
        }else{
            $this->flag =  ( $this->flag & ~(1 << Card::$FLAG_KEY)  );
            $this->flag_out =  ( $this->flag_out & ~(1 << Card::$FLAG_KEY)  );
        }
        \Yii::info("flag has key: ".$this->flag .";".$this->flag_out);
	}


    public function isFlagValidity(){
        return Helper::isBitOn($this->flag,Card::$FLAG_TICKET);
    }

    public function isFlagDoor(){
        return Helper::isBitOn($this->flag,Card::$FLAG_DOOR);
    }

    public function isFlagKey(){
        return Helper::isBitOn($this->flag,Card::$FLAG_KEY);
    }

    public function isFlagStatus(){
        return Helper::isBitOn($this->flag,Card::$FLAG_STATUS);
    }

    public function isFlagOutDoor(){
        return Helper::isBitOn($this->flag_out,Card::$FLAG_DOOR);
    }

    public function isFlagOutKey(){
        return Helper::isBitOn($this->flag_out,Card::$FLAG_KEY);
    }

    /**
     * if flag is on, door entry is not allowed.
     */
    public function isFlagDoorAllowed(){
        return Helper::isBitOn($this->flag,Card::$FLAG_DOOR_ALLOWED);
    }

    public static function updateFlagStatus(){
        \Yii::$app->db->createCommand(self::$SQL_UPDATE_FLAG_STATUS_ACTIVE)->execute();
    }

    public function isFree(){
        return !isset($this->customer);
    }

    public function getActiveTickets(){
        return  Ticket::readActive($this);
    }

}
