#include "graphics.h"
#include "mac.h"

void CenterWindow()
{
	SDL_SysWMinfo info;

	SDL_VERSION(&info.version);
	if ( SDL_GetWMInfo(&info) > 0 ) {
		#ifdef __unix
			SDL_Surface *screen=SDL_GetVideoSurface();
			if ( info.subsystem == SDL_SYSWM_X11 ) {
				info.info.x11.lock_func();
				int w = DisplayWidth(info.info.x11.display,
								 DefaultScreen(info.info.x11.display));
				int h = DisplayHeight(info.info.x11.display,
								 DefaultScreen(info.info.x11.display));
				int x = (w - screen->w)/2;
				int y = (h - screen->h)/2;
				XMoveWindow(info.info.x11.display, info.info.x11.wmwindow, x, y);
				info.info.x11.unlock_func();
			}
		#endif // unix
		#ifdef WIN32
			{
			RECT rc;
			HWND hwnd = info.window;
			int w=GetSystemMetrics(SM_CXSCREEN);
			int h=GetSystemMetrics(SM_CYSCREEN);
			GetWindowRect(hwnd, &rc);
			int x = (w - (rc.right-rc.left))/2;
			int y = (h - (rc.bottom-rc.top))/2;
			SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
			}
		#endif // win
    }
	#if defined(__APPLE__) && defined(__GNUC__) // mac
		mac_CenterWindow();
	#endif
}

static bool screen_locked = false;

int safeBlitToScreen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Rect *dstrect)
{
    SDL_Surface *screen=SDL_GetVideoSurface();
    bool lock = SDL_MUSTLOCK(screen);
    if (lock && screen_locked) SDL_UnlockSurface(screen);
    int res = SDL_BlitSurface(src, srcrect, screen, dstrect);
    if (lock && screen_locked) SDL_LockSurface(screen);
    return res;
}

void drawString(TTF_Font *font, int x, int y, std::string text, SDL_Color color)
{
	SDL_Surface *temp=TTF_RenderText_Blended(font, text.c_str(), color);
	SDL_Rect fontpos;
	fontpos.x=x;
	fontpos.y=y;
	safeBlitToScreen(temp, NULL, &fontpos);
	SDL_FreeSurface(temp);
}
void centerString(TTF_Font *font, int x, int y, std::string text, SDL_Color color)
{
	SDL_Surface *temp=TTF_RenderText_Blended(font, text.c_str(), color);
	SDL_Rect fontpos;
	fontpos.x=x-(int)temp->w/2;
	fontpos.y=y-(int)temp->h/2;
	safeBlitToScreen(temp, NULL, &fontpos);
	SDL_FreeSurface(temp);
}
void DrawIMG(SDL_Surface *img, int x, int y)
{
  SDL_Rect dest;
  dest.x = x;
  dest.y = y;
  safeBlitToScreen(img, NULL, &dest);
}
void DrawIMG(SDL_Surface *img, int x, int y, int w, int h)
{
  SDL_Rect dest;
  dest.x = x;
  dest.y = y;
  SDL_Rect dest2;
  dest2.x = 0;
  dest2.y = 0;
  dest2.w = w;
  dest2.h = h;
  safeBlitToScreen(img, &dest2, &dest);
}
void DrawPixel(int x, int y, Uint8 R, Uint8 G, Uint8 B)
{
  SDL_Surface *screen=SDL_GetVideoSurface();
  Uint32 color = SDL_MapRGB(screen->format, R, G, B);
  switch (screen->format->BytesPerPixel)
  {
    case 1: // Assuming 8-bpp
      {
        Uint8 *bufp;
        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x;
        *bufp = color;
      }
      break;
    case 2: // Probably 15-bpp or 16-bpp
      {
        Uint16 *bufp;
        bufp = (Uint16 *)screen->pixels + y*screen->pitch/2 + x;
        *bufp = color;
      }
      break;
    case 3: // Slow 24-bpp mode, usually not used
      {
        Uint8 *bufp;
        bufp = (Uint8 *)screen->pixels + y*screen->pitch + x * 3;
        if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
        {
          bufp[0] = color;
          bufp[1] = color >> 8;
          bufp[2] = color >> 16;
        } else {
          bufp[2] = color;
          bufp[1] = color >> 8;
          bufp[0] = color >> 16;
        }
      }
      break;
    case 4: // Probably 32-bpp
      {
        Uint32 *bufp;
        bufp = (Uint32 *)screen->pixels + y*screen->pitch/4 + x;
        *bufp = color;
      }
      break;
  }
}

