from collections import namedtuple
from xml.etree import ElementTree as et

from .. import core
from parallels.core.utils.common import if_not_none

ServerInfo = namedtuple('ServerInfo', (
	'key', 'gen_info', 'components', 'statistics', 'admin', 'interfaces', 'services', 'shells', 'session_setup'
))

ServerKey = namedtuple('ServerKey', ('properties'))
ServerGenInfo = namedtuple('ServerGenInfo', ('name', 'guid', 'external_id', 'mode'))
ServerComponent = namedtuple('ServerComponent', ('name', 'version'))
ServerStat = namedtuple('ServerStat', ('objects', 'versions', 'other', 'load', 'memory', 'swap', 'disk_space'))
ServerAdmin = namedtuple('ServerAdmin', (
	'cname', 'pname', 'phone', 'fax', 'email', 'address', 'city', 'state', 'pcode', 'country', 'send_announce',
))
ServerServiceState = namedtuple('ServerServiceState', ('id', 'title', 'state', 'error'))
ServerPrefs = namedtuple('ServerPrefs', ())
ServerShell = namedtuple('ServerShell', ('name', 'path'))
ServerSessionSetup = namedtuple('ServerSessionSetup', ('login_timeout'))

ServerObjectsStatistics = namedtuple('ServerObjectsStatistics', (
	'clients', 'domains', 'active_domains', 'mail_boxes', 'mail_redirects', 'mail_groups',
	'mail_responders', 'web_users', 'databases', 'database_users', 'problem_clients', 'problem_domains',
))
ServerVersionStatistics = namedtuple('ServerVersionStatistics', (
	'plesk_name', 'plesk_version', 'plesk_os', 'plesk_os_version', 'plesk_build', 'os_release', 'veid'
))
ServerOtherStatistics = namedtuple('ServerOtherStatistics', (
	'cpu', 'uptime', 'inside_vz',
))
ServerCpuUsage = namedtuple('ServerCpuUsage', ('l1', 'l5', 'l15'))
ServerMemoryStatistics = namedtuple('ServerMemoryStatistics', (
	'total', 'used', 'free', 'shared', 'buffer', 'cached',
))
ServerSwapStatistics = namedtuple('ServerSwapStatistics', ('total', 'used', 'free'))
ServerDiskSpaceStatistics = namedtuple('ServerDiskSpaceStatistics', (
	'name', 'total', 'used', 'free',
))


