import pickle
import re
import os
import pandas as pd
from pycaret.classification import *


def serialize(obj):
    return obj.encode('latin1')

def unserialize(obj):
    return obj.decode('latin1')

def toPickle(obj):
    return pickle.dumps(obj, 0)

def toUnpickle(obj):
    return pickle.loads(obj)

def toCut(obj, width):
    return re.findall('.{1,%s}' % width, obj, flags=re.S)

def toUncut(obj):
    return "".join(obj)


def serializeModelsToStringDataframe(models_dict):
    pickled_models_dict = {}
    for model_id in models_dict:
        # każdy model zserializowany do Bytearray
        pickled_models_dict[model_id] = toPickle(models_dict[model_id])

    pickled_models_int_array_dict = {}
    for model_id in pickled_models_dict:
        # każda struktura Bytearray przekształcona do postaci słownika wartości int
        pickled_models_int_array_dict[model_id] = [x for x in pickled_models_dict[model_id]]


    pickled_models_int_str_dict = {}
    for model_id in pickled_models_int_array_dict:
        # każda tablica int przekształcona na ciąg znaków reprezentujący tablicę int (spacja jako separator liczb całkowitych)
        pickled_models_int_str_dict[model_id] = " ".join( [str(a) for a in pickled_models_int_array_dict[model_id]] )


    pickled_models_int_str_chopped_dict = {}
    for model_id in pickled_models_int_str_dict:
        # każdy ciąg liczb całkowitych przekształcony na listę fragmentów ciągów o szerokości 32000 (ograniczenie Python Visual: 32766)
        pickled_models_int_str_chopped_dict[model_id] = toCut(pickled_models_int_str_dict[model_id], width=32000)


    models_df_lst = []
    # Dla każdej wartości model_id zaczerpniętej ze słownika pickled_plots_int_str_chopped_dict...
    for model_id in pickled_models_int_str_chopped_dict:

        # ...pobierz listę fragmentów dla bieżącej wartości model_id
        chops_lst = pickled_models_int_str_chopped_dict[model_id]
        # pobierz liczbę fragmentów zawartych na liście
        num_chops = len(chops_lst)

        # utwórz tymczasową ramkę danych zawierającą identyfikator modelu, całkowitoliczbowy indeks
        # zliczanie fragmentów i zawartości listy ciągów fragmentów
        tmp_data = {
            'model_id': [model_id] * num_chops,
            'chunk_id': list(range(1, num_chops+1)),
            'model_str': chops_lst
        }

        tmp_df = pd.DataFrame(tmp_data, columns = ['model_id','chunk_id','model_str'])

        # dołącz tymczasową ramkę danych do listy ramek danych models_df_lst
        models_df_lst.append(tmp_df)


    # Scalanie wszystkich ramek danych models_df_lst w ramkę danych models_df
    models_df = pd.concat(models_df_lst, ignore_index=True)

    # Utwórz także ramkę danych identyfikatorów modeli
    model_ids_df = pd.DataFrame( pickled_models_int_str_chopped_dict.keys(), columns = ['model_id'])

    return model_ids_df, models_df


project_folder = r'c:\Users\User\Desktop\Extending Power BI\kod\Extending-Power-BI-with-Python-and-R-main\Chapter13\Python\'

# W tym przypadku mamy tylko jeden model. Więc zdeserializujemy go jako model_01.
# Następnie stworzymy słownik zawierający modele (w tym przypadku tylko jeden).
# Pamiętaj, że nie możesz dodawać rozszerzenia .pkl
model_01 = load_model(os.path.join(project_folder, "titanic-model"))

models_dict = {}
models_dict['model01'] = model_01


# Pobieranie ramki danych identyfikatorów modeli i ramki danych modeli zserializowanych
model_ids_df, models_df = serializeModelsToStringDataframe(models_dict)

