from Acquisition import aq_inner
from logging import getLogger
from ploneintranet.docconv.client.interfaces import IFileWrapper
from ploneintranet.docconv.client.interfaces import IPreviewSettings
from ploneintranet.docconv.exc import SubProcessException
from Products.CMFCore.utils import getToolByName
from tempfile import TemporaryDirectory
from ZODB.blob import Blob

import errno
import os
import subprocess

logger = getLogger(__name__)
PDF_FILENAME = "dump.pdf"
TEXT_REL_PATHNAME = "text"


class DocType:
    def __init__(self, name, extensions, requires_conversion=True):
        self.name = name
        self.extensions = extensions
        self.requires_conversion = requires_conversion


CONVERTABLE_TYPES = {
    "pdf": DocType("PDF", ("pdf",), False),
    "word": DocType(
        "Word Document",
        ("doc", "docx", "dot", "wiz", "odt", "sxw", "wks", "wpd", "vor", "sdw"),
    ),
    "excel": DocType("Excel File", ("xls", "xlsx", "xlt", "ods", "csv")),
    "ppt": DocType("Powerpoint", ("ppt", "pptx", "pps", "ppa", "pwz", "odp", "sxi")),
    "html": DocType("HTML File", ("htm", "html", "xhtml")),
    "rft": DocType("RTF", ("rtf",)),
    "ps": DocType("PS Document", ("ps", "eps", "ai")),
    "photoshop": DocType("Photoshop", ("psd",)),
    "visio": DocType("Visio", ("vss", "vst", "vsw", "vsd")),
    "palm": DocType("Aportis Doc Palm", ("pdb",)),
    "txt": DocType("Plain Text File", ("txt",)),
    "image": DocType("Images", ("jpg", "jpeg", "png", "gif", "bmp", "tif", "tiff")),
}

EXTENSION_TO_ID_MAPPING = {}

for type_id, doc in CONVERTABLE_TYPES.items():
    for ext in doc.extensions:
        EXTENSION_TO_ID_MAPPING[ext] = type_id


def getDocumentType(obj):
    ct = ""
    if hasattr(obj, "portal_type") and obj.portal_type == "Document":
        ct = "text/html"
    elif hasattr(obj, "file") and obj.file is not None:
        ct = getattr(obj.file, "contentType")
    elif hasattr(obj, "image") and obj.image is not None:
        ct = getattr(obj.image, "contentType")

    if not ct:
        return

    mime_registry = getToolByName(obj, "mimetypes_registry")

    for _type in mime_registry.lookup(ct):
        for ext in _type.extensions:
            if ext in EXTENSION_TO_ID_MAPPING:
                id = EXTENSION_TO_ID_MAPPING[ext]
                if id in CONVERTABLE_TYPES:
                    return CONVERTABLE_TYPES[id]


def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as exc:
        if exc.errno == errno.EEXIST:
            pass
        else:
            raise


class BaseConverter:
    """
    A base class with helper methods used by both the pdf and the svg converter
    """

    def __init__(self, context):
        self.context = aq_inner(context)
        self.settings = IPreviewSettings(self.context)
        self.fw = IFileWrapper(self.context)
        self.blob = self.fw.blob

    def saveFileToBlob(self, filepath):
        blob = Blob()
        with open(filepath, "rb") as fi, blob.open("w") as bfile:
            bfile.write(fi.read())
        return blob

    def get_storage_dir(self):
        tmp_dir = TemporaryDirectory(prefix="quaive")
        logger.info("Initialised storage dir for %r: %r", self, tmp_dir)
        return tmp_dir

    def run(self, *args, **kwargs):
        raise NotImplementedError

    def __call__(self, *args, **kwargs):
        with self.get_storage_dir() as storage_dir:
            self.storage_dir = storage_dir
            return self.run(*args, **kwargs)


class BaseSubProcess:
    """
    This is a convenience class that finds a named binary in the environment
    and provides the _run_command method to execute this command using
    subprocess and does some logging. Nothing else.
    """

    def _run_command(self, cmd, env=None):
        if isinstance(cmd, str):
            cmd = cmd.split()

        cmdformatted = " ".join(map(str, cmd))
        logger.info("Running command: %s" % cmdformatted)
        process = subprocess.Popen(
            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, env=env
        )
        output, error = process.communicate()
        process.stdout.close()
        process.stderr.close()
        if process.returncode != 0:
            error = """Command
%s
finished with return code
%i
and output:
%s
%s""" % (
                cmdformatted,
                process.returncode,
                output,
                error,
            )
            logger.info(error)
            raise SubProcessException(error)
        logger.info("Finished Running Command %s" % cmdformatted)
        return output
