<?php
/**
 * Created by PhpStorm.
 * User: stanley-king
 * Date: 2017/8/30
 * Time: 下午9:14
 */

namespace activity;

use algorithm;
use StatesHelper;
use Log;
use commonid_helper;

//M元买N件商品活动
class opgroup
{
    private $mPrice;
    private $mOptions;
    private $mStartTm;
    private $mEndTm;
    private $mGoods;
    private $mRepeat;
    private $mSpecialID;

    public function __construct($price,$options,$start,$end,$repeat,$special_id)
    {
        $this->mPrice = $price;
        $this->mOptions = $options;
        $this->mStartTm = $start;
        $this->mEndTm = $end;
        $this->mRepeat = $repeat;
        $this->mSpecialID = $special_id;

        $this->mGoods = [];
    }

    public function match($goods_nums)
    {
        if($this->acting() == false) return false;

        $gids = array_keys($goods_nums);
        sort($gids);
        $match_gids = algorithm::set_intersection($this->mGoods,$gids);

        $matched = false;
        if($this->mRepeat == false)
        {
            if(count($match_gids) >= $this->mOptions) {
                $matched = true;
            }
        }
        else
        {
            $goods_num = $this->goods_num($match_gids, $goods_nums);
            if ($goods_num >= $this->mOptions) {
                $matched = true;
            }
        }

        if($matched)
        {
            $matched_goods = [];
            foreach ($match_gids as $gid) {
                $matched_goods[$gid] = $goods_nums[$gid];
            }
            return ['goods_nums' => $matched_goods,'price' => $this->mPrice,'options' => $this->mOptions,'repeat' => $this->mRepeat];
        } else {
            return false;
        }
    }

    public function info($gid)
    {
        if($this->acting() == false) return false;

        if(algorithm::binary_search($this->mGoods,$gid))
        {
            $result['special_id'] = $this->mSpecialID;
            $price = $this->mPrice / 100;
            $result['desc'] = "{$price}元任选{$this->mOptions}件";
            $result['short_desc'] = "{$price}选{$this->mOptions}";

            return $result;
        } else {
            return false;
        }
    }

    private function goods_num($gids,$gid_nums)
    {
        $num = 0;
        foreach ($gids as $gid)
        {
            $num += $gid_nums[$gid];
        }
        return $num;
    }

    public function add_goods($gid)
    {
        $gid = intval($gid);
        if($gid <= 0) return false;

        if(algorithm::binary_search($this->mGoods,$gid)) {
            return false;
        } else {
            $pos = algorithm::lower_bonud($this->mGoods,$gid);
            algorithm::array_insert($this->mGoods,$pos,$gid);
            return true;
        }
    }
    public function acting() {
        $cur_tm = time();
        return ($cur_tm >= $this->mStartTm && $cur_tm < $this->mEndTm);
    }
    public function equal($price,$options) {
        return ($this->mPrice == $price && $this->mOptions == $options);
    }
}

class optional_goods
{
    private $mAllGoods;
    private $mOpgroups;
    private $mSpecials;
    private $mErrGoods;

    static private $stInstance = null;

    private function __construct()
    {
        $this->mOpgroups = [];
        $this->mAllGoods = [];
        $this->mSpecials = [];
        $this->mErrGoods = [];
    }

    static public function instance()
    {
        if (self::$stInstance == null) {
            self::$stInstance = new optional_goods();
        }
        if (StatesHelper::fetch_state('optional_goods')) {
            Log::record("optional_goods reinit data.", Log::DEBUG);
            self::$stInstance->init();
        }
        return self::$stInstance;
    }

    public function layout_error()
    {
        if (empty($this->mErrGoods)) {
            return false;
        } else {
            return $this->mErrGoods;
        }
    }

    public function all_goods()
    {
        return $this->mAllGoods;
    }

    public function exist_goods($gid)
    {
        $gid = intval($gid);
        if ($gid <= 0) return false;

        if (algorithm::binary_search($this->mAllGoods, $gid)) {
            return true;
        } else {
            return false;
        }
    }

    public function info($goods_id)
    {
        $gid = intval($goods_id);
        if ($gid <= 0) return false;

        if (algorithm::binary_search($this->mAllGoods, $gid))
        {
            foreach ($this->mOpgroups as $group)
            {
                $info = $group->info($gid);
                if($info == false) continue;

                if($group->acting() == false) {
                    return false;
                } else {
                    return $info;
                }
            }
            return false;
        } else {
            return false;
        }
    }

    public function match($gidnums)
    {
        $input_goods = $this->input_goods($gidnums);
        $match_goods = algorithm::set_intersection($this->mAllGoods, $input_goods);
        if (empty($match_goods)) return false;

        $match_goods = $this->sel_goods($match_goods, $gidnums);

        $result = [];
        foreach ($this->mOpgroups as $opgroup)
        {
            if (empty($match_goods)) break;
            $part = $opgroup->match($match_goods);
            if ($part != false) {
                $result[] = $part;
                $goods_nums = $part['goods_nums'];
                foreach ($goods_nums as $gid => $num) {
                    unset($match_goods[$gid]);
                }
            }
        }

        return $result;
    }