class ServerOperator(object):
	class Dataset(object):
		KEY = 'key'
		GEN_INFO = 'gen_info'
		COMPONENTS = 'components'
		STAT = 'stat'
		ADMIN = 'admin'
		INTERFACES = 'interfaces'
		SERVICES_STATE = 'services_state'
		PREFERENCES = 'prefs'
		SHELLS = 'shells'
		SESSION_SETUP = 'session_setup'

		values = [KEY, GEN_INFO, COMPONENTS, STAT, ADMIN, INTERFACES, SERVICES_STATE, PREFERENCES, SHELLS, SESSION_SETUP]
		
	class Get(core.operation('Get', ('dataset'))):
		operator_name = 'server'
		operation_name = 'get'
		min_api_version = '1.5.2.1'
		max_api_version = None

		def inner_xml(self):
			return [et.Element(value) for value in ServerOperator.Dataset.values if value in self.dataset]
			
		@classmethod
		def parse(cls, elem):
			return core.Result.parse(elem.find('result'), cls._parse_data)
		
		@classmethod
		def _parse_data(cls, elem):
			key = if_not_none(elem.find('key'), cls._parse_key)
			gen_info = if_not_none(elem.find('gen_info'), cls._parse_gen_info)
			components = if_not_none(elem.find('components'), cls._parse_components)
			statistics = if_not_none(elem.find('stat'), cls._parse_statistics)
			admin = if_not_none(elem.find('admin'), cls._parse_admin_info)
			interfaces = if_not_none(elem.find('interfaces'), cls._parse_interfaces)
			services = if_not_none(elem.find('services_state'), cls._parse_services_state)
			shells = if_not_none(elem.find('shells'), cls._parse_shells)
			session_setup = if_not_none(elem.find('session_setup'), cls._parse_session_setup)
			return ServerInfo(key, gen_info, components, statistics, admin, interfaces, services, shells, session_setup)
			
		@classmethod
		def _parse_key(cls, key_elem):
			key_props = [(e.findtext('name'), e.findtext('value')) for e in key_elem.findall('property')]
			return ServerKey(dict(key_props))

		@classmethod
		def _parse_gen_info(cls, gi_elem):
			name = gi_elem.findtext('server_name')
			guid = gi_elem.findtext('server_guid')
			external_id = gi_elem.findtext('external-id')
			mode = gi_elem.findtext('mode')  # standard | poweruser
			return ServerGenInfo(name, guid, external_id, mode)
		
		@classmethod
		def _parse_components(cls, elem):
			return dict(
				(n.findtext('name'), ServerComponent(n.findtext('name'), n.findtext('version')))
				for n in elem.findall('component')
			)
		
		@classmethod
		def _parse_statistics(cls, elem):
			objects = cls._parse_objects_statistics(elem.find('objects'))
			versions = cls._parse_version_statistics(elem.find('version'))
			other = cls._parse_other_statistics(elem.find('other'))
			load = cls._parse_load_statistics(elem.find('load_avg'))
			memory = cls._parse_memory_statistics(elem.find('mem'))
			swap = cls._parse_swap_statistics(elem.find('swap'))
			disk_space = cls._parse_disk_space_statistics(elem.find('diskspace'))
			return ServerStat(objects, versions, other, load, memory, swap, disk_space)
		
		@classmethod
		def _parse_objects_statistics(cls, elem):
			return ServerObjectsStatistics._make(int(elem.findtext(name)) for name in ServerObjectsStatistics._fields)
		
		@classmethod
		def _parse_version_statistics(cls, elem):
			return ServerVersionStatistics(
				elem.findtext('plesk_name'),
				elem.findtext('plesk_version'),
				elem.findtext('plesk_os'),
				elem.findtext('plesk_os_version'),
				elem.findtext('plesk_build'),
				elem.findtext('os_release'),
				if_not_none(elem.findtext('veid'), int),
			)
			
		@classmethod
		def _parse_other_statistics(cls, elem):
			return ServerOtherStatistics(
				elem.findtext('cpu'),
				int(elem.findtext('uptime')),
				elem.findtext('inside_vz') == 'true',
			)
			
		@classmethod
		def _parse_load_statistics(cls, elem):
			return ServerCpuUsage._make(float(elem.findtext(name)) for name in ServerCpuUsage._fields)
		
		@classmethod
		def _parse_memory_statistics(cls, elem):
			return ServerMemoryStatistics._make(int(elem.findtext(name)) for name in ServerMemoryStatistics._fields)
		
		@classmethod
		def _parse_swap_statistics(cls, elem):
			return ServerSwapStatistics._make(int(elem.findtext(name)) for name in ServerSwapStatistics._fields)

		@classmethod
		def _parse_disk_space_statistics(cls, elem):
			stats = [
				ServerDiskSpaceStatistics(
					e.findtext('name'), int(e.findtext('total')), int(e.findtext('used')), int(e.findtext('free'))
				)
				for e in elem.findall('device')
			]
			return dict((s.name, s) for s in stats)
		
		@classmethod
		def _parse_interfaces(cls, elem):
			return set(e.text for e in elem.findall('interface'))

		@classmethod
		def _parse_services_state(cls, elem):
			services = [
				ServerServiceState(e.findtext('id'), e.findtext('title'), e.findtext('state'), e.findtext('error'))
				for e in elem.findall('srv')
			]
			return dict((s.id, s) for s in services)

		@classmethod
		def _parse_shells(cls, elem):
			shells = [
				ServerShell(e.findtext('name'), e.findtext('path'))
				for e in elem.findall('shell')
			]
			return dict((s.name, s) for s in shells)
		
		@classmethod
		def _parse_session_setup(cls, elem):
			return ServerSessionSetup(if_not_none(elem.findtext('login_timeout'), int))
		
		@classmethod
		def _parse_admin_info(cls, elem):
			return ServerAdmin(
				elem.findtext('cname'), elem.findtext('pname'),
				elem.findtext('phone'), elem.findtext('fax'), elem.findtext('email'),
				elem.findtext('address'), elem.findtext('city'), elem.findtext('state'), elem.findtext('pcode'),
				elem.findtext('country'), elem.findtext('send_announce') == 'true',
			)