from flow.commands.base import CommandBase
from flow.petri.safenet import Token, SetTokenMessage
from tempfile import NamedTemporaryFile
import flow.redisom as rom
import json
import subprocess
import os

import logging

LOG = logging.getLogger(__name__)


class WrapperCommand(CommandBase):
    default_logging_mode = 'debug'

    def __init__(self, broker=None, storage=None, routing_key=None, exchange=None):
        self.broker = broker
        self.storage = storage
        self.routing_key = routing_key
        self.exchange = exchange


    @staticmethod
    def annotate_parser(parser):
        parser.add_argument('--net-key', '-n')
        parser.add_argument('--running-place-id', '-r', type=int)
        parser.add_argument('--success-place-id', '-s', type=int)
        parser.add_argument('--failure-place-id', '-f', type=int)
        parser.add_argument('--with-inputs', default=None, type=str)
        parser.add_argument('--with-outputs', default=False,
                action="store_true")

        parser.add_argument('command_line', nargs='+')

    def __call__(self, parsed_arguments):
        self.send_token(net_key=parsed_arguments.net_key,
                place_idx=parsed_arguments.running_place_id,
                data={"pid": str(os.getpid())})

        rv = 1
        cmdline = parsed_arguments.command_line

        with NamedTemporaryFile() as inputs_file:
            with NamedTemporaryFile() as outputs_file:
                if parsed_arguments.with_inputs:
                    inputs_hash = rom.Hash(
                            connection=self.storage,
                            key=parsed_arguments.with_inputs,
                            value_decoder=rom.json_dec,
                            value_encoder=rom.json_enc)

                    inputs = inputs_hash.value

                    LOG.debug("Fetched inputs from key %s" %
                            parsed_arguments.with_inputs)
                    LOG.debug("Input values: %r" % inputs)

                    json.dump(inputs, inputs_file)
                    inputs_file.flush()
                    cmdline += ["--inputs-file", inputs_file.name]
                else:
                    LOG.debug("No inputs for command")

                if parsed_arguments.with_outputs:
                    cmdline += ["--outputs-file", outputs_file.name]

                try:
                    subprocess.check_call(cmdline)

                    outputs = None
                    if parsed_arguments.with_outputs:
                        outputs = json.load(outputs_file)

                    self.send_token(net_key=parsed_arguments.net_key,
                            place_idx=parsed_arguments.success_place_id,
                            data={"exit_code": 0, "outputs": outputs})

                    rv = 0
                except subprocess.CalledProcessError as e:
                    LOG.error("Failed to execute command '%s': %s",
                            " ".join(cmdline), str(e))
                    self.send_token(net_key=parsed_arguments.net_key,
                            place_idx=parsed_arguments.failure_place_id,
                            data={"exit_code": e.returncode})

                    rv = e.returncode

        return rv

    def send_token(self, net_key=None, place_idx=None, data=None):
        self.broker.connect()
        token = Token.create(self.storage, data=data, data_type="output")

        LOG.info("Sending command response token %s to net %s, place %r",
                token.key, net_key, place_idx)
        message = SetTokenMessage(net_key=net_key, place_idx=place_idx,
                token_key=token.key)
        self.broker.publish(exchange_name=self.exchange, routing_key=self.routing_key,
                message=message)
        self.broker.disconnect()

@@ -196,16 +196,32 @@
 mport os
+%0Aimport platform
 %0A%0Aimport
@@ -2358,16 +2358,130 @@
 .name%5D%0A%0A
+                LOG.info(%22On host %25s: executing %25s%22, platform.node(),%0A                        %22 %22.join(cmdline))%0A%0A
         

add log message including hostname to wrapper