<?php
/**
 * Created by PhpStorm.
 * User: stanley-king
 * Date: 2017/4/6
 * Time: 下午3:00
 */

namespace fcode;

require_once(BASE_ROOT_PATH . '/helper/session_helper.php');
require_once(BASE_ROOT_PATH . '/helper/util_helper.php');

use session_helper;
use Log;
use util;

class operator
{
    private $mCommonID;
    private $mod_fcode;
    private $mBatchCode;
    private $mMobile;
    private $mSessionID;
    private $mFUserMode;

    const time_out = 300;

    public function __construct($common_id, $batch_code, $mobile, $session_id)
    {
        $this->mCommonID = $common_id;
        $this->mBatchCode  = $batch_code;
        $this->mod_fcode = Model('goods_fcode');
        $this->mMobile = $mobile;
        $this->mSessionID = $session_id;
        $this->mFUserMode = !empty($session_id);
    }

    public function grabed()
    {
        $cond = [];
        $cond['goods_commonid'] = $this->mCommonID;
        $cond['batch_code']     = $this->mBatchCode;

        if(empty($this->mMobile) && empty($this->mSessionID)) {
            return false;
        }
        elseif (empty($this->mMobile)) {
            $cond['session_id'] = $this->mSessionID;
        }
        elseif(empty($this->mSessionID)) {
            $cond['mobile'] = $this->mMobile;
        }
        else {
            $cond['mobile|session_id'] = ['_multi'=>true,$this->mMobile,$this->mSessionID];
        }

        $fcode = $this->mod_fcode->getGoodsFCode($cond,true);
        if(empty($fcode)) {
            return false;
        }
        else {
            return $fcode;
        }
    }

    public function grab()
    {
        $fcode = $this->grabed();
        if($fcode != false) return $fcode;

        while(true)
        {
            $cond = array('goods_commonid' => $this->mCommonID,
                'batch_code' => $this->mBatchCode,
                'fc_state' => '0',
                'grab_state' => array('in', array(0,1)),
                'grab_time' => array('lt',time() - self::time_out));

            $fcodes = $this->mod_fcode->where($cond)->field('*')->order('fc_id asc')->limit(1)->select(array('master' => true));
            if(empty($fcodes) || empty($fcodes[0])) return false;

            $fcode = $this->try_grab($fcodes[0]);
            if($fcode != false) {
                return $fcode;
            }
        }
    }
    public function bind($fcode)
    {
        $cond = [];
        $cond['goods_commonid'] = $this->mCommonID;
        $cond['batch_code']      = $this->mBatchCode;

        $cond['user_key']       = $fcode['user_key'];
        $cond['fc_id']          = $fcode['fc_id'];
        $cond['fc_state']       = $fcode['fc_state'];
        $cond['grab_state']     = $fcode['grab_state'];
        $cond['grab_time']      = $fcode['grab_time'];
        $cond['session_id']     = $fcode['session_id'];
        $cond['mobile']         = $fcode['mobile'];

        $datas = ['grab_state' => 2,
            'user_key' => mt_rand(1000, 9999),
            'usable_time' => util::last_day_secs(time() + $fcode['usable_days'] * 86400)];

        if(!empty($this->mSessionID)) {
            $datas['session_id'] = $this->mSessionID;
        }
        if(!empty($this->mMobile)) {
            $datas['mobile'] = $this->mMobile;
        }

        $ret = $this->mod_fcode->where($cond)->update($datas);
        $affect_rows = $this->mod_fcode->affected_rows();

        Log::record("fcode::grab try_grab ret={$ret} affected_rows={$affect_rows}",Log::DEBUG);
        if($ret != false && $affect_rows > 0) {
            $fcode = array_merge($fcode,$datas);
            return $fcode;
        } else {
            return false;
        }
    }

    public function change($fcode)
    {
        return $this->bind($fcode);
    }

    public function lock($pay_sn)
    {
        $fcode = $this->grabed();
        if($fcode != false) return $fcode;

        while(true)
        {
            $cond = array('goods_commonid' => $this->mCommonID,
                'batch_code' => $this->mBatchCode,
                'fc_state' => '0',
                'grab_state' => array('in', array(0,1)),
                'grab_time' => array('lt',time() - self::time_out));

            $fcodes = $this->mod_fcode->where($cond)->field('*')->order('fc_id asc')->limit(1)->select(array('master' => true));
            if(empty($fcodes) || empty($fcodes[0])) return false;

            $fcode = $this->try_lock($fcodes[0],$pay_sn);
            if($fcode != false) {
                return $fcode;
            }
        }
    }

