
#include <WFX/SDL/SDLRenderWindow.h>
#include <WFX/lang/WFXException.h>
#include <GL/gl.h>

using namespace WFX;
using namespace WFX::SDL;

Int SDLRenderWindow::Instances = 0;

SDLRenderWindow::SDLRenderWindow(Int w, Int h, Int d, std::string title, bool fs) : RenderWindow(w,h,d,title,fs) {
    LOG("SDLRenderWindow::SDLRenderWindow");
    if (Instances<1) {
        //no instances yet - init SDL subsystem
        if(-1 == SDL_InitSubSystem(SDL_INIT_VIDEO))
            THROW("unable to init SDL Video... " << SDL_GetError());

        int flags  = SDL_OPENGL;
        flags |= SDL_HWPALETTE;
        flags |= SDL_RESIZABLE;

        if (fs)
            flags |= SDL_FULLSCREEN;

        const SDL_VideoInfo* VideoInfo = SDL_GetVideoInfo();

        if(VideoInfo == NULL) {
            THROW("unable to get videoinfo " << SDL_GetError());
        } else {
            if (VideoInfo -> hw_available)
                flags |= SDL_HWSURFACE;
            else
                flags |= SDL_SWSURFACE;
        }

        SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 0);          // we aren't going to use the stencil buffer
        SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, 0);        // this and the next three lines set the bits allocated per pixel -
        SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, 0);      // - for the accumulation buffer to 0
        SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, 0);
        SDL_GL_SetAttribute( SDL_GL_ACCUM_ALPHA_SIZE, 0);
        SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, Depth );
        SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );


        //create the window
        Screen = SDL_SetVideoMode(Width,Height,Depth,flags);
        if (!Screen)
            THROW("unable to create SDL Window... " << SDL_GetError());

        //set window caption
        setTitle(title);

        //set the default clear color to black
        setClearColor(WFX::scene::Color::BLACK);

        //enable HLHSR
        glEnable(GL_DEPTH_TEST);

        resize(w,h);
    }
    Instances++;
}

SDLRenderWindow::~SDLRenderWindow() {
    Instances--;
    if (Instances<1) {
        //TODO: shutdown SDL Video subsystem
    }
    SDL_FreeSurface(Screen);
}

void SDLRenderWindow::resize(Int w, Int h) {
    RenderWindow::resize(w,h);
    glViewport(0,0,Width,Height);
}

void SDLRenderWindow::swapBuffers() {
    SDL_GL_SwapBuffers();
}

void SDLRenderWindow::setClearColor(const WFX::scene::Color& c) {
    glClearColor(c.R,c.G,c.B,c.A);
}

void SDLRenderWindow::clear() {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}

void SDLRenderWindow::setTitle(std::string title) {
    WFX::renderer::RenderWindow::setTitle(title);
    SDL_WM_SetCaption(Title.c_str(), 0);
}

void SDLRenderWindow::toggleFullscreen() {
    if (!SDL_WM_ToggleFullScreen(Screen))
        THROW("could not toggle fullscreen mode");
}

void SDLRenderWindow::hideCursor() {
    SDL_ShowCursor(SDL_DISABLE);
}

void SDLRenderWindow::showCursor() {
    SDL_ShowCursor(SDL_ENABLE);
}

void SDLRenderWindow::warpCursor(UInt x, UInt y) {
    SDL_WarpMouse(x,y);
}

void SDLRenderWindow::centerCursor() {
    SDL_WarpMouse(Width/2,Height/2);
}

void SDLRenderWindow::saveToFile(const WFX::io::File& f) {
    LOG("saving to " << f.toString());
  
    if (f.toString().length() < 1)
        THROW("unable to save to file: " << f.toString());

    // we will store the image data here
    UChar *pixels;
    // the thingy we use to write files
    FILE * shot;
    // we get the width/height of the screen into this array
    Int screenStats[4];

    // get the width/height of the window
    glGetIntegerv(GL_VIEWPORT, screenStats);

    // generate an array large enough to hold the pixel data 
    // (width*height*bytesPerPixel)
    pixels = new UChar[screenStats[2]*screenStats[3]*3];
    // read in the pixel data, TGA's pixels are BGR aligned
    glReadPixels(0, 0, screenStats[2], screenStats[3], GL_BGR, 
            GL_UNSIGNED_BYTE, pixels);

    // open the file for writing. If unsucessful, throw Exception
    if((shot=fopen(f.toString().data(), "wb"))==NULL) 
        THROW("unable to open file " << f.toString());

    // this is the tga header it must be in the beginning of 
    // every (uncompressed) .tga
    UChar TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};
    // the header that is used to get the dimensions of the .tga
    // header[1]*256+header[0] - width
    // header[3]*256+header[2] - height
    // header[4] - bits per pixel
    // header[5] - ?
    UChar header[6]={((int)(screenStats[2]%256)),
        ((int)(screenStats[2]/256)),
        ((int)(screenStats[3]%256)),
        ((int)(screenStats[3]/256)),24,0};

    // write out the TGA header
    fwrite(TGAheader, sizeof(UChar), 12, shot);
    // write out the header
    fwrite(header, sizeof(UChar), 6, shot);
    // write the pixels
    fwrite(pixels, sizeof(UChar), 
            screenStats[2]*screenStats[3]*3, shot);

    // close the file
    fclose(shot);
    // free the memory
    delete [] pixels;
}

