"""
Downloads an iCal url or reads an iCal file.
"""
import logging

from httplib2 import Http


def apple_data_fix(content):
    """
    Fix Apple tzdata bug.

    :param content: content to fix
    :return: fixed content
    """
    return content.replace("TZOFFSETFROM:+5328", "TZOFFSETFROM:+0053")


def apple_url_fix(url):
    """
    Fix Apple URL.

    :param url: URL to fix
    :return: fixed URL
    """
    if url.startswith("webcal://"):
        url = url.replace("webcal://", "http://", 1)
    return url


class ICalDownload:
    """
    Downloads or reads and decodes iCal sources.
    """

    def __init__(self, http=None, encoding="utf-8"):
        # Get logger
        logger = logging.getLogger()

        # default http connection to use
        if http is None:
            try:
                http = Http(".cache")
            except (PermissionError, OSError) as e:
                # Cache disabled if no write permission in working directory
                logger.warning(
                    (
                        "Caching is disabled due to a read-only working directory: {}"
                    ).format(e)
                )
                http = Http()

        self.http = http
        self.encoding = encoding

    def data_from_url(self, url, apple_fix=False):
        """
        Download iCal data from URL.

        :param url: URL to download
        :param apple_fix: fix Apple bugs (protocol type and tzdata in iCal)
        :return: decoded (and fixed) iCal data
        """
        if apple_fix:
            url = apple_url_fix(url)

        _, content = self.http.request(url)

        if not content:
            raise ConnectionError("Could not get data from %s!" % url)

        return self.decode(content, apple_fix=apple_fix)

    def data_from_file(self, file, apple_fix=False):
        """
        Read iCal data from file.

        :param file: file to read
        :param apple_fix: fix wrong Apple tzdata in iCal
        :return: decoded (and fixed) iCal data
        """
        with open(file, mode="rb") as f:
            content = f.read()

        if not content:
            raise IOError("File %s is not readable or is empty!" % file)

        return self.decode(content, apple_fix=apple_fix)

    def data_from_string(self, string_content, apple_fix=False):
        if not string_content:
            raise IOError("String content is not readable or is empty!")

        return self.decode(string_content, apple_fix=apple_fix)

    def decode(self, content, apple_fix=False):
        """
        Decode content using the set charset.

        :param content: content do decode
        :param apple_fix: fix Apple txdata bug
        :return: decoded (and fixed) content
        """
        content = content.decode(self.encoding)
        content = content.replace("\r", "")

        if apple_fix:
            content = apple_data_fix(content)

        return content