# Copyright 2016 by Raytheon BBN Technologies Corp.  All Rights Reserved.

import ast
import os
import sys

from copy import deepcopy

from pyqgl2.ast_qgl2 import is_concur, is_seq
from pyqgl2.ast_util import ast2str, NodeError
from pyqgl2.find_channels import find_all_channels


class SingleSequence(object):
    """
    Create a sequence list for a single QBIT

    Note: this assumes that the AST is for one function
    definition that has already been inlined, successfully
    flattened, grouped, and sequenced already.
    """

    def __init__(self, importer):

        self.importer = importer

        self.qbits = set()
        self.qbit_creates = list()
        self.sequences = dict() # From channel to list of pulses

        # the imports we need to make in order to satisfy the stubs
        #
        # the key is the name of the module (i.e. something like
        # 'QGL.PulsePrimitives') and the values are sets of import
        # clauses (i.e. 'foo' or 'foo as bar')
        #
        self.stub_imports = dict()

    def find_imports(self, node):

        default_namespace = node.qgl_fname

        for subnode in ast.walk(node):
            if (isinstance(subnode, ast.Call) and
                    isinstance(subnode.func, ast.Name)):
                funcname = subnode.func.id

                # If we created a node without an qgl_fname,
                # then use the default namespace instead.
                # FIXME: This is a hack, but it will work for now.
                #
                if not hasattr(subnode, 'qgl_fname'):
                    namespace = default_namespace
                else:
                    namespace = subnode.qgl_fname

                fdef = self.importer.resolve_sym(namespace, funcname)
                if not fdef:
                    print('ERROR %s funcname' % funcname)
                    NodeError.error_msg(subnode,
                            'cannot find import info for [%s]' % funcname)
                elif not fdef.qgl_stub_import:
                    NodeError.error_msg(subnode,
                            'not a stub: [%s]' % funcname)
                else:
                    # print('FI AST %s' % ast.dump(fdef))
                    (sym_name, module_name, orig_name) = fdef.qgl_stub_import

                    if orig_name:
                        import_str = '%s as %s' % (orig_name, sym_name)
                    else:
                        import_str = sym_name

                    if module_name not in self.stub_imports:
                        self.stub_imports[module_name] = set()

                    self.stub_imports[module_name].add(import_str)

        return True

    def create_imports_list(self):

        import_list = list()

        for module_name in sorted(self.stub_imports.keys()):
            for sym_name in sorted(self.stub_imports[module_name]):
                import_list.append(
                        'from %s import %s' % (module_name, sym_name))

        return import_list

    def find_sequence(self, node):

        if not isinstance(node, ast.FunctionDef):
            NodeError.fatal_msg(node, 'not a function definition')
            return False

        self.qbits = find_all_channels(node)

        if len(self.qbits) == 0:
            NodeError.error_msg(node, 'no channels found')
            return False
        else:
            NodeError.diag_msg(node, "Found channels %s" % self.qbits)

        lineNo = -1