# By: Riasat Ullah
# This file contains cache queries for task instances.

from objects.instance_state import InstanceState
from utils import cache_names, helpers
import json


def store_single_instance(client, instance):
    '''
    Stores a new open instance in the cache.
    :param client: cache client
    :param instance: InstanceState object
    '''
    assert isinstance(instance, InstanceState)
    client.hset(cache_names.open_instances, instance.instance_id, json.dumps(instance.to_dict(),
                                                                             default=helpers.jsonify_unserializable))


def store_multiple_instances(client, instances):
    '''
    Stores a new open instance in the cache.
    :param client: cache client
    :param instances: (list) of InstanceState object
    '''
    assert isinstance(instances, list) and len(instances) > 0
    data = dict()
    for inst in instances:
        assert isinstance(inst, InstanceState)
        data[inst.instance_id] = json.dumps(inst.to_dict(), default=helpers.jsonify_unserializable)
    client.hmset(cache_names.open_instances, data)


def get_single_instance(client, inst_id):
    '''
    Gets a single InstanceState object given its instance ID.
    :param client: cache client
    :param inst_id: instance ID
    :return: InstanceState object
    '''
    json_instance = client.hget(cache_names.open_instances, inst_id)
    if json_instance is not None:
        return InstanceState.create_instance(json.loads(json_instance))
    else:
        return None


def get_multiple_instances(client, id_list):
    '''
    Get multiple instances at the same time
    :param client: cache client
    :param id_list: (list) of instance IDs
    :return: (dict) -> {id: InstanceState object, ...}
    '''
    json_instances = client.hmget(cache_names.open_instances, id_list)
    data = dict()
    if json_instances is not None:
        for i in range(0, len(id_list)):
            inst_item = json_instances[i]
            if inst_item is not None:
                data[id_list[i]] = InstanceState.create_instance(json.loads(inst_item))
    return data


def get_open_instances(client):
    '''
    Gets all the open instances from cache.
    :param client: cache client
    :return: (dict) {inst_id: InstanceState, ...}
    '''
    inst_json = client.hgetall(cache_names.open_instances)
    data = dict()
    if inst_json is not None:
        for id_ in inst_json:
            inst_obj = InstanceState.create_instance(json.loads(inst_json[id_]))
            data[inst_obj.instance_id] = inst_obj
    return data


def remove_instance(client, inst_id):
    '''
    Remove an instance from the list of open instances.
    :param client: cache client
    :param inst_id: (int or list) ID of the instance to be removed
    '''
    if isinstance(inst_id, int):
        inst_id = [inst_id]
    if len(inst_id) > 0:
        client.hdel(cache_names.open_instances, *inst_id)


def remove_all_instances(client):
    '''
    Removes all open instances from the cache.
    :param client: cache client
    '''
    client.delete(cache_names.open_instances)


def store_pending_instance_update(client, update_details):
    '''
    Store the details of an instance update or business impact that should be dispatched
    through the business impact monitor.
    :param client: cache client
    :param update_details: (dict) the details of the update
    '''
    client.rpush(cache_names.pending_instance_updates,
                 json.dumps(update_details, default=helpers.jsonify_unserializable))


def get_all_pending_instance_updates(client):
    '''
    Gets all the pending instance updates (for subscribers).
    :param client: cache client
    :return: (list) [dict, ...]
    '''
    upd_list = client.lrange(cache_names.pending_instance_updates, 0, -1)
    if upd_list is None:
        return []
    else:
        return upd_list


def remove_pending_instance_updates(client, start, end):
    '''
    Remove all pending instance updates from cache.
    :param client: cache client
    :param start: start index
    :param end: end index
    '''
    client.ltrim(cache_names.pending_instance_updates, start, end)