void Slock()
{
  SDL_Surface *screen=SDL_GetVideoSurface();
  if ( SDL_MUSTLOCK(screen) )
  {
    if ( SDL_LockSurface(screen) < 0 )
    {
      return;
    }
    else
    {
      screen_locked = true;
    }
  }
}

void Sulock()
{
  SDL_Surface *screen=SDL_GetVideoSurface();
  if ( SDL_MUSTLOCK(screen) )
  {
    SDL_UnlockSurface(screen);
    screen_locked = false;
  }
}
/*
 * Return the pixel value at (x, y)
 * NOTE: The surface must be locked before calling this!
 */
Uint32 getpixel(SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to retrieve */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        return *p;

    case 2:
        return *(Uint16 *)p;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;

    case 4:
        return *(Uint32 *)p;

    default:
        return 0;       /* shouldn't happen, but avoids warnings */
    }
}
void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}
bitmask *MakeMask(SDL_Surface *surface)
{
	int i, j;
	Uint8 r1=0;
	Uint8 g1=0;
	Uint8 b1=0;
	Uint8 a1=255;
	SDL_Rect *r;
	SDL_Rect rr;
	rr.x=0;
	rr.y=0;
	rr.w=surface->w;
	rr.h=surface->h;
	r=&rr;
	bitmask *mask;

	if ( SDL_MUSTLOCK(surface) ) { SDL_LockSurface(surface); }
	mask=bitmask_create(r->w,r->h);
	for (j = r->y; j < r->h + r->y; j++)
	{
		for (i=r->x; i < r->w + r->x; i++)
		{
			SDL_GetRGBA(getpixel(surface, i, j), surface->format, &r1, &g1, &b1, &a1);
			if (a1>128)
			{
				bitmask_setbit(mask,i-r->x,j-r->y);
			}
		}
	}
	if ( SDL_MUSTLOCK(surface) ) { SDL_UnlockSurface(surface); }
	return mask;
}
bool BoxCollision(SDL_Rect dest, SDL_Rect src)
{
	// calculate box collision
	return ((((src.x >= dest.x) && (src.x <= (dest.x+dest.w))) && ((src.y >= dest.y) && (src.y <= (dest.y+dest.h)))) ||
			((((src.x+src.w) >= dest.x) && ((src.x+src.w) <= (dest.x+dest.w))) && (((src.y+src.h) >= dest.y) && ((src.y+src.h) <= (dest.y+dest.h)))));
}
void ColorizeSurface(SDL_Surface *surf, Uint8 r, Uint8 g, Uint8 b)
{
	boxRGBA(surf, 0, 0, surf->w, surf->h, r, g, b, 128);
}

