#!/usr/bin/env python

from __future__ import print_function

"""
share-objects
~~~~~~~~~~~~~~~~~
Assigns sharing to shareable DHIS2 objects like userGroups and publicAccess by  calling the /api/sharing endpoint.
"""

import argparse
import sys

from six import iteritems

from core.core import Dhis


class Sharer(Dhis):
    """Inherited from core Dhis class to extend functionalities"""

    def __init__(self, server, username, password, api_version, debug_flag):
        Dhis.__init__(self, server, username, password, api_version, debug_flag)

    def get_usergroup_uids(self, filter_list, type):
        """Get UID(s) of userGroup(s) based on object filter"""
        params = {
            'fields': 'id,name',
            'paging': False,
            'filter': filter_list
        }

        print(("\n--- GET userGroup(s) for filter {} ({})".format(filter_list, type)))

        endpoint = 'userGroups'
        response = self.get(endpoint=endpoint, params=params)

        if len(response['userGroups']) > 0:
            # zip it into a dict { id: name, id:name }
            ugmap = {ug['id']: ug['name'] for ug in response['userGroups']}
            for (key, value) in iteritems(ugmap):
                self.log.info("{} - {}".format(key, value))
            return ugmap.keys()
        else:
            self.log.info("*** No userGroup(s) found. Wrong filter?")
            sys.exit()

    def get_objects(self, objects, objects_filter):
        """Returns filtered DHIS2 objects"""

        params = {
            'fields': 'id,name,code',
            'filter': objects_filter,
            'paging': False
        }
        print("\n--- GET {} with filter(s) {}".format(objects, objects_filter))
        response = self.get(endpoint=objects, params=params)

        if len(response[objects]) > 0:
            return response
        else:
            self.log.info('*** No objects found. Wrong filter?')
            sys.exit()

    def share_object(self, payload, parameters):
        """Share object by using sharing enpoint"""
        self.post(endpoint="sharing", params=parameters, payload=payload)


# argument parsing
parser = argparse.ArgumentParser(usage='%(prog)s [-h] -s -t -f [-w] [-r] -a [-v] -u -p -d',
                                 description="PURPOSE: Share DHIS2 objects (dataElements, programs, ...) with userGroups")
parser.add_argument('-s', dest='server', action='store', required=True,
                    help="DHIS2 server URL, e.g. 'play.dhis2.org/demo'")
parser.add_argument('-t', dest='object_type', action='store', required=True, choices=Dhis.objects_types,
                    help="DHIS2 object type to apply sharing, e.g. -t=sqlViews")
parser.add_argument('-f', dest='filter', action='store', required=True,
                    help="Filter on objects with DHIS2 field filter, e.g. -f='name:like:ABC'")
parser.add_argument('-w', dest='usergroup_readwrite', action='store', required=False,
                    help="UserGroup filter for Read-Write access, concat. with '&' e.g. -w='name:$ilike:UG1&id:!eq:aBc123XyZ0u'")
parser.add_argument('-r', dest='usergroup_readonly', action='store', required=False,
                    help="UserGroup filter for Read-Only access, concat. with '&' e.g. -r='id:eq:aBc123XyZ0u'")
parser.add_argument('-a', dest='publicaccess', action='store', required=True, choices=Dhis.public_access.keys(),
                    help="publicAccess (with login), e.g. -a=readwrite")
parser.add_argument('-v', dest='api_version', action='store', required=False, type=int,
                    help='DHIS2 API version e.g. -v=24')
parser.add_argument('-u', dest='username', action='store', required=True, help='DHIS2 username, e.g. -u=admin')
parser.add_argument('-p', dest='password', action='store', required=True, help='DHIS2 password, e.g. -p=district')
parser.add_argument('-d', dest='debug', action='store_true', default=False, required=False,
                    help="Debug flag - writes more info to log file, e.g. -d")
args = parser.parse_args()

# init DHIS
dhis = Sharer(server=args.server, username=args.username, password=args.password, api_version=args.api_version,
              debug_flag=args.debug)

user_group_accesses = []
if args.usergroup_readwrite:
    # split filter of arguments into list
    rw_ug_filter_list = args.usergroup_readwrite.split('&')
    # get UIDs of usergroups with RW access
    readwrite_usergroup_uids = dhis.get_usergroup_uids(rw_ug_filter_list, 'readwrite')
    for ug in readwrite_usergroup_uids:
        acc = {
            'id': ug,
            'access': Dhis.public_access['readwrite']
        }
        user_group_accesses.append(acc)

if args.usergroup_readonly:
    ro_ug_filter_list = args.usergroup_readonly.split('&')
    # get UID(s) of usergroups with RO access
    readonly_usergroup_uids = dhis.get_usergroup_uids(ro_ug_filter_list, 'readonly')
    for ug in readonly_usergroup_uids:
        acc = {
            'id': ug,
            'access': Dhis.public_access['readonly']
        }
        user_group_accesses.append(acc)

# split arguments for multiple filters for to-be-shared objects
object_filter_list = args.filter.split('&')

# pull objects for which to apply sharing
data = dhis.get_objects(args.object_type, object_filter_list)

no_of_obj = len(data[args.object_type])

dhis.log.info("Fetched {} {} to apply sharing settings...\n".format(no_of_obj, args.object_type))

counter = 1
for obj in data[args.object_type]:
    payload = {
        'object': {
            'publicAccess': Dhis.public_access[args.publicaccess],
            'externalAccess': False,
            'user': {},
            'userGroupAccesses': user_group_accesses
        }
    }
    # strip name to match API (e.g. dataElements -> dataElement)
    if args.object_type == 'categories':
        o_type = 'category'
    else:
        o_type = args.object_type[:-1]
    parameters = {
        'type': o_type,
        'preheatCache': False,
        'id': obj['id']
    }

    # apply sharing
    dhis.share_object(payload, parameters)

    try:
        dhis.log.info("({}/{}) [OK] {} {}".format(str(counter), str(no_of_obj), obj['id'], obj['code']))
    except KeyError:
        try:
            dhis.log.info("({}/{}) [OK] {} {}".format(str(counter), str(no_of_obj), obj['id'], obj['name']))
        except UnicodeEncodeError:
            dhis.log.info("({}/{}) [OK] {}".format(str(counter), str(no_of_obj), obj['id']))

    counter += 1
