import sys
import shutil

import py
import subprocess
from pypy.config.config import Config
from pypy.translator.oosupport.genoo import GenOO
from pypy.translator.cli import conftest
from pypy.translator.cli.ilgenerator import IlasmGenerator
from pypy.translator.cli.function import Function, log
from pypy.translator.cli.class_ import Class
from pypy.translator.cli.option import getoption
from pypy.translator.cli.database import LowLevelDatabase
from pypy.translator.cli.cts import CTS
from pypy.translator.cli.opcodes import opcodes
from pypy.translator.cli.sdk import SDK
from pypy.translator.cli.rte import get_pypy_dll
from pypy.translator.cli.support import Tee
from pypy.translator.cli.prebuiltnodes import get_prebuilt_nodes
from pypy.translator.cli import constant

class GenCli(GenOO):
    TypeSystem = CTS
    Function = Function
    opcodes = opcodes
    Database = LowLevelDatabase
    log = log
    
    ConstantGenerator = constant.CLIConstantGenerator
    InstanceConst = constant.CLIInstanceConst
    RecordConst = constant.CLIRecordConst
    ClassConst = constant.CLIClassConst
    ListConst = constant.CLIListConst
    ArrayConst = constant.CLIArrayConst
    StaticMethodConst = constant.CLIStaticMethodConst
    CustomDictConst = constant.CLICustomDictConst
    DictConst = constant.CLIDictConst
    WeakRefConst = constant.CLIWeakRefConst

    def __init__(self, tmpdir, translator, entrypoint, config=None, exctrans=False):
        GenOO.__init__(self, tmpdir, translator, entrypoint, config, exctrans)
        self.assembly_name = entrypoint.get_name()
        self.tmpfile = tmpdir.join(self.assembly_name + '.il')
        self.const_stat = str(tmpdir.join('const_stat'))
        rtyper = translator.rtyper
        bk = rtyper.annotator.bookkeeper
        clsdef = bk.getuniqueclassdef(Exception)
        ll_Exception = rtyper.exceptiondata.get_standard_ll_exc_instance(rtyper, clsdef)
        self.EXCEPTION = ll_Exception._inst._TYPE

    def append_prebuilt_nodes(self):
        for node in get_prebuilt_nodes(self.translator, self.db):
            self.db.pending_node(node)

    def generate_source(self):
        GenOO.generate_source(self)
        self.db.const_count.dump(self.const_stat)
        return self.tmpfile.strpath

    def create_assembler(self):
        out = self.tmpfile.open('w')
        if getoption('stdout'):
            out = Tee(sys.stdout, out)
        isnetmodule = self.entrypoint.isnetmodule
        return IlasmGenerator(out, self.assembly_name, self.config, isnetmodule)

    def build_exe(self):        
        if getoption('source'):
            return None

        pypy_dll = get_pypy_dll() # get or recompile pypy.dll
        shutil.copy(pypy_dll, self.tmpdir.strpath)

        ilasm = SDK.ilasm()
        tmpfile = self.tmpfile.strpath
        self.outfile = self.entrypoint.output_filename(tmpfile)
        argv = [tmpfile,'/output:' + self.outfile] + self.entrypoint.ilasm_flags()
        self._exec_helper(ilasm, argv,
                          'ilasm failed to assemble (%s):\n%s\n%s',
                          timeout = 900)
        # Mono's ilasm occasionally deadlocks.  We set a timer to avoid
        # blocking automated test runs forever.


        if getoption('verify'):
            peverify = SDK.peverify()
            self._exec_helper(peverify, [outfile], 'peverify failed to verify (%s):\n%s\n%s')
        return self.outfile

    def _exec_helper(self, helper, args, msg, timeout=None):
        args = [helper] + args
        if timeout and not sys.platform.startswith('win'):
            import os
            from pypy.tool import autopath
            watchdog = os.path.join(autopath.pypydir, 'tool', 'watchdog.py')
            args[:0] = [sys.executable, watchdog, str(float(timeout))]
        proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        retval = proc.wait()
        assert retval == 0, msg % (args[0], stdout, stderr)
        
