#include <allegro5/allegro.h>
#include <allegro5/allegro_acodec.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_ttf.h>
#include <stdio.h>
#include <stdlib.h>

#define notes_length (sizeof(notes) / sizeof(ALLEGRO_SAMPLE *))

#define say_center(w, h, text) \
        (al_draw_text(musicals, white, w, h, ALLEGRO_ALIGN_CENTRE, text)) 

#define play_note(i) \
        (al_play_sample( \
                 notes[i], \
                 1.0, 0.0, 1.0, \
                 ALLEGRO_PLAYMODE_ONCE, \
                 &sample_ids[i])) 

static const char abcdefga[] = "cdefgabc";

int main(int argc, char * argv[])
{
    char tmp[9] = "        ";
    int i = 0, l = -1;
    int playing[8] = {0};
    int status = 0;
    ALLEGRO_COLOR black, white;
    ALLEGRO_DISPLAY * display = NULL;
    ALLEGRO_EVENT_QUEUE * event_queue = NULL;
    ALLEGRO_FONT * musicals = NULL;
    ALLEGRO_SAMPLE * notes[8] = {0};
    ALLEGRO_SAMPLE_ID sample_ids[8] = {0};
    ALLEGRO_TIMEOUT timeout;

    if (!al_init()) {
        fprintf(stderr, "al_init failed\n");
        goto error;
    }

    if (!al_install_keyboard()) {
        fprintf(stderr, "al_install_keyboard failed\n");
        goto error;
    }

    if (!al_install_audio()) {
        fprintf(stderr, "al_install_audio failed\n");
        goto error;
    }

    if (!al_init_acodec_addon()) {
        fprintf(stderr, "al_init_acodec_addon failed\n");
        goto error;
    }

    if (!al_init_font_addon()) {
        fprintf(stderr, "al_init_font_addon failed\n");
        goto error;
    }

    if (!al_init_ttf_addon()) {
        fprintf(stderr, "al_init_ttf_addon failed\n");
        goto error;
    }

    display = al_create_display(1440, 900);

    if (display == NULL) {
        fprintf(stderr, "al_create_display failed\n");
        goto error;
    }

    event_queue = al_create_event_queue();

    if (event_queue == NULL) {
        fprintf(stderr, "al_create_event_queue failed\n");
        goto error;
    }

    if (!al_reserve_samples(7 * 7)) {
        fprintf(stderr, "al_reserve_samples failed\n");
        goto error;
    }

    for (i=0,l=notes_length; i<l; i++) {
        char filename[8][25] = {
           "media/Piano.ff.C3.ogg",
           "media/Piano.ff.D3.ogg",
           "media/Piano.ff.E3.ogg",
           "media/Piano.ff.F3.ogg",
           "media/Piano.ff.G3.ogg",
           "media/Piano.ff.A3.ogg",
           "media/Piano.ff.B3.ogg",
           "media/Piano.ff.C4.ogg"
        };
        notes[i] = al_load_sample(filename[i]);

        if (notes[i] == NULL) {
            fprintf(stderr, "al_load_sample %s failed\n", filename[i]);
            goto error;
        }
    }

    musicals = al_load_ttf_font("musicals.ttf", 72, 0);

    if (musicals == NULL) {
        fprintf(stderr, "al_load_ttf_font failed\n");
        goto error;
    }

    al_register_event_source(event_queue,
            al_get_display_event_source(display));

    al_register_event_source(event_queue,
            al_get_keyboard_event_source());

    black = al_map_rgb(0, 0, 0);
    white = al_map_rgb(255, 255, 255);

    al_init_timeout(&timeout, 0.06);

    while (1) {
        int w = al_get_display_width(display);
        int h = al_get_display_height(display);
        ALLEGRO_EVENT ev;

        if (al_wait_for_event_until(event_queue, &ev, &timeout)) {
            switch (ev.type) {
                case ALLEGRO_EVENT_DISPLAY_CLOSE:
                    goto clean;
                    break;
                case ALLEGRO_EVENT_KEY_DOWN:
                    if (ev.keyboard.keycode >= ALLEGRO_KEY_1 &&
                            ev.keyboard.keycode <= ALLEGRO_KEY_8) {
                        i = ev.keyboard.keycode - ALLEGRO_KEY_1;
                        tmp[i] = abcdefga[i];

                        if (playing[i] == 0) {
                            playing[i] = play_note(i);
                        }
                    } else {
                        switch (ev.keyboard.keycode) {
                            case ALLEGRO_KEY_ESCAPE:
                            case ALLEGRO_KEY_Q:
                                goto clean;
                        }
                    }

                    break;
                case ALLEGRO_EVENT_KEY_UP:
                    if (ev.keyboard.keycode >= ALLEGRO_KEY_1 &&
                            ev.keyboard.keycode <= ALLEGRO_KEY_8) {
                        i = ev.keyboard.keycode - ALLEGRO_KEY_1;
                        tmp[i] = ' ';

                        if (playing[i] != 0) {
                            al_stop_sample(&sample_ids[i]);
                            playing[i] = 0;
                        }
                    }
                    break;
            }
        }

        al_clear_to_color(black);

        say_center(w / 2.0, h / 2.0, "abcdefg ABCDEFG");
        say_center(w / 2.0, h / 2.0 + 100, tmp);

        al_flip_display();
    }

clean:
    for (i=0,l=notes_length; i<l; i++) {
        if (notes[i]) al_destroy_sample(notes[i]);
    }
    if (musicals) al_destroy_font(musicals);
    if (event_queue) al_destroy_event_queue(event_queue);
    if (display) al_destroy_display(display);

    return status;

error:
    status = 1;
    goto clean;
}
