#[macro_use]
extern crate hlua;

fn main() 


// this `Sound` struct is the object that we will use to demonstrate hlua
struct Sound {
    playing: bool,
}

// this macro implements the required trait so that we can *push* the object to lua
// (ie. move it inside lua)
implement_lua_push!(Sound, |mut metatable| {
    // we create a `__index` entry in the metatable
    // when the lua code calls `sound:play()`, it will look for `play` in there
    let mut index = metatable.empty_array("__index");

    index.set("play", hlua::function1(|snd: &mut Sound| {
        snd.play()
    }));

    index.set("stop", hlua::function1(|snd: &mut Sound| {
        snd.stop()
    }));

    index.set("is_playing", hlua::function1(|snd: &Sound| {
        snd.is_playing()
    }));
});

// this macro implements the require traits so that we can *read* the object back
implement_lua_read!(Sound);

impl Sound {
    pub fn new() -> Sound {
        Sound {
            playing: false
        }
    }

    pub fn play(&mut self) {
        println!("playing");
        self.playing = true;
    }

    pub fn stop(&mut self) {
        println!("stopping");
        self.playing = false;
    }

    pub fn is_playing(&self) -> bool {
        self.playing
    }
}

// this destructor is here to show you that objects are properly getting destroyed
impl Drop for Sound {
    fn drop(&mut self) {
        println!("`Sound` object destroyed");
    }
}

{
    let mut lua = hlua::Lua::new();
    lua.openlibs();

    // we create a fill an array named `Sound` which will be used as a class-like interface
    {
        let mut sound_namespace = lua.empty_array("Sound");

        // creating the `Sound.new` function
        sound_namespace.set("new", hlua::function0(|| Sound::new()));
    }

    lua.execute::<()>(r#"
        s = Sound.new();
        s:play();

        print("hello world from within lua!");
        print("is the sound playing:", s:is_playing());

        s:stop();
        print("is the sound playing:", s:is_playing());

    "#).unwrap();
}