import ntpath
import logging

from parallels.common.utils.yaml_utils import read_yaml, write_yaml
from parallels.common.windows_rsync import RsyncInstaller, RsyncClient, RsyncServer, RsyncConfig, RsyncControl
from parallels.utils import generate_random_password

logger = logging.getLogger(__name__)


class RsyncPool(object):

	def __init__(self, storage_path_prefix):
		self._storage_path_prefix = storage_path_prefix
		self._clients = {}
		self._servers = {}

	def get(self, source, target, vhosts_dir=None, source_ip=None):
		if source is None and source_ip is None:
			raise Exception("Unable to get rsync: source server object or source server ip should be specified")

		client = self._prepare_client(target)
		server = self._prepare_server(source, vhosts_dir) if source is not None else None

		#  update config with passed vhost_dir
		if server is not None and server.vhosts_dir != vhosts_dir:
			self._update_server_vhosts_dir(source, vhosts_dir)

		return RsyncControl(
			target=target,
			target_rsync_bin=ntpath.join(client.base_path, 'rsync.exe'),
			source_ip=source.ip() if source is not None else source_ip,
			source_login=server.login if server is not None else None,
			source_password=server.password if server is not None else None,
			server=server
		)

	def stop_all(self):
		for ip in self._servers:
			self._servers[ip].stop()
		self._servers.clear()

	def _prepare_client(self, server):
		ip = server.ip()
		if ip not in self._clients:
			self._clients[ip] = RsyncClient(self._deploy(server))
		return self._clients[ip]

	def _prepare_server(self, server, vhosts_dir):
		ip = server.ip()
		if ip not in self._servers:
			rsync_server = RsyncServer(self._deploy(server), server)

			rsync_config = RsyncConfig(
				client_ips='"*"',
				vhosts_dir=vhosts_dir,
				migrator_dir=server.session_dir(),
				user='admin',
				password=generate_random_password()
			)

			rsync_server.configure(rsync_config)
			rsync_server.restart()

			self._servers[ip] = rsync_server

		return self._servers[ip]

	def _deploy(self, server):
		ip = server.ip()
		storage_path = self._storage_path_prefix + ip
		base_path = read_yaml(storage_path, True)
		if base_path is None:
			logger.debug("Install rsync on %s" % ip)
			rsync_installer = RsyncInstaller(server)
			base_path = rsync_installer.install()
			write_yaml(storage_path, base_path)
			logger.debug("Rsync on %s was installed into %s" % (ip, base_path))

		return base_path

	def _update_server_vhosts_dir(self, server, vhosts_dir):
		self._servers[server.ip()].set_vhosts_dir(vhosts_dir)