<?php

/**
 * Created by PhpStorm.
 * User: stanley-king
 * Date: 16/6/28
 * Time: 上午11:33
 */
require_once (BASE_ROOT_PATH . '/helper/account_helper.php');
require_once (BASE_ROOT_PATH . '/helper/predeposit_helper.php');

class friend
{
    //last_time,count,user_id
    private $mParam;

    public function __construct($param)
    {
        $this->mParam = $param;
    }

    public function last_time() {
        return intval($this->mParam['last_time']);
    }
    public function is_poor() {
        return (time() - intval($this->mParam['last_time']) <= shaker_helper::max_poor_period);
    }
    public function can_gain() {
        return (time() - intval($this->mParam['last_time']) >= shaker_helper::max_gain_period);
    }
    public function can_gain_system() {
        return (time() - intval($this->mParam['last_time']) >= shaker_helper::max_gain_period_system);
    }
    public function can_lost() {
        return (time() - intval($this->mParam['last_time']) >= shaker_helper::max_lost_period);
    }
    public function user_id() {
        return intval($this->mParam['user_id']);
    }
    public function count() {
        return intval($this->mParam['count']);
    }
}

class gain_policy
{
    const max_amount = 10;

    private $strength;
    private $total_amount;
    public function __construct($strength,$amount) {
        $this->strength = $strength;
        $this->total_amount = $amount;
    }

    public function calculate()
    {
        $scale = $this->scale();
        if($scale == false) {
            return false;
        }

        $cur_value = intval($this->total_amount) >= self::max_amount ? self::max_amount : $this->total_amount;
        $value = intval($this->scale() * $cur_value * 100 + 0.5);
        if($value == 0) {
            return false;
        }
        else {
            return $value / 100;
        }
    }

    private function scale()
    {
        if($this->strength == 5) {
            $start = 0.8;
            $end = 1.0;
        }
        elseif ($this->strength == 4) {
            $start = 0.6;
            $end = 0.8;
        }
        elseif ($this->strength == 3) {
            $start = 0.4;
            $end = 0.6;
        }
        elseif ($this->strength == 2) {
            $start = 0.2;
            $end = 0.4;
        }
        elseif ($this->strength == 1) {
            $start = 0.0;
            $end = 0.2;
        }
        else {
            return false;
        }

        $start = intval($start * 100 + 0.5);
        $end = intval($end * 100 + 0.5);

        $ret = mt_rand($start,$end);
        return $ret / 100;
    }
}

class shaker_helper
{
    const max_gain_period = 12 * 3600;
    const max_poor_period = 1800;
    const max_gain_period_system = 3 * 3600;
    const max_lost_period = 1800;
    const err_msg = '您此次么有抢到好友红包...邀请更多好友,更多机会哦~';

    const shake_expire  = 5;
    const direct_gain = 0;
    const direct_lost = 1;

    const max_strength = 5;

    private $strength = 1;

    private function gain(&$err)
    {
        $friends = $this->gain_friends();
        $usable_amount = 0.00;
        $user_id = $this->find_gain_friend($friends, $usable_amount);
        if ($user_id != false)
        {
            $policy = new gain_policy($this->strength, $usable_amount);
            $value = $policy->calculate();
            if($value == false) {
                $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
                return false;
            }

            $bonus = account_helper::gain_bonus($user_id, $_SESSION['member_id'], $value);
            if($bonus != false) {
                $this->add_gained_friend(array($user_id));
            } else {
                $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
            }

            return $bonus;
        }
        else
        {
            if ($this->gained_system() == false) {
                $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
                return false;
            }
            else
            {
                $policy = new gain_policy($this->strength, 10);
                $value = $policy->calculate();
                if($value == false) {
                    $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
                    return false;
                }

                $bonus = account_helper::gain_system($_SESSION['member_id'], $value);
                if($bonus != false) {
                    $this->save_gained_system();
                } else {
                    $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
                }
                return $bonus;
            }
        }
    }

