import ldclient

class DNGLDClient(ldclient.LDClient):
    
    def dng_get_project_by_id(self, project_id):
        """Retrieves an ldclient.models.Project object from a project ID or None if no matching project is found."""
        project = None
        projects = self.projects()
        for p in projects:
            if p.id == str(project_id):
                project = p
                break
        return project
    
    def dng_get_folder_by_id(self, folder_id, project_id = None):
        """Retrieves an ldclient.models.Folder object from a folder ID or None if no matching folder is found."""
        folder = None
        if project_id is None:
            folders = self.list_folders()
        else:
            folders = self.list_folders([str(project_id)])
        for f in folders:
            if f.id == str(folder_id):
                folder = f
                break
        return folder
    
    def dng_list_folders_by_name(self, folder_name, project_id = None):
        if project_id is None:
            all_folders = self.list_folders()
        else:
            all_folders = self.list_folders([str(project_id)])
        folders = []
        for folder in all_folders:
            if folder.name == folder_name:
                folders.append(folder)
        return folders
    
    def dng_list_live_reports_by_name(self, report_name, project_id = None, folder_id = None, is_template = None):
        if project_id is None:
            all_reports = self.live_reports()
        else:
            all_reports = self.live_reports([str(project_id)])
        reports = []
        for l in all_reports:
            if l.title == report_name:                
                if folder_id is None or [str(folder_id)] == l.tags or (str(folder_id) == "" and l.tags == []):
                    if is_template is None or l.template == is_template:
                        reports.append(l)
        return reports
    
    def dng_list_columns_by_ids(self, live_report_id, column_ids):
        column_descriptors = self.column_descriptors(live_report_id)
        columns = []
        ids = []
        for descriptor in column_descriptors:
            if descriptor.addable_column_id in column_ids:
                columns.append(descriptor)
                ids.append(descriptor.addable_column_id)
        return (columns, ids)
        
    def dng_list_groups_by_ids(self, live_report_id, group_ids):
        column_groups = self.get_column_groups_by_live_report_id(live_report_id)
        groups = []
        ids = []
        for group in column_groups:
            if group.id in group_ids:
                groups.append(group)
                ids.append(group.id)
        return (groups, ids)

def clientFactory(context):
    
	server_base = None
	if context.getGlobalProperties().find("LDServer") is not None:
		server_base = context.getGlobalProperties().get("LDServer").getValue().getString()
	elif context.getGlobalProperties().find("Live Design Server") is not None:
		server_base = context.getGlobalProperties().get("Live Design Server").getValue().getString()
	elif context.getGlobalProperties().find("/discngine/ldconn/LiveDesignServerUrl") is not None:
		server_base = context.getGlobalProperties().get("/discngine/ldconn/LiveDesignServerUrl").getValue().getString()
    
	# not used in v3.1+
	username = None
	if context.getGlobalProperties().find("LDUsername") is not None:
		username = context.getGlobalProperties().get("LDUsername").getValue().getString()
	elif context.getGlobalProperties().find("Live Design Username") is not None:
		username = context.getGlobalProperties().get("Live Design Username").getValue().getString()
    
	# not used in v3.1+
	password = None
	if context.getGlobalProperties().find("LDPassword") is not None:
		password = context.getGlobalProperties().get("LDPassword").getValue().getString()
	elif context.getGlobalProperties().find("Live Design Password") is not None:
		password = context.getGlobalProperties().get("Live Design Password").getValue().getString()

	verifySSL = True
	if context.getGlobalProperties().find('/discngine/ldconn/VerifySSL') is not None:
		verifySSLConf = context.getGlobalProperties().get('/discngine/ldconn/VerifySSL').getValue().getString()
		if verifySSLConf is not None and verifySSLConf != 'True':
			verifySSL = False

	jsessionid = ''
	if context.getGlobalProperties().find('ldsession') is not None:
		jsessionid = context.getGlobalProperties().get('ldsession').getValue().getString()

	client = None
	if jsessionid != '' and jsessionid is not None and jsessionid != 'none':
		if server_base is not None and server_base != '' :
			client = DNGLDClient(server_base + '/livedesign/api', session_id=jsessionid, verify_ssl=verifySSL)
		else:
			raise Exception('Error using Pipeline Pilot gadget connection details : server name not found.')
	elif username is not None and username != '' and password is not None and password != '' and server_base is not None and server_base != '' :
		client = DNGLDClient(server_base + '/livedesign/api', username, password, verify_ssl=verifySSL)
	else:
		raise ConnectionDetailsNotFoundError()

	client.ping()

	return client


### Helpers ###

def getStringArrayParameter(context, propertyName):
	propertyValue = []
	try :
		propertyValue = context.getGlobalProperties().get(propertyName).getValue().getStringArray()
	except Exception:
		propertyValue = context.getGlobalProperties().get(propertyName).getValue().getString().split("\n")
	if "" in propertyValue and len(propertyValue) == 1:
		propertyValue = []
	return propertyValue

def getStringArrayProperty(data, propertyName):
	propertyValue = []
	try :
		propertyValue = data.getProperties().get(propertyName).getValue().getStringArray()
	except Exception:
		propertyValue = data.getProperties().get(propertyName).getValue().getString().split("\n")
	return propertyValue

