#include "img_conv.h"
#include "Image.h"

#ifdef __cplusplus
extern "C" {
#endif

static void
rotate90( PImage i, Byte * new_data, int new_line_size)
{
   int y;
   int w   = i->w;
   int pixel_size    = (i-> type & imBPP) / 8;
   int tail = i-> lineSize - w * pixel_size  ;
   Byte * src = i->data, * dst0;

   switch (i->type & imBPP) {
   case 8: 
      dst0 = new_data + i->w * new_line_size;
      for ( y = 0; y < i-> h; y++) {
         register int x = w;
         register Byte * dst = dst0++;
         while (x--) 
            *(dst -= new_line_size) = *src++;
         src += tail;
      }
      return;

   default: 
      dst0 = new_data + ( i-> w - 1) * new_line_size;
      new_line_size += pixel_size;
      for ( y = 0; y < i-> h; y++) {
         register int x = w;
         register Byte * dst = dst0;
         while (x--) {
            register int b = pixel_size;
            while ( b--) 
               *dst++ = *src++;
            dst -= new_line_size;
         }
         src += tail;
         dst0 += pixel_size;
      }
      return ;
   }     
}

static void
rotate180( PImage i, Byte * new_data)
{
   int y, bs2;
   int w          = i->w;
   int pixel_size = (i-> type & imBPP) / 8;
   int tail       = i-> lineSize - w * pixel_size  ;
   Byte * src = i->data, *dst = new_data + i-> h * i-> lineSize - tail - pixel_size;

   switch (i->type & imBPP) {
   case 8: 
      for ( y = 0; y < i-> h; y++) {
         register int x = w;
         while (x--) 
            *dst-- = *src++;
         src += tail;
         dst -= tail;
      }
      return;

   default: 
      bs2 = pixel_size + pixel_size;
      for ( y = 0; y < i-> h; y++) {
         register int x = w;
         while (x--) {
            register int b = pixel_size;
            while ( b--) 
               *dst++ = *src++;
            dst -= bs2;
         }
         src += tail;
         dst -= tail;
      }
      return ;
   }     
}

static void
rotate270( PImage i, Byte * new_data, int new_line_size)
{
   int y;
   int w   = i->w;
   int pixel_size    = (i-> type & imBPP) / 8;
   int tail = i-> lineSize - w * pixel_size;
   Byte * src = i->data, *dst0;

   switch (i->type & imBPP) {
   case 8: 
      dst0 = new_data + i->h - new_line_size - 1;
      for ( y = 0; y < i-> h; y++) {
         register int x = w;
         register Byte * dst = dst0--;
         while (x--) 
            *(dst += new_line_size) = *(src++);
         src += tail;
      }
      return;

   default: 
      dst0 = new_data + (i->h - 1) * pixel_size;
      new_line_size -= pixel_size;
      for ( y = 0; y < i-> h; y++) {
         register int x = w;
         register Byte * dst = dst0;
         while (x--) {
            register int b = pixel_size;
            while ( b--) 
               *(dst++) = *(src++);
            dst += new_line_size;
         }
         src += tail;
         dst0 -= pixel_size;
      }
      return ;
   }     
}

void 
img_rotate( Handle self, Byte * new_data, int new_line_size, int degrees)
{
   PImage i = ( PImage ) self;

   if (( i-> type & imBPP) < 8 )
      croak("Not implemented");

   switch ( degrees ) {
   case 90:
      rotate90(i, new_data, new_line_size);
      break;
   case 180:
      rotate180(i, new_data);
      break;
   case 270:
      rotate270(i, new_data, new_line_size);
      break;
   }
}

void
img_mirror( Handle self, Bool vertically)
{
   int y;
   PImage i = ( PImage ) self;
   int ls = i->lineSize, w = i->w, h = i->h;
   register Byte swap;

   if ( vertically ) {
       Byte * src = i->data, *dst = i->data + ( h - 1 ) * ls, *p, *q;
       h /= 2;
       for ( y = 0; y < h; y++, src += ls, dst -= ls ) {
          register int t = ls;
          p = src;
          q = dst;
          while ( t-- ) {
            swap = *q;
            *(q++) = *p;
            *(p++) = swap;
          }
       }
   } else {
      Byte * data = i->data;
      int x, pixel_size = (i->type & imBPP) / 8, last_pixel = (w - 1) * pixel_size, w2 = w / 2;
      switch (i->type & imBPP) {
      case 1:
      case 4:
      	 croak("Not implemented");
      case 8:
         for ( y = 0; y < h; y++, data += ls ) {
            Byte *p = data, *q = data + last_pixel;
            register int t = w2;
            while ( t-- ) {
               swap = *q;
               *(q--) = *p;
               *(p++) = swap;
	    }
         }
	 break;
      default:
         for ( y = 0; y < h; y++, data += ls ) {
            Byte *p = data, *q = data + last_pixel;
	    for ( x = 0; x < w2; x++, q -= pixel_size * 2) {
               register int t = pixel_size;
	       while (t--) {
                  swap = *q;
                  *(q++) = *p;
                  *(p++) = swap;
	       }
	    }
          }
       } 	    
    }
}

#ifdef __cplusplus
}
#endif

