"""Exported method Container.attach()."""

from __future__ import absolute_import

import collections
import fcntl
import logging
import struct
import sys
import termios


class Mixin:
    """Publish attach() for inclusion in Container class."""

    def attach(self, eot=4, stdin=None, stdout=None):
        """Attach to container's PID1 stdin and stdout.

        stderr is ignored.
        PseudoTTY work is done in start().
        """
        if stdin is None:
            stdin = sys.stdin.fileno()
        elif hasattr(stdin, 'fileno'):
            stdin = stdin.fileno()

        if stdout is None:
            stdout = sys.stdout.fileno()
        elif hasattr(stdout, 'fileno'):
            stdout = stdout.fileno()

        with self._client() as podman:
            attach = podman.GetAttachSockets(self._id)

        # This is the UDS where all the IO goes
        io_socket = attach['sockets']['io_socket']
        assert len(io_socket) <= 107,\
            'Path length for sockets too long. {} > 107'.format(
                len(io_socket)
            )

        # This is the control socket where resizing events are sent to conmon
        # attach['sockets']['control_socket']
        self.pseudo_tty = collections.namedtuple(
            'PseudoTTY',
            ['stdin', 'stdout', 'io_socket', 'control_socket', 'eot'])(
                stdin,
                stdout,
                attach['sockets']['io_socket'],
                attach['sockets']['control_socket'],
                eot,
            )

    @property
    def resize_handler(self):
        """Send the new window size to conmon."""

        def wrapped(signum, frame):  # pylint: disable=unused-argument
            packed = fcntl.ioctl(self.pseudo_tty.stdout, termios.TIOCGWINSZ,
                                 struct.pack('HHHH', 0, 0, 0, 0))
            rows, cols, _, _ = struct.unpack('HHHH', packed)
            logging.debug('Resize window(%dx%d) using %s', rows, cols,
                          self.pseudo_tty.control_socket)

            # TODO: Need some kind of timeout in case pipe is blocked
            with open(self.pseudo_tty.control_socket, 'w') as skt:
                # send conmon window resize message
                skt.write('1 {} {}\n'.format(rows, cols))

        return wrapped

    @property
    def log_handler(self):
        """Send command to reopen log to conmon."""

        def wrapped(signum, frame):  # pylint: disable=unused-argument
            with open(self.pseudo_tty.control_socket, 'w') as skt:
                # send conmon reopen log message
                skt.write('2\n')

        return wrapped
