#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <ifl/iflFile.h>

typedef unsigned char uchar;

struct image
{
  int w, h, c;
  uchar *data;
};

struct image openFile(const char *filename)
{
  image ret = {0,0,NULL};

  // open the file named by 'filename'
  iflStatus sts;
  iflFile* file = iflFile::open(filename, O_RDONLY, &sts);
  if (sts != iflOKAY) {
    fprintf(stderr,"Error opening image file %s\n",filename);
    ret.data = NULL;
    return ret;
  }

  // read the entire image (just the first plane in z if image has depth)
  // into a buffer of unsiged chars
  iflSize dims;
  file->getDimensions(dims);

  ret.w = dims.x;
  ret.h = dims.y;
  ret.c = dims.c;
  ret.data = new uchar[dims.x * dims.y * dims.c];
  assert(ret.data);

  iflConfig cfg(iflUChar, iflInterleaved);
  sts = file->getTile(0, 0, 0, dims.x, dims.y, 1, ret.data, &cfg);

  if (sts != iflOKAY) {
    fprintf(stderr,"Error reading image file %s\n",filename);
    delete ret.data;
    ret.data = NULL;
  }

  // close the file
  file->close();

  return ret;
}

void writePPM(const char *filename, image img)
{
  FILE *out = fopen(filename, "w");
  if (!out) {
    fprintf(stderr,"Unable to create file %s\n",filename);
    return;
  }

  fprintf(out,"P6 %d %d 255\n",img.w,img.h);

  for (int i=0; i<img.w*img.h*img.c; i++) {
    /* dest = img.c*img.w*y + img.c*x + z */
    /* source = img.c*img.w*(img.h-y) + img.c*x + z */

    putc(img.data[3*img.w*(img.h-(i/(img.c*img.w))) + i%(img.c*img.w)],
	 out);
  }

  fclose(out);
  return;
}

void writeRAW(const char *filename, image img)
{
  FILE *out = fopen(filename, "w");
  if (!out) {
    fprintf(stderr,"Unable to create file %s\n",filename);
    return;
  }

  for (int i=0; i<img.w*img.h*img.c; i++) {
    /* dest = img.c*img.w*y + img.c*x + z */
    /* source = img.c*img.w*(img.h-y) + img.c*x + z */

    putc(img.data[3*img.w*(img.h-(i/(img.c*img.w))) + i%(img.c*img.w)],
	 out);
  }

  fclose(out);
  return;
}

int main(int argc, char *argv[])
{
  const char *file_in = NULL, *file_out = NULL;
  int make_raw = 0, usage_error = 0;

  for (int i=1; i<argc && !usage_error; i++) {
    if (!strcmp(argv[i],"-raw")) make_raw = 1;
    else if (!file_in) file_in = argv[i];
    else if (!file_out) file_out = argv[i];
    else usage_error = 1;
  }

  if (!file_in || !file_out || usage_error) {
    fprintf(stderr,"Usage:\n\t%s [-raw] <input_file> <output_file>\n\n",
            argv[0]);
    return -1;
  }

  image img = openFile(file_in);

  if (img.data) {
    /* Do something */
    printf("Image read:\n\twidth: %d\n\theight: %d\n\tcolor depth: %d\n",
	   img.w,img.h,img.c);

    if (make_raw) writeRAW(file_out,img);
    else writePPM(file_out,img);

    delete img.data;
    img.data = NULL;
  }

  return 0;
}