    private function lost(&$err)
    {
        $pred = new predeposit_helper($_SESSION['member_id']);
        $total_amount = $pred->total_bonus();

        if(intval($total_amount * 100 + 0.5) <= 0) {
            $err = array('code' => errcode::ErrShake,'msg' => self::err_msg);
            return false;
        }

        $friends = $this->lost_friends();
        $user_id = $this->find_lost_friend($friends);

        if($user_id == false) {
            $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
            return false;
        }

        $policy = new gain_policy($this->strength, $total_amount);
        $value = $policy->calculate();
        if($value == false) {
            $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
            return false;
        }
        $bonus = account_helper::lost_bonus($_SESSION['member_id'],$user_id, $value);
        if($bonus != false) {
            $this->add_lost_friend(array($user_id));
        } else {
            $err = array('code' => errcode::ErrShake, 'msg' => self::err_msg);
            return false;
        }

        return $bonus;
    }

    private function find_lost_friend($friends)
    {
        while (true)
        {
            $count = count($friends);
            if($count == 0) {
                return false;
            }

            $pos = mt_rand(0,$count -1);
            return $friends[$pos];
        }
    }

    private function find_gain_friend($friends, &$usable_amount)
    {
        while (true)
        {
            $count = count($friends);
            if($count == 0) return false;

            $pos = mt_rand(0,$count -1);
            $mod_bonus = Model('user_bonus');
            $usable_amount = $mod_bonus->getUsableSum($friends[$pos]);

            if(intval($usable_amount * 100 + 0.5) > 0) {
                return $friends[$pos];
            } else {
                $this->add_poor_friend($friends[$pos]);
                array_splice($friends,$pos,1);
            }
        }
    }

    public function shake($strength,&$err)
    {
        if($this->can_shake() == false) {
            $period = self::shake_expire;
            $err = array('code' => errcode::ErrShake,'msg' => "摇得太频繁啦,{$period}秒钟只能摇一次~");
            return false;
        }

        $this->strength = $strength;
        $direct = $this->direction();
        if($direct == self::direct_gain) {
            $bonuses = $this->gain($err);
        }
        else {
            $bonuses = $this->lost($err);
        }
        if($bonuses != false) {
            $this->save_shake();
        }

        return $bonuses;
    }

    private function save_gained_system()
    {
        if(isset($_SESSION['game_shake']['gained_system'])) {
            $_SESSION['game_shake']['gained_system'] = array();
        }

        $system = &$_SESSION['game_shake']['gained_system'];
        if(empty($system)) {
            $system['user_id'] = $_SESSION['member_id'];
            $system['last_time'] = time();
            $system['count'] = 1;
        } else {
            $system['user_id'] = $_SESSION['member_id'];
            $system['last_time'] = time();
            $system['count'] = intval($system['count']) + 1;
        }
    }

    private function gained_system()
    {
        if(!isset($_SESSION['game_shake']['gained_system'])) {
            return true;
        } else {
            $param = $_SESSION['game_shake']['gained_system'];
            $friend = new friend($param);

            return $friend->can_gain_system();
        }
    }

    private function add_gained_friend($user_ids)
    {
        if(!isset($_SESSION['game_shake']['gained_friends'])) {
            $_SESSION['game_shake']['gained_friends'] = array();
        }
        $friends = &$_SESSION['game_shake']['gained_friends'];

        foreach ($user_ids as $user_id)
        {
            if(isset($friends[$user_id])) {
                $friends[$user_id]['user_id'] = $user_id;
                $friends[$user_id]['last_time'] = time();
                $friends[$user_id]['count'] = intval($friends[$user_id]['count']) + 1;
            } else {
                $friends[$user_id]['user_id'] = $user_id;
                $friends[$user_id]['last_time'] = time();
                $friends[$user_id]['count'] = 1;
            }
        }
    }

    private function add_poor_friend($user_id)
    {
        if(!isset($_SESSION['game_shake']['poor_friends'])) {
            $_SESSION['game_shake']['poor_friends'] = array();
        }
        $friends = &$_SESSION['game_shake']['poor_friends'];

        if(isset($friends[$user_id])) {
            $friends[$user_id]['user_id'] = $user_id;
            $friends[$user_id]['last_time'] = time();
            $friends[$user_id]['count'] = intval($friends[$user_id]['count']) + 1;
        } else {
            $friends[$user_id]['user_id'] = $user_id;
            $friends[$user_id]['last_time'] = time();
            $friends[$user_id]['count'] = 1;
        }
    }

    private function del_poor_friend($user_id)
    {
        if(!isset($_SESSION['game_shake']['poor_friends'])) {
            $_SESSION['game_shake']['poor_friends'] = array();
        }
        $friends = &$_SESSION['game_shake']['poor_friends'];
        if(isset($friends[$user_id])) {
            unset($friends[$user_id]);
        }
    }

