#include <amscimglib4/amscimglib4.h>
#include <amscimglib4/amscimglib4_intl.h>

#ifdef __cplusplus
extern "C" {  
#endif


AMSCIMGLIB4_API int amscimglib4_image_new(amscimglib4_image **imgptr, int _sizex, int _sizey)
{
    int ret = amscimglib4_success;
    int res;

    if(imgptr==NULL)
    {
        ret = amscimglib4_failure;
        return ret;
    }
    if(*imgptr!=NULL)
    {
        res = amscimglib4_image_delete(imgptr);
        if(*imgptr!=NULL || res==amscimglib4_failure)
        {
            ret = amscimglib4_failure;
            return ret;
        }
    }

    *imgptr = (amscimglib4_image*) malloc(sizeof(amscimglib4_image));
    if(*imgptr==NULL)
    {
        ret = amscimglib4_failure;
        return ret;
    }
    (*imgptr)->sizex = 0;
    (*imgptr)->sizey = 0;
    (*imgptr)->data = NULL;

    res = amscimglib4_image_resize(*imgptr,_sizex,_sizey);
    if(res==amscimglib4_failure)
    {
        ret = amscimglib4_failure;
        return ret;
    }

    return ret;
}


AMSCIMGLIB4_API int amscimglib4_image_delete(amscimglib4_image **imgptr)
{
    int ret = amscimglib4_success;
    amscimglib4_image* lptr;

    if(imgptr==NULL)
    {
        return ret;
    }
    if(*imgptr==NULL)
    {
        return ret;
    }

    lptr = *imgptr;

    if(lptr->data!=NULL)
    {
        free(lptr->data);
        lptr->data=NULL;
    }
    
    lptr->sizex = 0;
    lptr->sizey = 0;

    free(*imgptr);
    *imgptr = NULL;

    return ret;
}


AMSCIMGLIB4_API int amscimglib4_image_resize(amscimglib4_image *imgptr, int _sizex, int _sizey)
{
    int ret = amscimglib4_success;
    unsigned char *newdata = NULL;
    int I,J,K;

    if(imgptr==NULL)
    {
        return amscimglib4_failure;
    }

    newdata = (unsigned char*) malloc(sizeof(unsigned char)*4*_sizex*_sizey);
    if(newdata==NULL)
    {
        return amscimglib4_failure;
    }

    for(K=0;K<4;K++)
    for(I=0;I<_sizex;I++)
    for(J=0;J<_sizey;J++)
        newdata[4*(I+_sizex*J)+K] = 0;

    if(imgptr->data!=NULL)
    {
        for(K=0;K<4;K++)
        for(I=0;I<_sizex && I<imgptr->sizex;I++)
        for(J=0;J<_sizey && J<imgptr->sizey;J++)
            newdata[4*(I+_sizex*J)+K] = imgptr->data[4*(I+imgptr->sizex*J)+K];
    }

    free(imgptr->data);
    imgptr->data = newdata;
    imgptr->sizex = _sizex;
    imgptr->sizey = _sizey;


    return ret;
}

//sets all pixels in the image to (0,0,0,0)
AMSCIMGLIB4_API void amscimglib4_image_clear(amscimglib4_image *imgptr)
{
    int I,J,K;

    if(imgptr == NULL) return;

    if(imgptr->data!=NULL)
    {
        for(K=0;K<4;K++)
        for(I=0;I<imgptr->sizex;I++)
        for(J=0;J<imgptr->sizey;J++)
            imgptr->data[4*(I+imgptr->sizex*J)+K] = 0;
    }

    return;
}

//copies an image from one image struct to another
//resizes imgto
AMSCIMGLIB4_API int amscimglib4_image_copy(amscimglib4_image *imgto, const amscimglib4_image *imgfrom)
{
    int ret = amscimglib4_success;
    int res;
    int I,J,K;

    res = amscimglib4_image_resize(imgto,imgfrom->sizex,imgfrom->sizey);
    if(res==amscimglib4_failure)
    {
        ret = amscimglib4_failure;
        return ret;
    }

    if(imgfrom->data!=NULL && imgto->data!=NULL)
    {
        for(K=0;K<4;K++)
        for(I=0;I<imgto->sizex && I<imgfrom->sizex;I++)
        for(J=0;J<imgto->sizey && J<imgfrom->sizey;J++)
            imgto->data[4*(I+imgto->sizex*J)+K] = imgfrom->data[4*(I+imgfrom->sizex*J)+K];
    }

    return ret;
}

//transposes an image
AMSCIMGLIB4_API int amscimglib4_transpose_image(amscimglib4_image *img)
{
    int ret = amscimglib4_success;
    int res;
    amscimglib4_image *img2 = NULL;
    int I,J,K;

    if(img==NULL)
    {
        ret = amscimglib4_failure;
        return ret;
    }

    res = amscimglib4_image_new(&img2,img->sizex,img->sizey);
    if(res==amscimglib4_failure)
    {
        ret = amscimglib4_failure;
        return ret;
    }

    amscimglib4_image_copy(img2,img);
    res = amscimglib4_image_resize(img,img2->sizey,img2->sizex);
    if(res==amscimglib4_failure || img->sizex != img2->sizey || img->sizey != img2->sizex)
    {
        ret = amscimglib4_failure;
        amscimglib4_image_delete(&img2);
        return ret;
    }

    for(K=0;K<4;K++)
    for(I=0;I<img->sizex;I++)
    for(J=0;J<img->sizey;J++)
        img->data[4*(I+img->sizex*J)+K] = img2->data[4*(J+img2->sizex*I)+K];

    amscimglib4_image_delete(&img2);

    return ret;
}

AMSCIMGLIB4_API int amscimglib4_set_pixel_RGBA(amscimglib4_image *img, int x, int y, 
    unsigned char R, unsigned char G, unsigned char B, unsigned char A)
{
    int ret = amscimglib4_success;
    if(img==NULL)
    {
        ret = amscimglib4_failure;
        return ret;
    }

    if(img->data==NULL)
    {
        ret = amscimglib4_failure;
        return ret;
    }


    if(x<0 || y<0 || x>=img->sizex || y>=img->sizey)
    {
        ret = amscimglib4_failure;
        return ret;
    }

    img->data[4*(x+img->sizex*y)+0] = R;
    img->data[4*(x+img->sizex*y)+1] = G;
    img->data[4*(x+img->sizex*y)+2] = B;
    img->data[4*(x+img->sizex*y)+3] = A;
    

    return ret;
}

AMSCIMGLIB4_API int amscimglib4_get_pixel_RGBA(amscimglib4_image *img, int x, int y, 
    unsigned char *R, unsigned char *G, unsigned char *B, unsigned char *A)
{
    int ret = amscimglib4_success;

    if(img==NULL)
    {
        ret = amscimglib4_failure;
        if(R!=NULL) *R = 0;
        if(G!=NULL) *G = 0;
        if(B!=NULL) *B = 0;
        if(A!=NULL) *A = 0;
        
        return ret;
    }

    if(img->data==NULL)
    {
        ret = amscimglib4_failure;
        if(R!=NULL) *R = 0;
        if(G!=NULL) *G = 0;
        if(B!=NULL) *B = 0;
        if(A!=NULL) *A = 0;
        
        return ret;
    }

    if(x<0 || y<0 || x>=img->sizex || y>=img->sizey)
    {
        ret = amscimglib4_failure;
        if(R!=NULL) *R = 0;
        if(G!=NULL) *G = 0;
        if(B!=NULL) *B = 0;
        if(A!=NULL) *A = 0;

        return ret;
    }

    if(R!=NULL) *R = img->data[4*(x+img->sizex*y)+0];
    if(G!=NULL) *G = img->data[4*(x+img->sizex*y)+1];
    if(B!=NULL) *B = img->data[4*(x+img->sizex*y)+2];
    if(A!=NULL) *A = img->data[4*(x+img->sizex*y)+3];

    return ret;
}

AMSCIMGLIB4_API int amscimglib4_set_pixel(amscimglib4_image *img, int x, int y, 
    const amscimglib4_pixel px)
{
    int ret = amscimglib4_set_pixel_RGBA(img,x,y,px.R,px.G,px.B,px.A);
    return ret;
}

AMSCIMGLIB4_API int amscimglib4_get_pixel(amscimglib4_image *img, int x, int y, 
    amscimglib4_pixel *px)
{
    int ret;
    if(px==NULL) return amscimglib4_failure;
    ret = amscimglib4_get_pixel_RGBA(img,x,y,&(px->R),&(px->G),&(px->B),&(px->A));
    return ret;
}


AMSCIMGLIB4_API void amscimglib4_image_flipx(amscimglib4_image *img)
{
    amscimglib4_image *img2 = NULL;
    if(img==NULL) return;
    int I,J,K;

    amscimglib4_image_new(&img2,img->sizex,img->sizey);
    amscimglib4_image_copy(img2,img);

    for(K=0;K<4;K++)
    for(I=0;I<img->sizex;I++)
    for(J=0;J<img->sizey;J++)
        img->data[4*(I+img->sizex*J)+K] = img2->data[4*((img2->sizex-I-1)+img2->sizex*J)+K];

    amscimglib4_image_delete(&img2);
    return;
}

AMSCIMGLIB4_API void amscimglib4_image_flipy(amscimglib4_image *img)
{
    amscimglib4_image *img2 = NULL;
    if(img==NULL) return;
    int I,J,K;

    amscimglib4_image_new(&img2,img->sizex,img->sizey);
    amscimglib4_image_copy(img2,img);

    for(K=0;K<4;K++)
    for(I=0;I<img->sizex;I++)
    for(J=0;J<img->sizey;J++)
        img->data[4*(I+img->sizex*J)+K] = img2->data[4*(I+img2->sizex*(img2->sizey-J-1))+K];

    amscimglib4_image_delete(&img2);
    return;
}


AMSCIMGLIB4_API void amscimglib4_readimage(const char *fname, amscimglib4_image *img)
{
  int type = amscimglib4_magic_type(fname);

  if(type==amscimglib4_type_bmp)
  {
    //BMP
    amscimglib4_readimage_bmp(fname,img);
  }
  else if(type==amscimglib4_type_png)
  {
    //PNG
    amscimglib4_readimage_png(fname,img);
  }
  else if(type==amscimglib4_type_jpg)
  {
    //JPEG
    amscimglib4_readimage_jpeg(fname,img);
  }
  else
  {
    printf("amscimglib4readimage: %s: unrecognized file type!\n", fname);
  }
  return;
}

AMSCIMGLIB4_API void amscimglib4_writeimage_select(const char *fname, amscimglib4_image *img, int formatspec)
{
    amscimglib4_image *zeroimg = NULL;
  if(img->sizex>0&&img->sizey>0) //do not write zero size images
  {
    if(formatspec == amscimglib4_type_bmp)
    {
      amscimglib4_writeimage_bmp(fname,img);
    }
    else if(formatspec == amscimglib4_type_png)
    {
      amscimglib4_writeimage_png(fname,img);
    }
    else if(formatspec == amscimglib4_type_jpg)
    {
      amscimglib4_writeimage_jpeg(fname,img,100);
    }
    else
    {
      //default to PNG
      amscimglib4_writeimage_png(fname,img);
    }

  } //do not write zero size images
  else
  {
    amscimglib4_image_new(&zeroimg,1,1);
    if(formatspec == amscimglib4_type_bmp)
    {
      amscimglib4_writeimage_bmp(fname,zeroimg);
    }
    else if(formatspec == amscimglib4_type_png)
    {
      amscimglib4_writeimage_png(fname,zeroimg);
    }
    else if(formatspec == amscimglib4_type_jpg)
    {
      amscimglib4_writeimage_jpeg(fname,zeroimg,100);
    }
    else
    {
      //default to PNG
      amscimglib4_writeimage_png(fname,zeroimg);
    }
    amscimglib4_image_delete(&zeroimg);
  }//do not write zero size images

  return;
}

void amscimglib4_get_extension(const char *fname, char *extension, int bufflen)
{
  int I;
  int len = strlen(fname);
  int ind;

  ind = 0;
  for(I=len;I>=0;I--)
  {
    if(fname[I]=='.')
    {
      ind = I;
      break;
    }
  }

  if(ind>0)
  {
    for(I=ind;I<(len)&&(I-ind)<(bufflen-1);I++)
    {
      extension[I-ind] = fname[I];
    }
    extension[I-ind] = '\0';

  }
  else
  {
    extension[0] = '\0';
  }

  for(I=0;I<strlen(extension);I++)
  {
    extension[I] = tolower(extension[I]);
  }

  return;
}

AMSCIMGLIB4_API void amscimglib4_writeimage(const char *fname, amscimglib4_image *img)
{
  char ext[20];
  amscimglib4_get_extension(fname,ext,20);
  if(strcmp(ext,".png")==0)
  {
    amscimglib4_writeimage_select(fname,img,amscimglib4_type_png);
  }
  else if(strcmp(ext,".bmp")==0)
  {
    amscimglib4_writeimage_select(fname,img,amscimglib4_type_png);
  }
  else if(strcmp(ext,".jpg")==0||strcmp(ext,".jpeg")==0)
  {
    amscimglib4_writeimage_select(fname,img,amscimglib4_type_jpg);
  }
  else
  {
    printf("amscimglib4_writeimage: Warning: %s is unidentified extension. Writing file with default format of PNG.\n",ext);
    amscimglib4_writeimage_select(fname,img,amscimglib4_type_png);
  }

  return;
}

#ifdef __cplusplus
}; //end extern "C"
#endif