#include "ninox.h"

#ifdef MSWIN32
#include <windows.h>
#endif

// malloc() with error trapping
void *
Malloc(int nbytes)
        {
        unsigned char *buf = malloc(nbytes);

        if (! buf) {
           Print("Malloc: Out of Memory\n");
           exit(1);
           }

        return buf;
        }

void *
ZeroMalloc(int nbytes)
	{
	unsigned char *buf = Malloc(nbytes);
	int i;

	for(i=0; i<nbytes;++i) buf[i]=0;

	//_vector_zero_F((FLOAT *)buf,nbytes/4);
	return buf;
	}

char *
VStrdup(char *str)
	{
	char *new;

	if (str==NULL) {
	   printf("VStrdup: passed NULL\n");
	   exit(1);
	   }

//printf("strdup '%s'\n",str); fflush(stdout);

	new = VMalloc(strlen(str)+1);
	strcpy(new,str);
//printf("done strdup\n"); fflush(stdout);
	return new;
	}

char *
TypeName(int type)
	{
	switch (type) {
	   case IMG_BMP: return "bmp"; break;
	   case IMG_FIT: return "fit"; break;
	   case IMG_PPM: return "ppm"; break;
	   }

	return "(unknown)";
	}

// return random value between 0 and (val-1) inclusive
int
Random(int val)
	{
	int rval;

	if (val<=0) return 0;

	again:
	rval = (int)((double)rand()/RAND_MAX * val);
	if (rval==val) goto again; // catch bad case

	return rval;
	}

int
Srandom()
	{
	srand(time(0));
	return(1);
	}

#ifdef MSWIN32
// We need our own version of strcasestr
char *
strcasestr(char *haystack, char *needle)
	{
	int len = strlen(haystack) - strlen(needle) + 1;
	int nlen = strlen(needle);
	int i,match=-1;

	if (len<0) return NULL;

	for(i=0; i<len; ++i)
	   if (! strncasecmp(haystack+i,needle,nlen)) {
		match=i;
		break;
	   	}

	if (match>=0) return haystack+match;
	return NULL;
	}
#endif

int
Usleep(int n)
	{
#ifdef MSWIN32
	Sleep((n / 1000));
#else
	usleep(n);
#endif
	return 0;
	}

void
Mkdir(char *dirname)
        {
	if (dirname==NULL || dirname[0]==0)  return;

        if (! isDirectory(dirname)) {
#ifdef MSWIN32
             mkdir(dirname);
#else
             mkdir(dirname,0755);
#endif

            if (! isDirectory(dirname)) {
               Print("Cannot create output directory %s\n",dirname);
               exit(1);
               }
           }
        }

FILE *
OpenLogfile(char *fname, char *mode)
	{
	char *logdir = ".ninox";
	char logfile[256];
	FILE *z;

	Mkdir(logdir);

	if (! isDirectory(logdir)) {
	   printf("Cannot create log directory %s\n",logdir);
	   exit(1);
	   }

	sprintf(logfile,"%s/%s",logdir,fname);
	z = fopen(logfile,mode);
	return z;
	}

// Given an output filename, return 1 if we are allowed
// to write to that file
int
AllowWrite(char *fname)
	{
	struct stat st;

	// If we have "-nosave" then we are not
	// allowed to write
	if (NoSave) return 0;

	// If we have enabled "-overwrite" then we
	// can always write
	if (AllowOverwrite) return 1;

	// If the file doesn't exist then we can
	// always write to it
	if (access(fname,R_OK)) return 1;

	// stat the file. If this failes then give up
	if (stat(fname,&st)) {
	   Print("stat error on [%s]\n",fname);
	   exit(1);
	   }

	// If file exists with size 0 then we can overwrite
	if (st.st_size == 0) return 1;

	return 0;
	}

int
isDirectory(char *str)
        {
        struct stat st;
        int val;

        if (stat(str,&st)) {
                //fprintf(stderr,"Cannot stat '%s'\n",str);
                return(0);
                }

        val = (st.st_mode & S_IFDIR);
        return (val);
        }

int
isFile(char *str)
        {
        struct stat st;
        int val;

        if (stat(str,&st)) {
                Print("Cannot stat '%s'\n",str);
                return(0);
                }

        val = (st.st_mode & S_IFREG);
        return(val);
        }

