//! Allows to listen to runtime events.

use crate::Context;
use evm_runtime::{CreateScheme, Transfer};
use primitive_types::{H160, U256};

environmental::environmental!(listener: dyn EventListener + 'static);

pub trait EventListener {
    fn event(
        &mut self,
        event: Event
    );
}

#[derive(Debug, Copy, Clone)]
pub enum Event<'a> {
    Call {
        code_address: H160,
		transfer: &'a Option<Transfer>,
		input: &'a [u8],
		target_gas: Option<u64>,
		is_static: bool,
		context: &'a Context,
    },
    Create {
        caller: H160,
        address: H160,
		scheme: CreateScheme,
		value: U256,
		init_code: &'a [u8],
		target_gas: Option<u64>,
    },
    Suicide {
        address: H160,
		target: H160,
        balance: U256,
    },
}

impl<'a> Event<'a> {
    pub(crate) fn emit(self) {
        listener::with(|listener| listener.event(self));
    }
}

/// Run closure with provided listener.
pub fn using<R, F: FnOnce() -> R>(
    new: &mut (dyn EventListener + 'static),
    f: F
) -> R {
    listener::using(new, f)
}
