//#include <cmath>

#include "image.h"
#include <cmath>

void init_SDL(void)
{
  if (SDL_Init(SDL_INIT_VIDEO) != 0)
  {
    std::cerr << "SDL_Init() Failed: " << SDL_GetError() << '\n';
    exit(1);
  }
}

SDL_Surface* init_display(SDL_Surface *image, std::string title)
{
  SDL_Surface* display;
  display = SDL_SetVideoMode(image->w, image->h, 32,
                             SDL_HWSURFACE | SDL_DOUBLEBUF);
  if (display == NULL)
  {
    std::cerr << "SDL_SetVideoMode() Failed: " << SDL_GetError() << '\n';
    exit(1);
  }
  SDL_WM_SetCaption((char*)title.c_str(), (char*)title.c_str());
  return display;
}

void update_display(SDL_Surface *image, SDL_Surface *display)
{
  if (SDL_BlitSurface(image, NULL, display, NULL) != 0)
  {
    std::cerr << "SDL_BlitSurface() Failed: " << SDL_GetError() << '\n';
    exit(1);
  }
  SDL_Flip(display);
}

Uint8 *pixelref(SDL_Surface *surface, unsigned x, unsigned y)
{
  int bpp = surface->format->BytesPerPixel;
  return (Uint8*)surface->pixels + y * surface->pitch + x * bpp;
}

void putpixel(SDL_Surface *surface, unsigned x, unsigned y, char r, char g,
              char b)
{
  Uint32 pixel = SDL_MapRGB(surface->format, (Uint8) r, (Uint8) g, (Uint8) b);
  Uint8 *p = pixelref(surface, x, y);
  switch(surface->format->BytesPerPixel)
  {
  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;
  }
}


Uint32 getpixel(SDL_Surface *surface, unsigned x, unsigned y)
{
  Uint8 *p = pixelref(surface, x, y);
  switch(surface->format->BytesPerPixel)
  {
  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;
  }
  return 0;
}

SDL_Surface* create_image(int width, int length)
{
  SDL_Surface *image = SDL_CreateRGBSurface(0,width,length,32,255,255,255,0);
  return image;
}

void save_image(SDL_Surface *image, std::string filename)
{
  SDL_SaveBMP(image, (char*)filename.c_str());
}

void white_image(SDL_Surface *image)
{
  for(int i = 0; i < image->w; ++i)
    for(int j = 0; j < image->h; ++j)
      putpixel(image,i,j,255,255,255);
}


void draw_line(SDL_Surface* image, float x1, float y1, float x2, float y2)
{
  // Bresenham's line algorithm
  const bool steep = (fabs(y2 - y1) > fabs(x2 - x1));
  if(steep)
  {
    std::swap(x1, y1);
    std::swap(x2, y2);
  }

  if(x1 > x2)
  {
    std::swap(x1, x2);
    std::swap(y1, y2);
  }

  const float dx = x2 - x1;
  const float dy = fabs(y2 - y1);

  float error = dx / 2.0f;
  const int ystep = (y1 < y2) ? 1 : -1;
  int y = (int)y1;

  const int maxX = (int)x2;

  for(int x=(int)x1; x<maxX; x++)
  {
    if(steep)
    {
      if(y >= 0 && y < image->w && x >= 0 && x < image->h)
        putpixel(image, y, x, 0, 0, 0);
    }
    else
    {
      if(y >= 0 && y < image->h && x >= 0 && x < image->w)
        putpixel(image, x, y, 0, 0, 0);
    }

    error -= dy;
    if(error < 0)
    {
      y += ystep;
      error += dx;
    }
  }
}
