#!/usr/bin/env python
# Copyright 2018 Digital Domain 3.0
#
# Licensed under the Apache License, Version 2.0 (the "Apache License")
# with the following modification; you may not use this file except in
# compliance with the Apache License and the following modification to it:
# Section 6. Trademarks. is deleted and replaced with:
#
# 6. Trademarks. This License does not grant permission to use the trade
#    names, trademarks, service marks, or product names of the Licensor
#    and its affiliates, except as required to comply with Section 4(c) of
#    the License and to reproduce the content of the NOTICE file.
#
# You may obtain a copy of the Apache License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Apache License with the above modification is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
import argparse
import contextlib
from cStringIO import StringIO
import os
import subprocess
import sys


import qt_py_convert.run
import qt_py_convert.general


PYQT4 = "PyQt4"
PYQt5 = "PyQt5"
PYSIDE = "PySide"
PYSIDE2 = "PySide2"
PyUIC4 = "pyuic4"
PyRCC4 = "pyrcc4"
PyUIC5 = "pyuic5"
PyRCC5 = "pyrcc5"
PySideUIC = "pyside-uic"
PySideRCC = "pyside-rcc"
PySide2UIC = "pyside2-uic"
PySide2RCC = "pyside2-rcc"

QRESOURCE_ENVIRON = "QRESOURCE_CONVERTER_DEFAULT"

mappings = {
    PYQT4: (PyUIC4, PyRCC4),
    PYQt5: (PyUIC5, PyRCC5),
    PYSIDE: (PySideUIC, PySideRCC),
    PYSIDE2: (PySide2UIC, PySide2RCC),
}


class UICConversionError(ValueError):
    """If we were unable to convert the uic into a python file."""


def _is_uic(path):
    if os.path.splitext(path)[-1] in (".ui", ".uic"):
        return True
    return False


def execute_convert(application, path, output=None):
    if application is None:
        # Query Environ.
        application = os.environ.get(QRESOURCE_ENVIRON, PYQT4)

    uic, rcc = mappings[application]

    if _is_uic(path):
        binary = uic
    else:
        binary = rcc

    command = [binary, path]
    if output:
        command.extend(["-o", output])
    proc = subprocess.Popen(
        command,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
    )
    out, err = proc.communicate()
    has_errors = False

    if output:
        message = output
    else:
        message = out

    if proc.returncode:
        has_errors = True
        return has_errors, err, message
    else:
        return has_errors, None, message


@contextlib.contextmanager
def stdout_redirector():
    stdout, stderr = sys.stdout, sys.stderr
    out = StringIO()
    err = StringIO()
    sys.stdout = out
    sys.stderr = err
    yield
    sys.stdout = stdout
    sys.stderr = stderr


def parse_args():
    parser = argparse.ArgumentParser(
        "qresource_convert"
    )

    parser.add_argument(
        "-c", "--converter",
        action="store",
        choices=tuple(mappings.keys()),
        default=None,
        dest="converter"
    )
    parser.add_argument(
        "file",
        help="Pass explicit files or a directories to run.",
    )
    parser.add_argument(
        "-o",
        required=False,
        help="Filepath to write results to."
    )
    args = parser.parse_args()
    return args


def main():
    args = parse_args()
    has_errors, errors, message = execute_convert(
        args.converter, args.file, output=args.o
    )

    if has_errors:
        raise UICConversionError(errors)

    if not args.o:
        with stdout_redirector():
            # In memory
            _, _, output = qt_py_convert.run.run(
                message, skip_lineno=True, tometh_flag=True
            )
    else:
        with stdout_redirector():
            qt_py_convert.run.process_file(
                message,
                write_mode=qt_py_convert.general.WriteFlag.WRITE_TO_FILE,
                skip_lineno=True,
                tometh_flag=True
            )
            output = message

    sys.stdout.write(output)


if __name__ == "__main__":
    main()