//StarField class
void StarField::Init(int fieldw, int fieldh)
{
	int i, sfSize, x, y;
	width=fieldw;
	height=fieldh;
	sfSize=sizeof(starfieldx)/sizeof(starfieldx[0]);
	for(i=0; i<sfSize; i++)
	{
		x=rand()%width;
		y=rand()%height;
		starfieldx[i]=x;
		starfieldy[i]=y;
	}
}
void StarField::Display(int x, int y)
{
	int i, sfSize, tx, ty;
	sfSize=sizeof(starfieldx)/sizeof(starfieldx[0]);
	for(i=0; i<sfSize; i++)
	{
		if (starfieldx[i]+x >= width) { tx=(starfieldx[i]+x)%width; }
		else {
			if (starfieldx[i]+x < 0) { tx=((starfieldx[i]+x)%width)+width; }
			else { tx=starfieldx[i]+x; }
		}
		if (starfieldy[i]+y >= height-1) { ty=(starfieldy[i]+y)%(height-1); }
		else {
			if (starfieldy[i]+y < 0) { ty=((starfieldy[i]+y)%(height-1))+(height-1); }
			else { ty=starfieldy[i]+y; }
		}
		DrawPixel(tx, ty, 255, 255, 255);
	}
}
void StarField::DisplayWarp(int x, int y, int angle, int length)
{
	SDL_Surface *screen=SDL_GetVideoSurface();
	int i, sfSize, tx, ty, tx2, ty2;
	double xsub, ysub;
	bool blitok;
	sfSize=sizeof(starfieldx)/sizeof(starfieldx[0]);
	xsub=-(sin(angle*(PI/180)));
	ysub=(cos(angle*(PI/180)));
	for(i=0; i<sfSize; i++)
	{
		blitok=true;
		if (starfieldx[i]+x >= width) { tx=(starfieldx[i]+x)%width; }
		else {
			if (starfieldx[i]+x < 0) { tx=((starfieldx[i]+x)%width)+width; }
			else { tx=starfieldx[i]+x; }
		}
		if (starfieldy[i]+y >= height-1) { ty=(starfieldy[i]+y)%(height-1); }
		else {
			if (starfieldy[i]+y < 0) { ty=((starfieldy[i]+y)%(height-1))+(height-1); }
			else { ty=starfieldy[i]+y; }
		}
		if (starfieldx[i]+x-(int)(xsub*length) >= width)
		{
			tx2=(starfieldx[i]+x-(int)(xsub*length))%width;
		}
		else {
			if (starfieldx[i]+x-(int)(xsub*length) < 0)
			{
				tx2=((starfieldx[i]+x-(int)(xsub*length))%width)+width;
			}
			else { tx2=starfieldx[i]+x-(int)(xsub*length); }
		}
		if (starfieldy[i]+y-(int)(ysub*length) >= height-1)
		{
			ty2=(starfieldy[i]+y-(int)(ysub*length))%(height-1);
		}
		else {
			if (starfieldy[i]+y-(int)(ysub*length) < 0)
			{
				ty2=((starfieldy[i]+y-(int)(ysub*length))%(height-1)) +(height-1);
			}
			else { ty2=starfieldy[i]+y-(int)(ysub*length); }
		}
		if (angle>=0 && angle<=180)
		{
			if (tx>tx2) { blitok=false; }
		}
		if (angle>=180 && angle<=360)
		{
			if (tx<tx2) { blitok=false; }
		}
		if ((angle>=270 && angle<=360) || (angle>=0 && angle<=90))
		{
			if (ty<ty2) { blitok=false; }
		}
		if (angle<=270 && angle>=90)
		{
			if (ty>ty2) { blitok=false; }
		}
		if (blitok) { lineRGBA(screen, tx, ty, tx2, ty2, 255, 255, 255, 255); }
	}
}

StaticAnim::StaticAnim()
{
	int i;
	for(i=0; i<12; i++)
	{
		anim[i]=0;
	}
	nextframe=0;
	w=0;
	h=0;
	zoom=1;
}
StaticAnim::~StaticAnim()
{
	int i;
	for(i=0; i<12; i++)
	{
		if (anim[i]) SDL_FreeSurface(anim[i]);
	}
}
StaticAnim::StaticAnim(const StaticAnim &oldanim)
{
	animbase=oldanim.animbase;
	int i;
	for (i=0; i<12; i++)
	{
		anim[i]=rotozoomSurface(oldanim.anim[i], 0, 1, 0);
	}
	nextframe=oldanim.nextframe;
	x=oldanim.x;
	y=oldanim.y;
	w=oldanim.w;
	h=oldanim.h;
	zoom=oldanim.zoom;
}
void StaticAnim::SetX(int sx)
{
	x=sx;
}
void StaticAnim::SetY(int sy)
{
	y=sy;
}
void StaticAnim::LoadFrames(std::string sanim)
{
	int i;
	animbase=sanim;
	SDL_Surface *temp;
	char send[60];
	for(i=1; i<13; i++)
	{
		sprintf(send,"%s%02d.png",sanim.c_str(), i);
		temp=LoadIMG(send);
		if (anim[i-1]) SDL_FreeSurface(anim[i-1]);
		anim[i-1]=rotozoomSurface(temp, 0, zoom, SMOOTH);
		SDL_FreeSurface(temp);
		if (i==1)
		{
			w=anim[i-1]->w;
			h=anim[i-1]->h;
		}
	}
}
void StaticAnim::DisplayNext(int sx, int sy)
{
	DrawIMG(anim[nextframe], sx, sy);
	nextframe++;
}
void StaticAnim::IncNext()
{
	nextframe++;
}
SDL_Surface *StaticAnim::GetAnim(int index)
{
	return anim[index];
}
int StaticAnim::GetNextFrame()
{
	return nextframe;
}
int StaticAnim::GetCurFrame()
{
	if (nextframe>=12)
	{
		nextframe=0;
		return -1;
	}
	else return nextframe;
}
int StaticAnim::GetX()
{
	return x;
}
int StaticAnim::GetY()
{
	return y;
}
int StaticAnim::GetWidth()
{
	return w;
}
int StaticAnim::GetHeight()
{
	return h;
}
float StaticAnim::GetZoom()
{
	return zoom;
}
std::string StaticAnim::GetBase()
{
	return animbase;
}
void StaticAnim::SetZoom(float szoom)
{
	zoom=szoom;
}


