__version__ = "0.1"

from meshroom.core import desc
from meshroom.core.utils import VERBOSE_LEVEL
from pathlib import Path

import distutils.dir_util as du
import shutil
import glob
import os
import subprocess


class ExtractMetadata(desc.Node):
    size = desc.DynamicNodeSize("input")

    category = "Utils"
    documentation = """
Using exifTool, this node extracts the metadata of all images referenced in a SfMData and store them in appropriate files.
"""

    inputs = [
        desc.File(
            name="input",
            label="Input",
            description="SfMData input file.",
            value="",
        ),
        desc.BoolParam(
            name="keepFilename",
            label="Keep Filename",
            description="Keep the filename of the inputs for the outputs.",
            value=False,
        ),
        desc.ChoiceParam(
            name="extension",
            label="Output File Extension",
            description="Metadata file extension.",
            value="txt",
            values=["txt", "xml", "xmp"],
            exclusive=True,
        ),
        desc.StringParam(
            name="arguments",
            label="Arguments",
            description="ExifTool command arguments.",
            value="",
        ),
        desc.BoolParam(
            name="insertInSfm",
            label="Update SfMData",
            description="Insert the extracted metadata in the SfMData file.",
            value=False,
        ),
        desc.ChoiceParam(
            name="verboseLevel",
            label="Verbose Level",
            description="Verbosity level (fatal, error, warning, info, debug, trace).",
            values=VERBOSE_LEVEL,
            value="info",
        ),
    ]

    outputs = [
        desc.File(
            name="output",
            label="Result Folder",
            description="Output path for the resulting metadata files.",
            value="{nodeCacheFolder}",
        ),
    ]

    def processChunk(self, chunk):
        import pyalicevision as av
        try:
            chunk.logManager.start(chunk.node.verboseLevel.value)
            
            if chunk.node.input.value == "" or chunk.node.input.value[-4:].lower() != '.sfm':
                error = 'This node need to have a sfmData connected as input.'
                chunk.logger.error(error)
                raise RuntimeError(error)

            if not os.path.exists(chunk.node.output.value):
                os.mkdir(chunk.node.output.value)

            dataAV = av.sfmData.SfMData()
            if av.sfmDataIO.load(dataAV, chunk.node.input.value, av.sfmDataIO.ALL):
                views = dataAV.getViews()
                for id, v in views.items():
                    inputFile = v.getImage().getImagePath()
                    chunk.logger.info(f"Processing {inputFile}")

                    if chunk.node.keepFilename.value:
                        outputMetadataFilename = os.path.join(chunk.node.output.value, Path(inputFile).stem + "." + chunk.node.extension.value)
                    else:
                        outputMetadataFilename = os.path.join(chunk.node.output.value, str(id) + "." + chunk.node.extension.value)

                    if chunk.node.extension.value == 'txt':
                        cmd = 'exiftool ' + chunk.node.arguments.value.strip() + ' ' + inputFile + ' > ' + outputMetadataFilename
                    elif chunk.node.extension.value == 'xml':
                        cmd = 'exiftool -X ' + chunk.node.arguments.value.strip() + ' ' + inputFile + ' > ' + outputMetadataFilename
                    else: #xmp
                        cmd = 'exiftool -tagsfromfile ' + inputFile + ' ' + chunk.node.arguments.value.strip() + ' ' + outputMetadataFilename

                    chunk.logger.debug(cmd)
                    error = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stderr.read().decode()

                    chunk.logger.debug(error)
                    
                    if error != "":
                        chunk.logger.error(error)
                        raise RuntimeError(error)
                    if not os.path.exists(outputMetadataFilename):
                        info = 'No metadata extracted for file ' + inputFile
                        chunk.logger.info(info)
                    elif chunk.node.insertInSfm.value:
                        cmd = 'exiftool ' + chunk.node.arguments.value.strip() + ' ' + inputFile
                        metadata = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.read().decode()
                        chunk.logger.debug(metadata)
                        lmeta = metadata.split('\n')
                        for i in range(1, len(lmeta)-1):
                            l = lmeta[i].split(':', 1)
                            v.getImageInfo().addMetadata('ExifTool:'+l[0].strip(), l[1].strip())

                if chunk.node.insertInSfm.value:
                    outputSfm = os.path.join(chunk.node.output.value, Path(chunk.node.input.value).stem + ".sfm")
                    av.sfmDataIO.save(dataAV, outputSfm, av.sfmDataIO.ALL)

                chunk.logger.info('Metadata extraction end')
            
        finally:
            chunk.logManager.end()
