#pragma once
#include "overall_define.h"
#include "template/domain_dependent/hand_base.h"
#include <cstring>

template<typename Poker_t>
HandBase<Poker_t>::HandBase(const type::card_t* hole, const type::card_t* board, int round) : round(round){
    // int cur_idx = 0;
    // for(int i = 0; i<=round; ++i){
    //     if(Poker_t::deal_hole_round[i]){
    //         std::copy(hole + Poker_t::hole_len[i] - Poker_t::deal_hole_round[i], hole + Poker_t::hole_len[i], hand + cur_idx);
    //         cur_idx += Poker_t::deal_hole_round[i];
    //     }
    //     if(Poker_t::deal_board_round[i]){
    //         std::copy(board + Poker_t::board_len[i] - Poker_t::deal_board_round[i], board + Poker_t::board_len[i], hand + cur_idx);
    //         cur_idx += Poker_t::deal_board_round[i];
    //     }
    // }
    int hl = Poker_t::hole_len[round];
    std::memcpy(this->hand , hole, sizeof(type::card_t)*hl);
    std::memcpy(this->hand + hl, board, sizeof(type::card_t)*Poker_t::board_len[round]);
}

template<typename Poker_t>
HandBase<Poker_t>::~HandBase(){
}

template<typename Poker_t>
const type::card_t* HandBase<Poker_t>::get_data() const {
    return hand;
}

template<typename Poker_t>
int HandBase<Poker_t>::get_round() const {
    return round;
}
// template<typename Poker_t>
// uint64_t HandBase<Poker_t>::get_hand_index() const{
//     return HandBase<Poker_t>::compute_hand_index(this->round, this->hand);
// }
// template<typename Poker_t>
// void HandBase<Poker_t>::hand_unindex(uint64_t idx, int round) {
//     this->round = round;
//     HandBase<Poker_t>::hand_unindex(idx, round, this->hand);
// }

template<typename Poker_t>
uint64_t HandBase<Poker_t>::get_hand_isomorphism(int recall_from) const {
    return HandBase<Poker_t>::compute_hand_isomorphism(this->round, recall_from, this->hand);
}
template<typename Poker_t>
void HandBase<Poker_t>::hand_unisomorphism(uint64_t iso, int round, int recall_from){
    this->round = round;
    HandBase<Poker_t>::hand_unisomorphism(iso, round, recall_from, this->hand);
}

template<typename Poker>
void HandBase<Poker>::change_hole(const type::card_t* hole) {
    std::memcpy(this->hand , hole, sizeof(type::card_t) * Poker_t::hole_len[round]);
}

template<typename Poker>
void HandBase<Poker>::change_board(const type::card_t* board) {
    std::memcpy(this->hand + Poker_t::hole_len[round], board, sizeof(type::card_t)*Poker_t::board_len[round]);
}

// 默认hand中前面是hole， 后面是board, round是发牌后的轮次
template<typename Poker_t>
void add_deal(type::card_t* hand, const type::card_t* new_round_cards, int round){
    if(Poker_t::deal_hole_round[round]) {
        /*将牌向后移动本轮次应发私有牌的数量*/
        std::copy( std::reverse_iterator<type::card_t*>(hand+Poker_t::hand_len[round-1])
                 , std::reverse_iterator<type::card_t*>(hand+Poker_t::hole_len[round-1])
                 , std::reverse_iterator<type::card_t*>(hand+Poker_t::hand_len[round-1] + Poker_t::deal_hole_round[round]));
        /*发私有牌*/
        std::memcpy(hand+Poker_t::hole_len[round-1], new_round_cards, sizeof(type::card_t) * Poker_t::deal_hole_round[round]);
    }
    /*发公共牌*/
    std::memcpy( hand + Poker_t::hand_len[round-1] + Poker_t::deal_hole_round[round]
               , new_round_cards +  Poker_t::deal_hole_round[round]
               , sizeof(type::card_t) * Poker_t::deal_board_round[round]);
}

template<typename Poker>
void HandBase<Poker>::add_deal(const type::card_t* new_round_cards) {
    assert(round < Poker_t::num_rounds);
    ++round;
    ::add_deal<Poker_t>(hand, new_round_cards, round);
}

template<typename Poker_t>
void add_deal(type::card_t* hand, const type::card_t* new_round_hole, const type::card_t* new_round_board, int round) {
    if(Poker_t::deal_hole_round[round]) {
        /*将牌向后移动本轮次应发私有牌的数量*/
        std::copy( std::reverse_iterator<type::card_t*>(hand+Poker_t::hand_len[round-1])
                 , std::reverse_iterator<type::card_t*>(hand+Poker_t::hole_len[round-1])
                 , std::reverse_iterator<type::card_t*>(hand+Poker_t::hand_len[round-1] + Poker_t::deal_hole_round[round]));
        /*发私有牌*/
        std::memcpy(hand+Poker_t::hole_len[round-1], new_round_hole, sizeof(type::card_t) * Poker_t::deal_hole_round[round]);
    }
    /*发公共牌*/
    std::memcpy( hand + Poker_t::hand_len[round-1] + Poker_t::deal_hole_round[round]
               , new_round_board
               , sizeof(type::card_t) * Poker_t::deal_board_round[round]);
}

template<typename Poker>
void HandBase<Poker>::add_deal(const type::card_t* new_round_hole, const type::card_t* new_round_board) {
    assert(round < Poker_t::num_rounds);
    ++round;
    ::add_deal<Poker_t>(hand, new_round_hole, new_round_board, round);
}

template<typename Poker_t>
inline constexpr std::array<std::array<uint8_t, MAX_STREETS>, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> HandBase<Poker_t>::isomorphism_configs = get_isomorphism_configs<Poker_t>();

template<typename Poker_t>
inline constexpr std::array<int, Poker_t::num_rounds*(Poker_t::num_rounds+1)/2> HandBase<Poker_t>::isomorphism_stages = get_isomorphism_stages<Poker_t>();