
#include "allegro.h"
#include "fmod.hpp"
#include "fmod_errors.h"
#include <string.h>
#include <iostream>
#include <math.h>

//Width
#define screenx 800
//Height
#define screeny 600

#define fontWidth 32
#define fontHeight 64

#define fontx 1536

using namespace std;

void initAllegro();
void initFmod();
void startPlayBack();
void releaseResources();
void initFont();
void killBitmaps();
void drawString(int x, int y, char *message);
void drawCharacter(int x, int y, char letter);
void resolvePalettes(PALETTE font_pal,PALETTE img_pal,BITMAP *font_bmp, BITMAP *img_bmp,PALETTE out_pal);


PALETTE font_pal;
PALETTE combo_pal; 
PALETTE background_pal;

BITMAP *offScreen;
BITMAP *font_bmp;
BITMAP *background;

FMOD::System *fmodSystem;
FMOD::Sound *sound;
FMOD::Channel *channel = 0;

int main(int argc, char *argv[]) {

    int framecount;
    framecount = 0;

    float sinus = 0;
    
    // Scroller message
    char msg[] =    "Greetings from the pewsqaure crew!  "
    				"As you can probably tell, "
    				"we have not done anything like this before.  "
                    "We are really enjoying our first demo-party.  "
                    "Greetz to Mistluren, Qlint, dunzor and Nebulai.  "
                    "And of course everyone else at Edison 2015: A DemoScene Odyssey.  "
                    "This demo was created using a guide from 2004.  "
                    "Programming by Tylhadras.  "
                    "Music by Tek-ti and FireArrow.  "
                    "Graphics by Alcor.  "
                    "Use the escape key to quit.  "
                    "Text restarting in 5   4   3   2   1   0  "
                    "     -1";

    initAllegro();
    offScreen = create_bitmap(screenx, screeny);
    background = load_bitmap("1.bmp", background_pal);
    initFmod();
    initFont();
    resolvePalettes(font_pal,background_pal, font_bmp, background, combo_pal);
    set_palette(combo_pal);
    //set_pallete(font_pal);
    install_timer();
    startPlayBack();

    while(!key[KEY_ESC]){
        fmodSystem->update();
        blit(background, offScreen, 0, 0, 0, 0, screenx, screeny);
        drawString(screenx-framecount, (sin(sinus) * 60)+400+cos(sinus/2)*60, msg);
        if (((strlen(msg)*fontWidth) - framecount+screenx) <= 0) {
            framecount = 0;
        }
        framecount += 4;
        sinus += 0.05;
        vsync();
        blit(offScreen, screen, 0, 0, 0, 0, screenx, screeny);
        rest(1);
    }

    killBitmaps();
    remove_timer();
    releaseResources();
    return 0;
}
END_OF_MAIN();

void drawString(int x,int y,char *message) {
    int i;
    for (i=0;i<strlen(message);i++) {
        drawCharacter(x+i*fontWidth,y,message[i]);
    }
}

void drawCharacter(int x,int y, char letter) {
    int i;
    char chrmap[]="abcdefghijklmnopqrstuvwxyz0123456789\"'(),.;:+-!?";
    
    if(letter>='A' && letter<='Z')
        letter +='a'-'A';

    for (i=0;i<strlen(chrmap)&&(chrmap[i]!=letter);i++);

    if (i<strlen(chrmap)) {
        if ((x+fontWidth)>0 && x<screenx) {
            masked_blit(font_bmp, offScreen, i*fontWidth, 0, x, y, fontWidth, fontHeight);
        }
    }
}

void killBitmaps() {
    destroy_bitmap(font_bmp);
    destroy_bitmap(offScreen);
    destroy_bitmap(background);
}

void initFont() {
    font_bmp = load_bitmap("3.pcx", font_pal);
    if(!font_bmp) {
        set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
        allegro_message("Could not create bitmap from font\n%s\n", allegro_error);
        exit(1);
    }
}

void initAllegro() {
    allegro_init();
    install_keyboard();

    set_color_depth(8);

    if (set_gfx_mode(GFX_AUTODETECT_FULLSCREEN, screenx, screeny, 0, 0) < 0) {
        set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
        allegro_message("Failure to init video mode!\n%s\n", allegro_error);
        exit(1);
    }
    
}

void initFmod() {
    FMOD::System_Create(&fmodSystem);
    fmodSystem->init(32, FMOD_INIT_NORMAL, 0);
}

void startPlayBack() {
    fmodSystem->createSound("truck.xm", FMOD_DEFAULT, 0, &sound);
    //sound->setMode(FMOD_LOOP);
    fmodSystem->playSound(sound, 0, false, &channel);
}

void releaseResources() {
    sound->release();
    fmodSystem->close();
    fmodSystem->release();
}

void resolvePalettes(PALETTE font_pal,PALETTE img_pal,BITMAP *font_bmp, BITMAP *img_bmp,PALETTE out_pal) {
    int freq[64][64][64];
    int r,g,b;
    int x,y,i;
    int best_freq_value;
 
    RGB bestColour;
    RGB tempColour;
    
    memset(freq,0,sizeof(freq));
    
    set_palette(font_pal);
    for (x=0; x<fontx; x++) {
        for (y=0; y<fontHeight; y++) {
                get_color(getpixel(font_bmp,x,y),&tempColour);
                freq[tempColour.r][tempColour.g][tempColour.b]++;
        }
    }

    set_palette(img_pal);
    for (x=0; x<screenx; x++) {
        for (y=0; y<screeny; y++) {
                get_color(getpixel(font_bmp,x,y),&tempColour);
                freq[tempColour.r][tempColour.g][tempColour.b]++;
        }
    }

    out_pal[0].r=0;out_pal[0].g=0;out_pal[0].b=0;
    freq[0][0][0]=-1;
    for (i=1;i<256;i++) {
        best_freq_value=0;
        bestColour.r=0;  bestColour.g=0;  bestColour.b=0;
        for (r=0; r<64; r++) {
            for (g=0; g<64; g++) {
                for (b=0; b<64; b++) {
                    if (freq[r][g][b]>best_freq_value) {
                        bestColour.r=r;
                        bestColour.g=g;
                        bestColour.b=b;
                        best_freq_value=freq[r][g][b];
                    }
                }
            }
        }
        out_pal[i]=bestColour;
        freq[bestColour.r][bestColour.g][bestColour.b]=-1;
    }
    
    set_palette(font_pal);
    for (x=0; x<fontx; x++) {
        for (y=0; y<fontHeight; y++) {
            if (getpixel(font_bmp, x, y) == 0) {
                putpixel(font_bmp, x, y, 0);
            } else {
                get_color(getpixel(font_bmp, x, y), &tempColour);
                putpixel(font_bmp, x, y, bestfit_color(out_pal, tempColour.r, tempColour.g, tempColour.g));
            }
        }
    }

    set_palette(img_pal);
    for (x=0; x<screenx; x++) {
        for (y=0; y<screeny; y++) {
            get_color(getpixel(img_bmp,x,y),&tempColour); 
            putpixel(img_bmp, x, y, bestfit_color(out_pal, tempColour.r, tempColour.g, tempColour.g));
        }
    }
}
