#pragma once

#include "numeral211/hand_numeral211.h"
#include "template/domain_dependent/hand_base.hpp"


////////////////////////////////////////////////////////////////////////////////

template<>
void HandBase<Numeral211>::init(){
    for(int i = 0; i<Poker_t::num_rounds * (Poker_t::num_rounds+1)/2; ++i){
        hand_indexer_init( Hand<Poker_t>::isomorphism_stages[i]
                         , Hand<Poker_t>::isomorphism_configs[i].data()
                         , &Hand<Poker_t>::isomorphism_indexers[i]);
    }
    initialized_ = true;
}

template<>
void HandBase<Numeral211>::free(){
    for(int i = 0; i<Poker_t::num_rounds * (Poker_t::num_rounds+1)/2; ++i){
        hand_indexer_free(&Hand<Poker_t>::isomorphism_indexers[i]);
    }
}

// template<> void 
// HandBase<Numeral211>::hand_unindex(uint64_t hand_index, int round, type::card_t* hand) {
//     ::hand_unindex( &Hand<Poker_t>::isomorphism_indexers[id_2d_to_1d(round, 0)]
//                   , Poker_t::isomorphism_stages[id_2d_to_1d(round, 0)]-1
//                   , hand_index
//                   , hand
//                   );
// }

// template<> uint64_t 
// HandBase<Numeral211>::compute_hand_index(int round, const type::card_t* hand) {
//     return hand_index_last(&Hand<Poker_t>::isomorphism_indexers[id_2d_to_1d(round, 0)], hand);
// }

template<> void 
HandBase<Numeral211>::hand_unisomorphism(uint64_t hand_isomorphism, int round, int recall_from, type::card_t* hand) {
    ::hand_unindex( &Hand<Poker_t>::isomorphism_indexers[id_2d_to_1d(round, recall_from)]
                  , Hand<Poker_t>::isomorphism_stages[id_2d_to_1d(round, recall_from)]-1
                  , hand_isomorphism
                  , hand
                  );
}

template<> uint64_t 
HandBase<Numeral211>::compute_hand_isomorphism(int round, int recall_from, const type::card_t* hand) {
    return hand_index_last(&Hand<Poker_t>::isomorphism_indexers[id_2d_to_1d(round, recall_from)], hand);
}


template<> uint64_t 
HandBase<Numeral211>::get_isomorphism_size(int round, int recall_from) {
    return Hand<Poker_t>::isomorphism_indexers[id_2d_to_1d(round, recall_from)].round_size[Hand<Poker_t>::isomorphism_stages[id_2d_to_1d(round, recall_from)]-1];
}

template<>
Hand<Numeral211> HandBase<Numeral211>::from_string(const std::string str){
    int round = -1;
    for(int r = 0, hl = str.size(); r < Poker_t::num_rounds; ++r){
        if(Poker_t::hand_len[r] * 2 == hl){
            round = r;
            break;
        }
    }
    assert(round != -1);

    type::card_t hand[Poker_t::hand_len[Poker_t::num_rounds-1]];

    const char* str_c = str.c_str();
    for(int i = 0, sz = str.size(); 2*i<sz; ++i) {
        hand[i] = Poker_t::CHAR_TO_SUIT[(int) *(str_c+2*i)] + Poker_t::CHAR_TO_RANK[(int) *(str_c+2*i+1)] * SUITS;
    }
    return Hand<Poker_t>(hand, hand + Poker_t::hole_len[Poker_t::num_rounds-1], round);
}

//////////////////////////////////////////////////////////////////////////////////

Hand<Numeral211>::Hand(const type::card_t* hole, const type::card_t* board, int round) : HandBase<Poker_t>(hole, board, round){
}