#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "burnint.h"
#include "png.h"
#include "sshot.h"

int GetDisplayDepth();

unsigned char *pSShotBuffer = NULL;		// Pointer to DtosMem (for screenshot purposes)

#ifdef _MSC_VER
 #pragma warning(disable:4611)			// interaction between _setjmp and C++ destructors not portable
#endif

#define SSHOT_DIRECTORY "sshots\\"
#define LOG_RAW 0

static unsigned char* newpic;
static png_bytep* row_pointer_bunch;

int DoScreenShot()
{
    int w,h,i;
    char tmpname[256];
    time_t ltime;
    struct tm *newtime;
    time(&ltime);
    newtime = localtime(&ltime);
	if (pSShotBuffer == NULL) return SSHOT_OTHER_ERROR;
	BurnDrvGetScreen(&w,&h); // get width and height
	if (BurnDrvGetFlags() & BDF_ROTATE_GRAPHICS_CCW) {
		int t = w;
		w = h;
		h = t;
	}
    // construct our filename -> "romname-hhmmss.png"
    sprintf(tmpname,"%s%s-%.2d%.2d%.2d.png",SSHOT_DIRECTORY,BurnDrvText(0),newtime->tm_hour,newtime->tm_min,newtime->tm_sec);
    FILE *ff=NULL; ff=fopen(tmpname,"wb"); if (ff==NULL) return SSHOT_OTHER_ERROR;

    // do our PNG construct things
    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {fclose(ff); remove(tmpname); return SSHOT_LIBPNG_ERROR;}

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
        fclose(ff);
        remove(tmpname);
        return SSHOT_LIBPNG_ERROR;
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
		if (newpic) free(newpic);
		if (row_pointer_bunch) free(row_pointer_bunch);
        fclose(ff);
        remove(tmpname);
        return SSHOT_LIBPNG_ERROR;
    }

    png_init_io(png_ptr, ff);

    if (nBurnBpp==1) // we don't do 256 colors
    {
        remove(tmpname);
        return SSHOT_ERROR_BPP_NOTSUPPORTED;
    }

    if (nBurnBpp==2) // unpack 16-bit pixels data to 24-bit
    {
        newpic = (unsigned char*)malloc(w*h*3);
        for (i=0;i<h*w;i++)
        {
            short* temp = (short*)(pSShotBuffer+2*i);
			int nSShotDepth = nBurnBitDepth;

			/**************************************

			  initial = bbbbb gggggg rrrrr (565) (or 555 for 15-bit)

			  final = RRRRRRRR GGGGGGGG BBBBBBBB

            ***************************************/

            *(newpic+3*i+0)=(char)((*temp&0x1f)<<3);
			*(newpic+3*i+0) |= *(newpic+3*i+0) >> 5;
			if (nSShotDepth==15)
			{
				*(newpic+3*i+1)=(char)(((*temp>>5)&0x1f)<<3);
				*(newpic+3*i+1) |= *(newpic+3*i+1) >> 5;
				*(newpic+3*i+2)=(char)(((*temp>>10)&0x1f)<<3);
				*(newpic+3*i+2) |= *(newpic+3*i+2) >> 5;
			}
			if (nSShotDepth==16)
			{
				*(newpic+3*i+1)=(char)(((*temp>>5)&0x3f)<<2);
				*(newpic+3*i+1) |= *(newpic+3*i+1) >> 6;
				*(newpic+3*i+2)=(char)(((*temp>>11)&0x1f)<<3);
				*(newpic+3*i+2) |= *(newpic+3*i+2) >> 5;
			}
        }
        pSShotBuffer=newpic;
    }

    png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
    png_write_info(png_ptr, info_ptr);

    // strip the extra byte
    if (nBurnBpp==4) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);

    png_set_bgr(png_ptr);
    row_pointer_bunch = (png_bytep*)malloc(h*sizeof(png_bytep));
    for (i=0;i<h;i++)
    {
		int nSShotBurnBpp = nBurnBpp;
		if (nSShotBurnBpp < 3) {
			nSShotBurnBpp = 3;
		}
        row_pointer_bunch[i]=pSShotBuffer+(i*w*nSShotBurnBpp);
    }
#if LOG_RAW
    FILE *ll=NULL; ll=fopen("c:\\pnglog.bin","wb"); if (ll==NULL) return SSHOT_OTHER_ERROR;
    for (int j=0;j<h;j++)
		int nSShotBurnBpp = nBurnBpp;
		if (nSShotBurnBpp < 3) {
			nSShotBurnBpp = 3;
		}
        for (int k=0;k<w*nSShotBurnBpp;k++)
            fputc(*(pSShotBuffer+(j*w*nSShotBurnBpp+k)),ll);
		fclose(ll);
#endif
	png_write_image(png_ptr, row_pointer_bunch);
	png_write_end(png_ptr, info_ptr);
	png_destroy_write_struct(&png_ptr, &info_ptr);
	if (newpic) free(newpic);
	if (row_pointer_bunch) free(row_pointer_bunch);
	fclose(ff);
	return SSHOT_NOERROR;
}