    public static function unlock($pay_sn)
    {
        $mod_fcode = Model('goods_fcode');
        $cur_time = util::last_day_secs(time());

        $ret = $mod_fcode->where(['pay_sn' => $pay_sn,'fc_state' => 3])
            ->update(['fc_state' => 0,'usable_time' => array('exp', "usable_days * 86400 + {$cur_time}")]);
        $affect_rows = $mod_fcode->affected_rows();

        if($ret != false && $affect_rows > 0) {
            return $affect_rows;
        } else {
            return 0;
        }
    }

    public static function reset($pay_sn)
    {
        $mod_fcode = Model('goods_fcode');
        $ret = $mod_fcode->where(['pay_sn' => $pay_sn,'fc_state' => 3])
            ->update(['fc_state' => 0,
                      'usable_time' => 0,
                      'mobile' => '',
                      'session_id' => '',
                      'grab_state' => 0,
                      'grab_time' => 0,
                      'pay_sn' => 0]);
        $affect_rows = $mod_fcode->affected_rows();

        if($ret != false && $affect_rows > 0) {
            return $affect_rows;
        } else {
            return 0;
        }
    }

    private function try_lock($fcode,$pay_sn)
    {
        $cond = [];
        $cond['goods_commonid'] = $this->mCommonID;
        $cond['batch_code']     = $this->mBatchCode;
        $cond['user_key']       = $fcode['user_key'];
        $cond['fc_id']          = $fcode['fc_id'];
        $cond['fc_state']       = $fcode['fc_state'];
        $cond['grab_state']     = $fcode['grab_state'];
        $cond['grab_time']      = $fcode['grab_time'];
        $cond['session_id']     = $fcode['session_id'];
        $cond['mobile']         = $fcode['mobile'];

        $datas = ['grab_state' => 2,
            'grab_time' => time(),
            'fc_state' => 3,
            'pay_sn' => $pay_sn,
            'user_key' => mt_rand(1000, 9999)];

        if(!empty($this->mSessionID)) {
            $datas['session_id'] = $this->mSessionID;
        }
        if(!empty($this->mMobile)) {
            $datas['mobile'] = $this->mMobile;
        }

        $ret = $this->mod_fcode->where($cond)->update($datas);
        $affect_rows = $this->mod_fcode->affected_rows();

        Log::record("fcode::grab try_grab ret={$ret} affected_rows={$affect_rows}",Log::DEBUG);
        if($ret != false && $affect_rows > 0) {
            $fcode = array_merge($fcode,$datas);
            return $fcode;
        } else {
            return false;
        }
    }

    private function try_grab($fcode)
    {
        $cond = [];
        $cond['goods_commonid'] = $this->mCommonID;
        $cond['batch_code']     = $this->mBatchCode;
        $cond['user_key']       = $fcode['user_key'];
        $cond['fc_id']          = $fcode['fc_id'];
        $cond['fc_state']       = $fcode['fc_state'];
        $cond['grab_state']     = $fcode['grab_state'];
        $cond['grab_time']      = $fcode['grab_time'];
        $cond['session_id']     = $fcode['session_id'];
        $cond['mobile']         = $fcode['mobile'];

        if($this->mFUserMode && session_helper::logined())
        {
            $datas =   ['grab_state' => 2,
                        'grab_time' => time(),
                        'user_key' => mt_rand(1000, 9999),
                        'usable_time' => util::last_day_secs(time() + $fcode['usable_days'] * 86400)];
        }
        else {
            $datas = ['grab_state' => 1,
                      'grab_time' => time()];
        }

        if(!empty($this->mSessionID)) {
            $datas['session_id'] = $this->mSessionID;
        }
        if(!empty($this->mMobile)) {
            $datas['mobile'] = $this->mMobile;
        }

        $ret = $this->mod_fcode->where($cond)->update($datas);
        $affect_rows = $this->mod_fcode->affected_rows();

        Log::record("fcode::grab try_grab ret={$ret} affected_rows={$affect_rows}",Log::DEBUG);
        if($ret != false && $affect_rows > 0) {
            $fcode = array_merge($fcode,$datas);
            return $fcode;
        } else {
            return false;
        }
    }
}