def initialize_connection(self):  # noqa: E501 pylint:disable=too-many-statements, too-many-branches
        """Initialize a socket to a Chromecast, retrying as necessary."""
        tries = self.tries

        if self.socket is not None:
            self.socket.close()
            self.socket = None

        # Make sure nobody is blocking.
        for callback in self._request_callbacks.values():
            callback['event'].set()

        self.app_namespaces = []
        self.destination_id = None
        self.session_id = None
        self._request_id = 0
        self._request_callbacks = {}
        self._open_channels = []

        self.connecting = True
        retry_log_fun = self.logger.error

        # Dict keeping track of individual retry delay for each named service
        retries = {}

        def mdns_backoff(service, retry):
            """Exponentional backoff for service name mdns lookups."""
            now = time.time()
            retry['next_retry'] = now + retry['delay']
            retry['delay'] = min(retry['delay']*2, 300)
            retries[service] = retry

        while not self.stop.is_set() and (tries is None or tries > 0):  # noqa: E501 pylint:disable=too-many-nested-blocks
            # Prune retries dict
            retries = {key: retries[key] for key in self.services if (
                key is not None and key in retries)}

            for service in self.services.copy():
                now = time.time()
                retry = retries.get(
                    service, {'delay': self.retry_wait, 'next_retry': now})
                # If we're connecting to a named service, check if it's time
                if service and now < retry['next_retry']:
                    continue
                try:
                    self.socket = new_socket()
                    self.socket.settimeout(self.timeout)
                    self._report_connection_status(
                        ConnectionStatus(CONNECTION_STATUS_CONNECTING,
                                         NetworkAddress(self.host, self.port)))
                    # Resolve the service name. If service is None, we're
                    # connecting directly to a host name or IP-address
                    if service:
                        host = None
                        port = None
                        service_info = get_info_from_service(service,
                                                             self.zconf)
                        host, port = get_host_from_service_info(service_info)
                        if host and port:
                            try:
                                self.fn = service_info.properties[b'fn']\
                                    .decode('utf-8')
                            except (AttributeError, KeyError, UnicodeError):
                                pass
                            self.logger.debug(
                                "[%s:%s] Resolved service %s to %s:%s",
                                self.fn or self.host, self.port, service, host,
                                port)
                            self.host = host
                            self.port = port
                        else:
                            self.logger.debug(
                                "[%s:%s] Failed to resolve service %s",
                                self.fn or self.host, self.port, service)
                            self._report_connection_status(
                                ConnectionStatus(
                                    CONNECTION_STATUS_FAILED_RESOLVE,
                                    NetworkAddress(service, None)))
                            mdns_backoff(service, retry)
                            # If zeroconf fails to receive the necessary data,
                            # try next service
                            continue

                    self.logger.debug("[%s:%s] Connecting to %s:%s",
                                      self.fn or self.host, self.port,
                                      self.host, self.port)
                    self.socket.connect((self.host, self.port))
                    self.socket = ssl.wrap_socket(self.socket)
                    self.connecting = False
                    self._force_recon = False
                    self._report_connection_status(
                        ConnectionStatus(CONNECTION_STATUS_CONNECTED,
                                         NetworkAddress(self.host, self.port)))
                    self.receiver_controller.update_status()
                    self.heartbeat_controller.ping()
                    self.heartbeat_controller.reset()

                    self.logger.debug("[%s:%s] Connected!",
                                      self.fn or self.host, self.port)
                    return
                except OSError as err:
                    self.connecting = True
                    if self.stop.is_set():
                        self.logger.error(
                            "[%s:%s] Failed to connect: %s. "
                            "aborting due to stop signal.",
                            self.fn or self.host, self.port, err)
                        raise ChromecastConnectionError("Failed to connect")

                    self._report_connection_status(
                        ConnectionStatus(CONNECTION_STATUS_FAILED,
                                         NetworkAddress(self.host, self.port)))
                    if service is not None:
                        retry_log_fun(
                            "[%s:%s] Failed to connect to service %s"
                            ", retrying in %.1fs",
                            self.fn or self.host, self.port,
                            service, retry['delay'])
                        mdns_backoff(service, retry)
                    else:
                        retry_log_fun(
                            "[%s:%s] Failed to connect, retrying in %.1fs",
                            self.fn or self.host, self.port, self.retry_wait)
                    retry_log_fun = self.logger.debug

            # Only sleep if we have another retry remaining
            if tries is None or tries > 1:
                self.logger.debug(
                    "[%s:%s] Not connected, sleeping for %.1fs. Services: %s",
                    self.fn or self.host, self.port,
                    self.retry_wait, self.services)
                time.sleep(self.retry_wait)

            if tries:
                tries -= 1

        self.stop.set()
        self.logger.error("[%s:%s] Failed to connect. No retries.",
                          self.fn or self.host, self.port)
        raise ChromecastConnectionError("Failed to connect")