#!python
# -*- coding: utf-8 -*-

"""
@authors Reda Drissi <mohamed-reda.drissi@atos.net>
@internal
@copyright 2017-2019  Bull S.A.S.  -  All rights reserved.
           This is not Free or Open Source software.
           Please contact Bull SAS for details about its license.
           Bull - Rue Jean Jaurès - B.P. 68 - 78340 Les Clayes-sous-Bois

@file qat-interop/packaged/bin/oqasm2circ
@brief An OpenQASM compiler in python

Description Command line tool for compiling Openqasm circuits into
            QLM circuits
"""

import importlib
import os

from argparse import ArgumentParser

from qat.interop.openqasm.qasm_parser import OqasmParser, extract_inc
from qat.lang.AQASM.misc import generate_gate_set
try:
    from qat.lang.linking.linker import Linker
    from qat.lang.linking.util import inline_gates
except ImportError:
    from qat.core.linker import GenericInstantiator
    from qat.core.circ import writecirc


class UnknownModule(Exception):
    """ Raised when some unknown python module is linked to the compiler """

    def __init__(self, mod_name):
        super(UnknownModule, self).__init__()
        self.name = mod_name


def __str__(self):
    return ("Can't load module '{}'\nMaybe check your " + "$PYTHONPATH?").format(
        self.name
    )


def main():
    parser = ArgumentParser(
        description="Compiles an OQASM file into" " a circuit file."
    )

    parser.add_argument(
        "input",
        type=str,
        metavar="OQASM_FILE",
        help="Filename containning the OPENQASM" " circuit to be compiled",
    )

    parser.add_argument(
        "output",
        type=str,
        default=None,
        nargs="?",
        metavar="OUTFILE",
        help="Output file receiving the compiled circuit",
    )

    parser.add_argument('--full-matrices',
                        action='store_true',
                        dest="full_matrices",
                        help="Tells the compiler to generate and include"
                             " the full matrices of each gate. Notice that this can"
                             " lead to larger .circ files and longer compilation time.")

    args = parser.parse_args()

    fname = args.input
    output = args.output
    if output is None:
        output = os.path.splitext(fname)[0] + ".circ"
    aq_parser = OqasmParser()
    aq_parser.build(debug=False)

    # Parsing the file and running the compiler
    # print(extract_inc(fname))
    res = aq_parser.parse(extract_inc(fname), debug=False)
    if res == 1:
        # Generating the circuit from the compiler
        circ = aq_parser.compiler.gen_circuit()
        global_gate_set = aq_parser.compiler.gate_set

        try:
            # Linking the various lib calls
            linker = Linker(gate_set=global_gate_set,
                            include_matrices=args.full_matrices)
            linker.link(circ)
            # Inlining the linked gates
            inline_gates(circ)
            circ.dump(output)
        except NameError:
            instantiator = GenericInstantiator()
            instantiator.instantiate(circ, global_gate_set)
            if args.full_matrices is True:
                instantiator.fill_matrices(circ, global_gate_set)
            writecirc(circ, output)



if __name__ == "__main__":
    main()