// return 1 if this file is of a known supported type
int
isSupportedFile(char *fname)
	{
	char *ptr;

	if (!fname) return(0);

	ptr = fname + strlen(fname)-1;
	while(ptr != fname && *ptr != '.') --ptr;
	if (*ptr != '.') return 0;

	if (!strcasecmp(ptr,".bmp")) return 1;
	if (!strcasecmp(ptr,".fit")) return 1;
	if (!strcasecmp(ptr,".ppm")) return 1;
	if (!strcasecmp(ptr,".fta")) return 1;

	return 0;
	}

void ShowImage(struct Image *img)
        {
        static int prop = -1;  // display properties for SDL
	static int last_needs_destroy = 0;
	static struct Image *I;
	int d_width,d_height;

	if (last_needs_destroy) {
	   DestroyImage(I);
	   last_needs_destroy = 0;
	   }

	if (img->depth == 16)
	   I = img;
	else {
	   I = ConvertImage(img,img->type,16);
	   last_needs_destroy = 1;
	   }

        if (DisplayFrames) {
           int x1,y1,x2,y2;

	   // may be displaying a subregion
	   x1 = img->cutout.x1; y1 = img->cutout.y1; x2 = img->cutout.x2; y2 = img->cutout.y2;

	   if (x1<0) x1=0; if (x2>=I->width) x2=I->width-1;
	   if (y1<0) y1=0; if (y2>= I->height) y2=I->height-1;

	   if (x1==0 && x2==0) x2 = I->width-1;
	   if (y1==0 && y2==0) y2 = I->height-1;

	   d_width  = x2-x1+1;	// dimensions of region we are transferring
	   d_height = y2-y1+1;

	    // make sure the display width is a multiple of 4
	    d_width = (d_width+3) & ~3;

            // If the image dimensions have changed then shutdown and restart the display
            if (HaveWindow && (d_width > GetDisplayWidth() || d_height > GetDisplayHeight())) {
		Print("current display is (%dx%d), we have image (%dx%d) - mismatch, delete and re-init display\n",
				GetDisplayWidth(), GetDisplayHeight(), d_width, d_height);

                ShutdownDisplay();
                HaveWindow = 0;
                }

            if (! HaveWindow) {
                int Depth = 16;
                HaveWindow = InitDisplay("Ninox",d_width,d_height,Depth);
                InitProperties();
                InitDisplay();
                }

            if (! HaveWindow) {
                int Depth = 32;
                HaveWindow = InitDisplay("VideoShow",d_width,d_height,Depth);
                }

           if (! HaveWindow) {
                Message("Cannot start SDL, display disabled");
                DisplayFrames = 0;
                }

           if (HaveWindow) {
	      int kb;

              if (prop<0) prop = CreateProperty(0,1.0,1.0);

	      x1=y1=0;  // no offset
              //y1 = (d_height - I->dst_height)/2;
              //x1 = (d_width - I->dst_width)/2;

	      //if (x1 > 200) x1 = 200;
	      //if (y1 > 200) y1 = 200;

              DisplayImage(I,prop,x1,y1);

	      if (DisplayPause)
		while(PollKeyboard() != 2) {Usleep(100);}
	      else PollKeyboard();
              }
           }
        }

#undef malloc
#undef free

// Code taken from man page for vsprintf()
int Print(char *fmt, ...)
        {
        /* Guess we need no more than 100 bytes. */
        int n, size = 100;
        char *p;
        va_list ap;
        static int start_of_line = 1;
        FILE *fd = stdout;

        if ((p = (char *)malloc (size)) == NULL) {
            fprintf(fd,"Print: Out of memory!\n");
            fflush(fd);
            return 0;
            }

        while (1) {
            /* Try to print in the allocated space. */
            va_start(ap, fmt);
            n = vsnprintf (p, size, fmt, ap);
            va_end(ap);

            /* If that worked, return the string. */
            if (n > -1 && n < size) {
                for(n=0; n<size && p[n]; ++n) {
                   if (start_of_line && CurrentFile) {fprintf(fd,"%s: ",CurrentFile); fflush(fd);}
                   if (putc(p[n],fd) == EOF) exit(1);
                   if (p[n] == '\n') start_of_line = 1;
                   else start_of_line = 0;
                   }

                free(p);
                fflush(fd);
		if (feof(fd)) exit(1);
                return 1;
                }

            /* Else try again with more space. */
            if (n > -1)    /* glibc 2.1 */
               size = n+1; /* precisely what is needed */
            else           /* glibc 2.0 */
               size *= 2;  /* twice the old size */
            if ((p = realloc (p, size)) == NULL) {
                fprintf(fd,"Print: Out of memory!\n"); fflush(fd);
                return 0;
                }
             }

        // notreached
        fflush(fd);
        return 0;
        }

