# -*- coding: utf-8 -*-
# @Time    : 2019/9/5 13:43
# @Author  : duofeng Wu
# @Site    : 
# @File    : util.py
# @Software: PyCharm

from collections import namedtuple, deque
from constants import Suit, SUIT_IMG, RANK_ORDER, BLACK, RED, Type, WEIGHT
from random import shuffle


class Card(namedtuple('Card', ['suit', 'rank'])):
    __slots__ = ()

    @property
    def is_black(self):
        return self.suit in BLACK

    @property
    def is_red(self):
        return self.suit in RED

    @property
    def is_spades(self):
        return self.suit == Suit.SPADES

    @property
    def is_hearts(self):
        return self.suit == Suit.HEARTS

    @property
    def is_clubs(self):
        return self.suit == Suit.CLUBS

    @property
    def is_diamonds(self):
        return self.suit == Suit.DIAMONDS

    @property
    def is_black_joker(self):
        return self.suit == Suit.SPADES and self.rank == RANK_ORDER[-1]

    @property
    def is_red_joker(self):
        return self.suit == Suit.HEARTS and self.rank == RANK_ORDER[-1]

    @property
    def is_joker(self):
        return self.is_black_joker or self.is_red_joker

    def __eq__(self, other):
        if isinstance(other, list):
            return self.suit == other[0] and self.rank == other[1]
        else:
            return self.rank == other.rank and self.suit == other.suit

    def __hash__(self):
        return hash(self.rank) ^ hash(self.suit)

    def __repr__(self):
        return SUIT_IMG[self.suit] + self.rank


class Cards(object):

    def __init__(self):
        self.__cards = [Card(i, j) for i in range(4) for j in RANK_ORDER[:-1] for _ in range(2)]
        for i in range(2):
            self.__cards.append(Card(Suit.SPADES, Type.JOKER))
            self.__cards.append(Card(Suit.HEARTS, Type.JOKER))
        shuffle(self.__cards)
        self.cards = deque(self.__cards)

    def deal(self, func=None):
        cards = [self.cards.pop() for _ in range(27)]
        if func:
            cards.sort(key=func)
        return cards

    def reset(self):
        shuffle(self.__cards)
        self.cards = deque(self.__cards)


# 根据权重分开
class Divisions(object):

    # 参数分别为卡牌，卡牌类型，卡牌牌号，卡牌个数
    def __init__(self, cards, card_type, rank):
        self.cards = cards
        self.card_type = card_type
        self.rank = rank

    '''
        types_num(list): 某种种类的个数
        total_num(int): 总选择数
        weight_table(list): 关联度
        space_size(int): 可选择牌大小数
    '''
    def run(self, weight_table):
        basic = WEIGHT.type_wight[self.card_type]
        for card in self.cards:
            basic *= WEIGHT.card_wight[card[1]]
        return basic


class Rank(object):

    def __init__(self):

        # Sort by game rules.
        self.str_order = {
            '2': 2, '3': 3, '4': 4, '5': 5,
            '6': 6, '7': 7, '8': 8, '9': 9,
            '10': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14,
            'JOKER': 16
        }

        # Sort by the number of points in the cards itself.
        self.number_order = {
            'A': 1, '2': 2, '3': 3, '4': 4, '5': 5,
            '6': 6, '7': 7, '8': 8, '9': 9, '10': 10,
            'J': 11, 'Q': 12, 'K': 13
        }

        # Sort by the rank.
        self.order = {
            '2': 15, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9,
            '10': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14, 'JOKER': 16
        }

        # the mapping of points in the cards itself
        self.number_map = ('', '', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A')

        # Number form of the current rank.
        self.value = 2

    @property
    def current(self):
        return self.number_map[self.value]

    def order_func(self, card):
        if card.rank == Type.JOKER and card.suit == 0:
            return 16
        elif card.rank == Type.JOKER and card.suit == 1:
            return 17
        else:
            return self.order[card.rank]

    def update(self, value):
        self.order[self.current] = self.str_order[self.current]
        self.value = self.number_map.index(value)
        self.order[self.current] = 15

    def reset(self):
        self.order[self.current] = self.str_order[self.current]
        self.value = 2
        self.order[2] = 15
