#ifdef CPC
    #include <cpctelera.h>
    #include "Interrupt.h"
#elif ALLEGRO4
    #include <allegro.h>
    #include <stdio.h>
#else
    #include <allegro5/allegro.h>
    #include <allegro5/allegro_font.h>
    #include <allegro5/allegro_primitives.h>
    #include <allegro5/allegro_ttf.h>
    #include <stdio.h>
#endif

#include "Config.h"
#include "GameTypes.h"
#include "Menu.h"
#include "Palette.h"

#ifdef ALLEGRO5

// The ALLEGRO_DISPLAY representing the content of the screen.
ALLEGRO_DISPLAY* display_ = NULL;

#endif

#ifdef CPC
void main(void)
#else
int main()
#endif
{
#ifdef CPC

    // Disable the firmware to prevent it from interfering with setVideoMode.
    cpct_disableFirmware();

    // Set video mode to mode 0.
    cpct_setVideoMode(0);

    // Setup interrupt handler for keyboard scanning.
    cpct_setInterruptHandler(interruptHandler);

    // Runm the menu which will loop forever.
    runMenu();

#elif ALLEGRO4

    u8 configPath[260];
    u8 gfxMode = 0;
    u16 screenWidth = 0;
    u16 screenHeight = 0;
    const u8* fontPath;

    if (allegro_init())
    {
        fprintf(stderr, "Failed to initialise allegro 4\n");
        return -1;
    }
    else
    {
        printf("Initialised allegro 4\n");
    }

    if (locateConfigPath("game.cfg", configPath))
    {
        fprintf(stderr, "Failed to locate game.cfg\n");
        return -2;
    }
    else
    {
        printf("Located game.cfg from: %s\n", configPath);
    }

    // Configuration file used for all configuration operations.
    set_config_file((const char*)configPath);

    install_keyboard();

    screenWidth = get_config_int(NULL, "display_width", 0);
    screenHeight = get_config_int(NULL, "display_height", 0);

    // With default scaling the minimal screen size is 640x400.
    if (screenWidth < 320)
    {
        screenWidth = 320;
    }

    if (screenHeight < 200)
    {
        screenHeight = 200;
    }

    printf("Screen height: %i\n", screenHeight); 
    printf("Screen width: %i\n", screenWidth);

#ifdef DJGPP
    // Windowed mode will always fail under DOS.
    set_gfx_mode(GFX_AUTODETECT, 320, 200, 0, 0);
#else
    // Needs to be 16bit for orange to display correctly 
    // Setting this on a real dos machine will cause an application crash.
    set_color_depth(16);

    // Read the graphics mode from the config file.
    gfxMode = get_config_int(NULL, "a4_gfx_mode", 2);
    set_gfx_mode(GFX_AUTODETECT_WINDOWED, 960, 600, 0, 0);
#endif

    // Load the PCX font.
    fontPath = get_config_string(NULL, "pcx_font", 0);

    if (initFonts(fontPath))
    {
        if (fontPath == NULL)
        {
            fprintf(stderr, "Failed to initialise font from: %s\n", "NULL");
        }
        else
        {
            fprintf(stderr, "Failed to initialise font from: %s\n", fontPath);
        }

        return -3;
    }
    else
    {
        printf("Initialised font from: %s\n", fontPath);
    }


    // Calculate the scale factor which will determine what multiple of 16 to use for sprites.
    scaleFactor = calculateScaleFactor(screenWidth, screenHeight);

    printf("Scale factor: %i\n", scaleFactor);

    // Read transparency value from config.
    transparencyType = get_config_int(NULL, "transparency", 0);
    printf("Transparency type: %i\n", transparencyType);

    if (transparencyType == 1)
    {
        // Updates the outside of sprites to HW_WHITE (grey) to emulate transparency.
        gamePalette[4] = HW_WHITE;
        initialPalette[4] = HW_WHITE;
    }
    else if (transparencyType == 2)
    {
        // Colour depth must be 16bit for this to work.
        set_color_depth(16);

        // Updated the outside of sprites to bright magenta to turn them transparent.
        gamePalette[4] = HW_BRIGHT_MAGENTA;
        initialPalette[4] = HW_BRIGHT_MAGENTA;
    }

    printf("Initialising allegro sprite sets...");

    // Initialise the sprite sets used by allegro.
    initAllAllegroSpriteSets(gamePalette, transparencyType);

    printf("done\n");

    // Runs the game menu including menu loop.
    runMenu();

    // Destroy the sprite sets used by allegro.
    destroyAllAllegroSpriteSets();

#else

    ALLEGRO_PATH* configPath = locateConfigPath("game.cfg");
    ALLEGRO_CONFIG* config = NULL;
    u16 screenWidth = 0;
    u16 screenHeight = 0;
    const u8* fontPath;

    if (configPath == NULL)
    {
        fprintf(stderr, "Failed to locate game.cfg\n");
        return -1;
    }
    else
    {
#ifdef _WIN32
        printf("Located game.cfg from: %s\n", al_path_cstr(configPath, '\\'));
#else
        printf("Located game.cfg at %s\n", al_path_cstr(configPath, '/'));
#endif
    }

    config = al_load_config_file(al_path_cstr(configPath, '/'));

    if (!al_init())
    {
        fprintf(stderr, "Failed to initialise allegro 5\n");

        return -2;
    }
    else
    {
        printf("Initialised allegro 5\n");
    }

    if (!al_init_font_addon())
    {
        fprintf(stderr, "Failed to initialise font addon\n");

        return -3;
    }
    else
    {
        printf("Initialised allegro font addon\n");
    }

    if (!al_init_ttf_addon())
    {
        fprintf(stderr, "Failed to initialise ttf addon\n");

        return -4;
    }
    else
    {
        printf("Initialised allegro ttf addon\n");
    }

    if (!al_init_primitives_addon())
    {
        fprintf(stderr, "failed to initialise primitives addon\n");

        return -5;
    }
    else
    {
        printf("Initialised allegro primitives addon\n");
    }

    screenWidth = atoi(al_get_config_value(config, "", "display_width"));
    screenHeight = atoi(al_get_config_value(config, "", "display_height"));

    // With default scaling the minimal screen size is 640x400.
    if (screenWidth < 640)
    {
        screenWidth = 640;
    }

    if (screenHeight < 400)
    {
        screenHeight = 400;
    }

    printf("Screen height: %i\n", screenHeight); 
    printf("Screen width: %i\n", screenWidth);

    display_ = al_create_display(screenWidth, screenHeight);

    if (!display_)
    {
        fprintf(stderr, "Failed to create display\n");

        return -3;
    }
    else
    {
        printf("Created display\n");
    }

    fontPath = al_get_config_value(config, "", "font");

    if (initFonts(fontPath))
    {
        fprintf(stderr, "Failed to initialise font from: %s\n", fontPath);

        return -4;
    }
    else
    {
        printf("Initialised font from: %s\n", fontPath);
    }

    // Calculate the scale factor which will determine what multiple of 16 to use for sprites.
    scaleFactor = calculateScaleFactor(screenWidth, screenHeight);

    printf("Scale factor: %i\n", scaleFactor);

    // Read transparency value from config.
    transparencyType = atoi(al_get_config_value(config, "", "transparency"));
    printf("Transparency type: %i\n", transparencyType);

    if (transparencyType == 1)
    {
        // Updates the outside of sprites to HW_WHITE (grey) to emulate transparency.
        gamePalette[4] = HW_WHITE;
        initialPalette[4] = HW_WHITE;
    }
    else if (transparencyType == 2)
    {
        // Updated the outside of sprites to bright magenta to turn them transparent.
        gamePalette[4] = HW_BRIGHT_MAGENTA;
        initialPalette[4] = HW_BRIGHT_MAGENTA;
    }

    printf("Initialising allegro sprite sets...");

    // Initialise the sprite sets used by allegro.
    initAllAllegroSpriteSets(gamePalette, transparencyType);

    printf("done\n");

    // Runs the game menu including menu loop.
    runMenu(config, configPath);

    // Destroy the sprite sets used by allegro.
    destroyAllAllegroSpriteSets();

#endif

    // Cleanup allegro.
#ifdef ALLEGRO5

    destroyFonts();

    al_destroy_display(display_);
    al_shutdown_font_addon();
    al_shutdown_primitives_addon();

#elif ALLEGRO4

    // Cleanup fonts.
    destroyFonts();

    // End allegro.
    allegro_exit();

#endif

#ifndef CPC
    return 0;
#endif
}

#ifdef ALLEGRO4
END_OF_MAIN()
#endif
