"""Class exercises"""
from email.parser import Parser
# Some versions of Anaconda python are missing IMAP4_SSL.
# So we want to trap and ignore that error for that very rare case.
try:
    from imaplib import IMAP4_SSL
except ImportError:
    pass


class BankAccount:
    """Bank account including an account balance."""


class Flavor:
    """Flavor of ice cream."""


class Size:
    """Ice cream size."""


class IceCream:
    """Ice cream to be ordered in our ice cream shop."""


class Month:
    """Class representing an entire month."""


class Row:
    """Row class that stores all given arguments as attributes."""


class MinimumBalanceAccount:
    """Bank account which does not allow balance to drop below zero."""


class IMAPChecker:
    """Facilitate connection to IMAP server."""

# Refactor the below functions into IMAPChecker methods


def get_connection(host, username, password):
    """Initialize IMAP server and login"""
    server = IMAP4_SSL(host)
    server.login(username, password)
    server.select("inbox")
    return server


def close_connection(server):
    server.close()
    server.logout()


def get_message_uids(server):
    """Return unique identifiers for each message"""
    return server.uid("search", None, "ALL")[1][0].split()


def get_message(server, uid):
    """Get email message identified by given UID"""
    result, data = server.uid("fetch", uid, "(RFC822)")
    (_, message_text), _ = data
    message = Parser().parsestr(message_text)
    return message


class Node:

    """Nodes for use in making hierarchies or trees."""

    def __init__(self, name, *, ancestors=[]):
        self.ancestors = list(ancestors)
        self.name = name

    def ancestors_and_self(self):
        """Return iterable with our ordered ancestors and our own node."""
        return [*self.ancestors, self]

    def make_child(self, *args, **kwargs):
        """Create and return a child node of the current node."""
        return type(self)(*args, ancestors=self.ancestors_and_self(), **kwargs)

    def __str__(self):
        """Return a slash-delimited ancestors hierarchy for this node."""
        return " / ".join([
            node.name
            for node in [*self.ancestors, self]
        ])

    def __repr__(self):
        return self.name


class DoublyLinkedNode:
    """Class with Nodes that are doubly-linked"""


class AlphaString:
    """Class that only allows alphabetic strings."""


class MaxCounter:
    """Counter-like class that allows retrieving all maximums."""


class LastUpdatedDictionary:

    """Dictionary that maintains last-updated order of items."""


class OrderedCounter:

    """Counter that maintains last-updated item order."""