def convertToJson(obj):
    if isinstance(obj, dict):
        return { k: convertToJson(v) for k, v in obj.items() }
    elif hasattr(obj, "_ast"):
        return convertToJson(obj._ast())
    elif not isinstance(obj, str) and hasattr(obj, "__iter__"):
        return [ convertToJson(v) for v in obj ]
    elif hasattr(obj, "__dict__"):
        return {
            k: convertToJson(v)
            for k, v in obj.__dict__.items()
            if not callable(v) and not k.startswith('_')
        }
    else:
        return obj

### Exceptions ###

class LiveDesignException(Exception):
	def __init__(self, message):
		self.message = message
		super().__init__(self.message)

class LiveDesignCustomException(LiveDesignException):
	def __init__(self, message):
		self.message = message
		super().__init__(self.message)

class ConnectionDetailsNotFoundError(LiveDesignException):
	def __init__(self):
		self.message = 'No username/password/server name found. On Pipeline Pilot, use the "Set LiveDesign Connection Details" component to specify these.'
		super().__init__(self.message)

class NotFoundException(LiveDesignException):
    def set_search_type(self, is_name = False):
        if is_name:
            self.search_type = 'name'
        else:
            self.search_type = 'ID'

class LiveReportException(LiveDesignException):
	def set_live_report_type(self, is_template = False):
		if is_template:
			self.lr_type = 'Template'
		else:
			self.lr_type = 'LiveReport'

class LiveReportNotFoundError(LiveReportException, NotFoundException):
	def __init__(self, live_report_id = None, is_template = False, is_name = False):
		super().set_live_report_type(is_template)
		super().set_search_type(is_name)
		if live_report_id is None:
			self.message = 'The provided ' + self.lr_type + ' ' + self.search_type + ' was not found.'
		else:
			self.message = 'The ' + self.lr_type + ' ' + self.search_type + ' ' + str(live_report_id) + ' was not found.'
		super().__init__(self.message)

class ProjectNotFoundError(NotFoundException):
	def __init__ (self, project_id = None, is_default_project = False, is_name = False):
		super().set_search_type(is_name)
		if is_default_project:
				self.message = 'The default project ID defined by the package global DefaultProjectID was not found.'
		else:
			if project_id is None:
				self.message = 'The provided project ' + self.search_type + ' was not found.'
			else:
				self.message = 'The project ' + self.search_type + ' ' + str(project_id) + ' was not found.'
		super().__init__(self.message)

class FolderNotFoundError(NotFoundException):
	def __init__(self, folder_id = None, is_name = False):
		super().set_search_type(is_name)
		if folder_id is None:
			self.message = 'The provided folder ' + self.search_type + ' was not found.'
		else:
			self.message = 'The folder ' + self.search_type + ' ' + str(folder_id) + ' was not found.'
		super().__init__(self.message)

class ColumnNotFoundError(NotFoundException):
	def __init__(self, column_id = None, is_name = False):
		super().set_search_type(is_name)
		if column_id is None:
			self.message = 'The provided addable column ' + self.search_type + ' was not found.'
		else:
			if isinstance(column_id, (list,set)):
				if len(column_id) > 1:
					self.message = 'The addable column ' + self.search_type + 's ' + ', '.join(column_id) + ' were not found.'
				else:
					self.message = 'The addable column ' + self.search_type + ' ' + ', '.join(column_id) + ' was not found.'
			else:
				self.message = 'The addable column ' + self.search_type + ' ' + str(column_id) + ' was not found.'
		super().__init__(self.message)

class ColumnGroupNotFoundError(NotFoundException):
	def __init__(self, group_id = None, is_name = False):
		super().set_search_type(is_name)
		if group_id is None:
			self.message = 'The provided group ' + self.search_type + ' was not found.'
		else:
			if isinstance(group_id, (list,set)):
				if len(group_id) > 1:
					self.message = 'The group ' + self.search_type + 's ' + ', '.join(group_id) + ' were not found.'
				else:
					self.message = 'The group ' + self.search_type + ' ' + ', '.join(group_id) + ' was not found.'
			else:
				self.message = 'The group ' + self.search_type + ' ' + str(group_id) + ' was not found.'
		super().__init__(self.message)

class LiveReportAlreadyExistsError(LiveReportException):
	def __init__(self, live_report_name = None, is_template = False):
		super().set_live_report_type(is_template)
		if live_report_name is None:
			self.message = 'This ' + self.lr_type + ' name already exists at the specified location.'
		else:
			self.message = 'The ' + self.lr_type + ' name "' + live_report_name + '" already exists at the specified location.'
		super().__init__(self.message)

class EmptyLiveReportError(LiveReportException):
	def __init__(self, live_report_id = None, is_template = False):
		super().set_live_report_type(is_template)
		if live_report_id is None:
			self.message = 'The provided ' + self.lr_type + ' is empty.'
		else:
			self.message = 'The ' + self.lr_type + ' ' + str(live_report_id) + ' is empty.'
		super().__init__(self.message)
