from parallels.source.custom import messages
from parallels.core.connections.connections import Connections
from parallels.core.connections.source_server import SourceServer
from parallels.core.migrator_config import read_source_unix_server_settings
from parallels.core.registry import Registry
from parallels.core.utils.config_utils import ConfigSection, get_sections_list
from parallels.core.utils.entity import Entity
from parallels.core.utils.common import group_by_id


class MigratorConnections(Connections):
	def __init__(self, config, target_panel):
		super(MigratorConnections, self).__init__(config, target_panel)

	def get_information_servers(self):
		return {}

	def get_source_server_by_id(self, server_id):
		section = ConfigSection(self._config, server_id)
		if 'ip' in section:
			return SourceServer(server_id, read_source_unix_server_settings(self._config, server_id))
		else:
			return None

	def get_source_backup_paths(self):
		"""
		:rtype: dict[basestring, basestring]
		"""
		backup_paths = {}

		for section in self._get_source_backup_config_sections():
			if self._config.has_option(section, 'path'):
				# for full backup, just provide the path specified in config
				backup_paths[section] = self._config.get(section, 'path')
			elif self._config.has_option(section, 'light-path'):
				# for light backup, provide path, where full backup will be put
				session_files = Registry.get_instance().get_context().session_files
				backup_paths[section] = session_files.get_path_to_full_backup_created_from_light(section)

		return backup_paths

	def iter_source_light_backup_configs(self):
		"""
		:rtype: collections.Iterable[parallels.source.custom.connections.LightBackupConfig]
		"""
		for section_name in self._get_source_backup_config_sections():
			section = ConfigSection(self._config, section_name)
			if 'light-path' in section:
				yield LightBackupConfig(
					source_id=section_name,
					path=section.get('light-path'),
					file_format=section.get('light-format', 'yaml').lower()
				)

	def iter_database_servers(self):
		"""
		:rtype: collections.Iterable[parallels.custom_panel_migrator.connections.DatabaseServerConfig]
		"""
		for section_name in self._get_source_database_servers_config_sections():
			section = ConfigSection(self._config, section_name)
			yield DatabaseServerConfig(
				db_server_id=section_name,
				db_type=section.get('type'),
				host=section.get('host'),
				port=section.get('port'),
				login=section.get('login'),
				password=section.get('password')
			)

	def get_source_light_backup_config(self, server_id):
		"""
		:type server_id: basestring
		:rtype: parallels.custom_panel_migrator.connections.LightBackupConfig
		"""
		light_backup_configs = group_by_id(self.iter_source_light_backup_configs(), lambda l: l.source_id)
		return light_backup_configs[server_id]

	def has_source_light_backup_config(self, server_id):
		"""
		:type server_id: basestring
		:rtype: bool
		"""
		light_backup_configs = group_by_id(self.iter_source_light_backup_configs(), lambda l: l.source_id)
		return server_id in light_backup_configs

	def _get_source_backup_config_sections(self):
		"""Get names of sections describing source backups

		:rtype: list[basestring]
		"""
		return get_sections_list(self._config, 'GLOBAL', 'source-backups')

	def _get_source_database_servers_config_sections(self):
		"""Get names of sections describing database servers

		:rtype: list[basestring]
		"""
		return get_sections_list(self._config, 'GLOBAL', 'database-servers')

	def get_source_backup_path(self, backup_id):
		"""
		:type backup_id: basestring
		:rtype: basestring
		"""
		backup_paths = self.get_source_backup_paths()
		if backup_id not in backup_paths:
			raise Exception(messages.UNABLE_TO_GET_BACKUP_PATH % backup_id)
		return backup_paths[backup_id]


class LightBackupConfig(Entity):
	def __init__(self, source_id, path, file_format):
		"""
		:type source_id: basestring
		:type path: basestring
		:type file_format: basestring
		"""
		self._source_id = source_id
		self._path = path
		self._file_format = file_format

	@property
	def source_id(self):
		"""Source ID - section name in migrator's configuration file

		:rtype: basestring
		"""
		return self._source_id

	@property
	def path(self):
		"""Path to the light backup

		:rtype: basestring
		"""
		return self._path

	@property
	def file_format(self):
		"""File format of the light backup: JSON or YAML (see FORMAT_* constants)

		:rtype: basestring
		"""
		return self._file_format


class DatabaseServerConfig(Entity):
	def __init__(self, db_server_id, db_type, host, port, login, password):
		"""
		:type db_server_id: basestring
		:type db_type: basestring
		:type host: basestring
		:type port: basestring
		:type login: basestring
		:type password: basestring
		"""
		self._db_server_id = db_server_id
		self._db_type = db_type
		self._host = host
		self._port = port
		self._login = login
		self._password = password

	@property
	def db_server_id(self):
		"""Database server ID - name of a section of the server in migrator's configuration file

		:rtype: basestring
		"""
		return self._db_server_id

	@property
	def db_type(self):
		"""Database type - 'mysql', 'postgresql' or 'mssql'

		:rtype: basestring
		"""
		return self._db_type

	@property
	def host(self):
		"""Database server host - hostname or IP address

		:rtype: basestring
		"""
		return self._host

	@property
	def port(self):
		"""Database server port

		:rtype: basestring
		"""
		return self._port

	@property
	def login(self):
		"""Administrator login of database server

		:rtype: basestring
		"""
		return self._login

	@property
	def password(self):
		"""Administrator password of database server

		:rtype: basestring
		"""
		return self._password
