/* Panorama_Tools       -       Generate, Edit and Convert Panoramic Images
   Copyright (C) 1998,1999 - Helmut Dersch  der@fh-furtwangen.de
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License along
   with this program; if not, see <https://www.gnu.org/licenses/>.  */

/*------------------------------------------------------------*/

// Functions to read and write ppm format


#include "filter.h"
#include "metadata.h"
#include "file.h"

static int readPPMFileHeader(file_spec src, Image * im);


// image is allocated, but not image data

int readPPM(Image * im, fullPath * sfile)
{
    file_spec src;
    size_t count;

    if (myopen(sfile, read_bin, src))
    {
        PrintError("Error Opening Image File");
        return -1;
    }


    if (readPPMFileHeader(src, im) != 0)
    {
        PrintError("Error Reading File Header");
        myclose(src);
        return -1;
    }

    im->bitsPerPixel = 24;
    im->bytesPerLine = im->width * 3;
    im->dataSize = im->bytesPerLine * im->height;

    im->data =
        (unsigned char **) mymalloc((size_t) (im->width * im->height * 4));
    if (im->data == NULL)
    {
        PrintError("Not enough memory");
        myclose(src);
        return -1;
    }

    count = (size_t) (im->width * im->height * 3);

    myread(src, count, *(im->data));

    if (count != im->width * im->height * 3)
    {
        PrintError("Error Reading Image Data");
        myclose(src);
        return -1;
    }

    myclose(src);
    ThreeToFourBPP(im);
    return 0;
}


static int readPPMFileHeader(file_spec src, Image * im)
{
    int i;
    char smallBuf[32], c;
    size_t count = 1;

    /* read the file header (including height and width) */

    im->height = -1;
    while (im->height == -1)
    {
        myread(src, count, &c);
        if (count != 1)
            return 1;
        switch (c)
        {
        case '#':
            /* comment line -- skip it */
            while (c != 0x0A && c != 0x0D && count == 1)
                myread(src, count, &c);
            break;
        case ' ':
        case '\012':
        case '\t':
        case '\015':
            /* random whitespace... just ignore it. */
            break;
        case 'P':
            /* magic number */
            myread(src, count, &c);
            if (c != '6')
            {
                PrintError("Bad magic number in input file");
                return (-1);
            }
            /* there should be one whitespace character */
            break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            /* read width */
            for (i = 0; isdigit(c) && (i + 1 < sizeof(smallBuf)); i++)
            {
                smallBuf[i] = c;
                myread(src, count, &c);
                if (count != 1)
                    return -1;
            }
            if (!isspace(c))
            {
                PrintError("Bad input file format");
                return -1;
            }
            smallBuf[i] = 0;
            im->width = atoi(smallBuf);
            /* read height */
            myread(src, count, &c);
            if (count != 1)
                return -1;
            for (i = 0; isdigit(c) && (i + 1 < sizeof(smallBuf)); i++)
            {
                smallBuf[i] = c;
                myread(src, count, &c);
                if (count != 1)
                    return -1;
            }
            if (!isspace(c))
            {
                PrintError("Bad input file format");
                return -1;
            }
            smallBuf[i] = 0;
            im->height = atoi(smallBuf);
            /* read numColors */
            myread(src, count, &c);
            if (count != 1)
                return -1;
            for (i = 0; isdigit(c) && (i + 1 < sizeof(smallBuf)); i++)
            {
                smallBuf[i] = c;
                myread(src, count, &c);
                if (count != 1)
                    return -1;
            }
            if (!isspace(c))
            {
                PrintError("Bad input file format");
                return -1;
            }
            smallBuf[i] = 0;
            if (atoi(smallBuf) != 255)
                PrintError("Warning: Wrong Colordepth!");
            break;
        default:
            PrintError("Bad input file format");
            return (-1);
            break;
        }
    }

    /* the header has been taken care of.  The rest of the file is just image data. */
    return (0);
}



int writePPM(Image * im, fullPath * sfile)
{
    char header[30];
    size_t count;
    file_spec fnum;
    int y, cy, cpy;
    unsigned char *data;



    if (myopen(sfile, write_bin, fnum))
    {
        PrintError("Error Writing Image File");
        return -1;
    }

    if (im->bitsPerPixel == 32)
        FourToThreeBPP(im);

    if (im->bytesPerLine != im->width * 3)      // Eliminate Pad bytes
    {
        data = *(im->data);
        for (y = 0; y < im->height; y++)
        {
            cy = im->height * im->bytesPerLine;
            cpy = im->height * im->width * 3;

            memcpy(data + cpy, data + cy, (size_t) (im->width * 3));
        }
        im->bytesPerLine = im->width * 3;
        im->dataSize = im->height * im->bytesPerLine;
    }


    snprintf(header, sizeof(header)-1, "P6\n%d %d\n%ld\n", im->width,
            im->height, 255L);

    count = strlen(header);
    mywrite(fnum, count, header);

    if (count != strlen(header))
    {
        PrintError("Error writing file header");
        return -1;
    }

    count = im->dataSize;
    mywrite(fnum, count, *(im->data));

    if (count != im->dataSize)
    {
        PrintError("Error writing image data");
        return -1;
    }

    myclose(fnum);
    return 0;
}


int panoPPMRead(Image * im, fullPath * sfile)
{
  if (readPPM(im, sfile) == 0) {
      return panoMetadataUpdateFromImage(im);
  } else
      return FALSE;
}