    private function sel_goods($gids, $gidnums)
    {
        $result = [];
        foreach ($gids as $gid) {
            $result[$gid] = $gidnums[$gid];
        }
        return $result;
    }

    private function input_goods($gidnums)
    {
        $result = [];
        foreach ($gidnums as $gid => $num) {
            if ($num > 0) {
                $result[] = $gid;
            }
        }
        sort($result);
        return $result;
    }

    private function init()
    {
        global $config;
        $opids = $config['optional_goods'];
        if (empty($opids)) return true;

        $this->mOpgroups = [];
        $this->mAllGoods = [];
        $this->mSpecials = [];
        $this->mErrGoods = [];

        $this->mSpecials = array_unique($opids);
        foreach ($this->mSpecials as $special_id) {
            $this->add_special($special_id);
        }
        sort($this->mErrGoods);
    }

    private function add_special($special_id)
    {
        $mod_special = Model('mb_special');
        $ret = $mod_special->getMbSpecialItemUsableListByID($special_id);
        $blocks = $ret['blocks'];

        $cur_group = null;
        foreach ($blocks as $block)
        {
            $type = $block['item_type'];
            if ($type == 'home1') {
                $tmp_group = $this->add_group($block, $special_id);
                if ($tmp_group != null) {
                    $cur_group = $tmp_group;
                    $this->mOpgroups[] = $cur_group;
                }
            } else {
                $this->add_goods($cur_group, $block);
            }
        }
    }

    private function add_goods($group, $block)
    {
        $items = $block['items'];
        if (empty($items)) return;

        foreach ($items as $item)
        {
            if (array_key_exists('type', $item) && $item['type'] == 'goods')
            {
                $goods_id = intval($item['data']);

                $spugids = $this->spu_goods($goods_id);
                if($spugids == false) continue;

                foreach ($spugids as $goods_id)
                {
                    if ($group != null && $goods_id > 0 && $this->exist_goods($goods_id) == false) {
                        if ($group->add_goods($goods_id)) {
                            $this->addgoods($goods_id);
                        }
                    } else {
                        $this->mErrGoods[] = $goods_id;
                    }
                }
            }
        }
    }

    private function spu_goods($gid)
    {
        $cid = commonid_helper::instance()->common_id($gid);
        if($cid != false)
        {
            $gids = commonid_helper::instance()->goods_ids($cid);
            if($gids == false) return false;

            if(count($gids) == 1) {
                return $gids;
            }
            else
            {
                $goods_map = [];

                $mod_goods = Model('goods');
                $goodses = $mod_goods->getGoodsOnlineList(array('goods_id' => array('in', $gids)));
                foreach ($goodses as $goods) {
                    $gid = intval($goods['goods_id']);
                    $goods_map[$gid] = $goods['goods_price'];
                }
                $goods_price = $goods_map[$gid];

                $result = [];
                foreach ($goods_map as $goods_id => $price)
                {
                    if($price == $goods_price) {
                        $result[] = $goods_id;
                    }
                }

                return empty($result) ? false : $result;
            }
        }
        else {
            return false;
        }
    }

    private function add_group($block,$special_id)
    {
        $items = $block['items'];
        if(empty($items)) return null;

        $reserved = $items['reserved'];
        $params = preg_split("/#/",$reserved);
        if(count($params) == 5)
        {
            $price   = intval($params[0] * 100 + 0.5);
            $options = intval($params[1]);
            $repeat  = intval($params[2]) == 1 ? true : false;
            $startm  = strtotime($params[3]);
            $hours   = intval($params[4]);

            if($price > 0 && $options > 1)
            {
                $group = $this->find($price,$options);
                if($group == null)
                {
                    if($startm > 0 && $hours > 0 && $startm + 3600 * $hours >  time()) {
                        $group = new opgroup($price,$options,$startm,$startm + 3600 * $hours,$repeat,$special_id);
                    }
                }
                return $group;
            }
            else {
                return null;
            }
        }
    }

    private function find($price,$options)
    {
        foreach ($this->mOpgroups as $item)
        {
            if($item->equal($price,$options)) {
                return $item;
            }
        }
        return null;
    }
    private function addgoods($gid)
    {
        $gid = intval($gid);
        if($gid <= 0) return false;

        if(algorithm::binary_search($this->mAllGoods,$gid)) {
            return false;
        } else {
            $pos = algorithm::lower_bonud($this->mAllGoods,$gid);
            algorithm::array_insert($this->mAllGoods,$pos,$gid);
            return true;
        }
    }
}
