#include <stdio.h>
#include <jmgraph.h>


static int COLOR;

void vga_init(int mode)
{
  if (mode == 1) // graphics mode
  { 
     if (!g_mode(G640x480x16))
     { fprintf (stderr, "Cannot switch to graphics mode 640x480x16\n");
       exit(1);
      }

     for(int i=0; i<16; i++) 
        vga_setpal(i,_R_[i],_G_[i],_B_[i]);

     COLOR = 1;
     g_clip(0,0,g_xsize-1,g_ysize-1);
    }
  else
    g_mode(GTEXT);
}

void vga_clear(int col) { g_box(0,0,g_xsize-1,g_ysize-1,col,G_FILL); }

int  vga_width()  { return g_xsize; }
int  vga_height() { return g_ysize; }
int  vga_depth()  { return 4; } //g_colors; 

void vga_set_color(int col) { COLOR = col; }


void vga_set_mode(int mode)
{ switch(mode) {
   case 0: g_wmode(G_NORM);
           break;
   case 1: g_wmode(G_AND);
           break;
   case 2: g_wmode(G_OR);
           break;
   case 3: g_wmode(G_XOR);
           break;
  }
}


void vga_setpal(int index, int red, int green, int blue)
{ _R_[index] = red;
  _G_[index] = green;
  _B_[index] = blue;
  char pal[3];
  pal[0] = red/4;
  pal[1] = green/4;
  pal[2] = blue/4;
  g_vgapal(pal,index,1,1);
}

void vga_getpal(int index, int* red, int* green, int* blue)
{ *red   = _R_[index];
  *green = _G_[index];
  *blue  = _B_[index];
 }

void vga_pixel(int x, int y)              { g_set(x,y,COLOR); }
void vga_hline(int x0,int x1, int y)      { g_box(x0,y,x1,y,COLOR,G_FILL); }
void vga_vline(int x, int y0, int y1)     { g_box(x,y0,x,y1,COLOR,G_FILL); }
void vga_box(int x0,int y0,int x1,int y1) { g_box(x0,y0,x1,y1,COLOR,G_FILL); }


static void vga_bytes(int x, int y, unsigned char* lp, int len)
{ unsigned char* stop = lp+len;
  while (lp < stop)
  { unsigned char c = *lp++;
    if (c & 128) g_set(x,  y,COLOR);
    if (c &  64) g_set(x+1,y,COLOR);
    if (c &  32) g_set(x+2,y,COLOR);
    if (c &  16) g_set(x+3,y,COLOR);
    if (c &   8) g_set(x+4,y,COLOR);
    if (c &   4) g_set(x+5,y,COLOR);
    if (c &   2) g_set(x+6,y,COLOR);
    if (c &   1) g_set(x+7,y,COLOR);
    x += 8;
   }
}

void vga_bitmap(int x, int y, unsigned char* pm, int width, int height)
{ while (height--)
  { vga_bytes(x,y++,pm,width);
    pm += width;
   }
 }


struct Image {
 int w;
 int h;
 char* buf;
};


char* vga_getimage(int left, int top, int right, int bottom )
{ Image* im = new Image;
  im->w = right - left + 1;
  im->h = bottom - top + 1;
  int sz = g_imagesize(im->w,im->h);
  im->buf = new char[sz];
  g_getimage(left,top,right,bottom,im->buf);
  return (char*)im;
}

void  vga_putimage(int x, int y, char* p)
{ Image* im = (Image*)p;
  g_putimage(x,y,x+im->w-1,y+im->h-1,im->buf);
 }

void  vga_delimage(char* p) 
{ Image* im = (Image*)p;
  delete[] im->buf; 
  delete im;
}


void vga_copyimage(int x1, int y1, int x2, int y2, int x, int y)
{ int w = x2 - x1 + 1;
  int h = y2 - y1 + 1;
  int sz = g_imagesize(w,h);
  char* image = new char[sz];
  g_getimage(x1,y1,x2,y2,image);
  g_putimage(x,y,x+w-1,y+h-1,image);
  delete[] image;
 }



