import base64
import json

import numpy as np
import re
import io
from PIL import Image

import torii

THUMB_HEIGHT = 200
THUMB_WIDTH = 200

def basis_decomposition(value, basis=2):

    decomposition = []
    current = int(value)
    exp = 0
    sign = 1 if current >= 0 else -1
    current = abs(current)
    while True:
        factor = current % basis
        current //= basis
        decomposition.append(sign *factor)

        if current == 0:
            break

        exp += 1

    return decomposition

def fake_hierachy(cluster, basis=2):
    decomp = basis_decomposition(cluster, basis)

    hierarchy = ''
    level=0
    for i in range(len(decomp)-1, -1, -1):
        level += decomp[i] * (basis ** i)
        hierarchy += '/' + str(level)

    return hierarchy

def clear_dataset(service, dataset):
    filter = {'property':'content.dataset','value': dataset,'filterType':'string','operator':'eq'}
    while True:

        bos = service.list(filters=[filter])

        if len(bos) == 0:
            break

        for bo in bos:
            service.delete(bo)

def load_dataset(service, dataset, json_path):
    root_path = re.sub('{}/.*$'.format(dataset), dataset, json_path)

    with open(json_path) as file:
        clusters = json.load(file)

    for cluster, vector_paths in clusters.items():
        bo = {
            'dataset': dataset,
            'path': '',
            'thumb': '',
            'classification': None,
            'cluster': fake_hierachy(cluster, 5),
            'clusterHist': [cluster],
            'score': 0
        }

        for vector_path in vector_paths:

            # since we may use json dataset that were produced in FLE we
            # may have to chankge the actual file location
            name = re.sub(r'^.*/([^/]+)\.npy$'.format(dataset), r'\1', vector_path)
            vector_path = re.sub(r'^.*/{}'.format(dataset), root_path, vector_path)
            vector = np.load(vector_path).tolist()

            # encode bytes to base64 string
            image_path = '{}/results/cropped/images/{}.jpg'.format(root_path, name)
            with Image.open(image_path) as image:
                # resize the image to thumb
                width, height = image.size
                if height > THUMB_HEIGHT or width >THUMB_WIDTH:
                    image.resize((min(width, THUMB_WIDTH), min(height, THUMB_HEIGHT)), Image.ANTIALIAS)

                # generate the base64 string
                with io.BytesIO() as buffer:
                    image.save(buffer, format='PNG')
                    image_str = 'data:image/png;base64, ' + base64.b64encode(buffer.getvalue())

            bo['name'] = name
            bo['vector'] = vector
            bo['path'] = image_path
            bo['thumb'] = image_str
            bo['size'] = [width, height]

            service.create(bo, )



if __name__ == '__main__':

    t = torii.Torii()
    service = t.get_bo_service('labelBox.images')

    experiment_dir = '/work/Fujitsu/labelbox/2018_8_16_9_25_Thu'
    json_path = experiment_dir + '/results/cropped/clusters/alexnet/clusters.json'
    dataset = experiment_dir.split('/')[-1]

    # Reload the dataset
    clear_dataset(service, dataset)
    load_dataset(service, dataset, json_path)

    # Get the clusters
    clusters = service.distinct('content.cluster', limit=1000)
    for cluster, count in sorted(list(clusters.items()), key=lambda x: x[1], reverse=True):
        print(("Cluster {} contains {} images".format(cluster, count)))