    private function add_lost_friend($user_ids)
    {
        if(!isset($_SESSION['game_shake']['losted_friends'])) {
            $_SESSION['game_shake']['losted_friends'] = array();
        }
        $friends = &$_SESSION['game_shake']['losted_friends'];

        foreach ($user_ids as $user_id)
        {
            if(isset($friends[$user_id])) {
                $friends[$user_id]['user_id'] = $user_id;
                $friends[$user_id]['last_time'] = time();
                $friends[$user_id]['count'] = intval($friends[$user_id]['count']) + 1;
            } else {
                $friends[$user_id]['user_id'] = $user_id;
                $friends[$user_id]['last_time'] = time();
                $friends[$user_id]['count'] = 1;
            }
        }
    }

    //可以偷的好友
    private function gain_friends()
    {
        if(!isset($_SESSION['game_shake']['gained_friends'])) {
            $_SESSION['game_shake']['gained_friends'] = array();
        }
        $friends = $_SESSION['game_shake']['gained_friends'];

        $exids = [];
        foreach ($friends as $uid => $param)
        {
            $friend = new friend($param);
            if($friend->can_gain() == false) {
                $exids[] = $friend->user_id();
            }
        }

        if(!isset($_SESSION['game_shake']['poor_friends'])) {
            $_SESSION['game_shake']['poor_friends'] = array();
        }

        $poor_friends = $_SESSION['game_shake']['poor_friends'];
        foreach ($poor_friends as $uid => $param)
        {
            $friend = new friend($param);
            if($friend->is_poor()) {
                $exids[] = $friend->user_id();
            } else {
                $this->del_poor_friend($friend->user_id());
            }
        }

        $all_friends = relation_helper::friends(session_helper::memberid());

        sort($all_friends,SORT_NUMERIC);
        $all_friends = array_merge(array_unique($all_friends,SORT_NUMERIC),[]);
        sort($all_friends);
        foreach ($exids as $uid)
        {
            $pos = algorithm::bsearch($uid,$all_friends);
            if($pos != -1) {
                array_splice($all_friends,$pos,1);
            }
        }

        return $all_friends;
    }
    private function lost_friends()
    {
        if(!isset($_SESSION['game_shake']['losted_friends'])) {
            $_SESSION['game_shake']['losted_friends'] = array();
        }
        $friends = $_SESSION['game_shake']['losted_friends'];

        $exids = array();
        foreach ($friends as $param)
        {
            $friend = new friend($param);
            if($friend->can_lost() == false) {
                array_push($exids,$friend->user_id());
            }
        }

        $subscriber = relation_helper::subscriber($_SESSION['member_id']);
        $follower = relation_helper::follower($_SESSION['member_id']);

        $all_friends = array_merge($subscriber,$follower);
        sort($all_friends,SORT_NUMERIC);
        $all_friends = array_merge(array_unique($all_friends,SORT_NUMERIC),[]);
        sort($all_friends,SORT_NUMERIC);

        foreach ($exids as $uid)
        {
            $pos = algorithm::bsearch($uid,$all_friends);
            if($pos != -1) {
                array_splice($all_friends,$pos,1);
            }
        }

        return $all_friends;
    }

    private function can_shake()
    {
        if(!isset($_SESSION['game_shake'])) {
            $_SESSION['game_shake'] = array();
        }

        if(isset($_SESSION['game_shake']['last_time']))
        {
            $last_time = intval($_SESSION['game_shake']['last_time']);
            if($last_time + self::shake_expire >= time()) {
                return false;
            } else {
                return true;
            }
        }
        else {
            return true;
        }
    }
    private function save_shake()
    {
        if(!isset($_SESSION['game_shake'])) {
            $_SESSION['game_shake'] = array();
        }

        $_SESSION['game_shake']['last_time'] = time();
    }

    private function direction()
    {
        if(!isset($_SESSION['game_shake'])) {
            $_SESSION['game_shake'] = array();
        }

        if(!isset($_SESSION['game_shake']['direction'])) {
            $_SESSION['game_shake']['direction'] = self::direct_gain;
        }
        else
        {
            $rand = mt_rand(1,100);
            $direct = ($rand % 5) == 0 ?  self::direct_lost : self::direct_gain;
            $_SESSION['game_shake']['direction'] = $direct;
        }

        return $_SESSION['game_shake']['direction'];
    }
}