/**************************************************************************
 *{@C
 *      Copyright:      1988-2024 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         FileFormats
 *      Filename:       FF_ImageRaw.c
 *
 *      Author:         Paul Obermeier
 *
 *      Description:    The file format dependent layer of the image file
 *                      format library: Functions to read and write
 *                      files in a simple raw image file format.
 *
 * The following image types are currently supported:
 *
 * Grayscale image:  1 channel  of 32-bit floating point values.
 * True-color image: 3 channels of 32-bit floating point values.
 *
 * There are 2 supported file formats:
 * One with the binary raw data only, the other with a 7 line ASCII
 * header of the following form:
 *
 *     Magic=RAW                File format identifier. Fixed value.
 *     Width=172                Image width in pixels.
 *     Height=181               Image height in pixels.
 *     NumChan=1                Possible values: 1.
 *     ByteOrder=Intel          Possible values: "Intel" or "Motorola".
 *     ScanOrder=TopDown        Possible values: "TopDown" or "BottomUp".
 *     PixelType=float          Possible values: "float", "short", "byte".
 *
 *     Each ASCII header line is exactly 20 bytes long (including the newline).
 *     If necessary, spaces are added between the value and the newline 
 *     character. Thus these files can easily be read by external tools like
 *     MatLab by skipping 140 bytes and then read in the pure data.
 *
 *      Additional documentation:
 *                      None.
 *
 *      Exported functions:
 *                      FF_ImgOpenWriteRaw
 *                      FF_ImgOpenReadRaw
 *
 **************************************************************************/

#include <stdio.h>
#include <string.h>

#include "UT_Compat.h"
#include "UT_Error.h"
#include "UT_Portable.h"
#include "UT_Memory.h"
#include "UT_FileIO.h"

#include "FF_Image.h"
#include "FF_ImagePrivate.h"
#include "FF_ImageRaw.h"

/* Format dependent pixel file descriptor */

typedef struct {
    FILE  *fp;                  /* C standard I/O file descriptor */
    FF_ImgChanType chanType;    /* Channel to read or write. */
} rawImgFile;

static void writeClose (FF_ImgFileDesc * px_f)
{
    rawImgFile *spf;

    spf = ((pixfile *) px_f->pixprivate)->fmtprivate;
    if (spf) {
        UT_FileClose (spf->fp);
        UT_MemFree (spf);
    }
    return;
}

static UT_Bool writeScan (FF_ImgFileDesc *px_f, Int32 y)
{
    Int32 chn;
    pixfile *pf;
    rawImgFile *spf;

    pf = px_f->pixprivate;
    spf = pf->fmtprivate;
    chn = spf->chanType;

    switch (px_f->channel[chn]) {
        case FF_ImgFmtTypeUByte: {
            UInt8 *pixBuf = pf->buf[chn].ubytes;
            if (!UT_ImgRawWriteUInt8Scan (spf->fp, pixBuf,
                                          px_f->desc.width)) {
                return UT_False;
            }
            break;
        }
        case FF_ImgFmtTypeFloat: {
            Float32 *pixBuf = pf->buf[chn].floats;
            if (!UT_ImgRawWriteFloat32Scan (spf->fp, pixBuf,
                                            px_f->desc.width)) {
                return UT_False;
            }
            break;
        }
        default: {
            UT_ErrFatal ("FF_ImgOpenWriteRaw", "unknown pixel format");
        }
    }
    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           FF_ImgOpenWriteRaw
 *
 *      Usage:          Open a RAW pixel file for writing.
 *
 *      Synopsis:       UT_Bool FF_ImgOpenWriteRaw
 *                              (const char *name, FF_ImgFileDesc *px_f)
 *
 *      Description:    RAW pixel file "name" is opened for writing.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:       FF_ImgOpenReadRaw
 *
 ***************************************************************************/

UT_Bool FF_ImgOpenWriteRaw (const char *name, FF_ImgFileDesc *px_f)
{
    FF_ImgChanType chanType;
    pixfile *pf;
    rawImgFile *spf;
    FILE *fp;

    UT_Bool topDown = UT_False;

    if (!FF_ImgGetChanType (px_f->version, &chanType)) {
        return UT_False;
    }
    if (!px_f->channel[(UInt32)chanType]) {
        printf ("ERROR: Channel %d not available in image\n", chanType);
        return UT_False;
    }
    if (!(spf = UT_MemPerm (rawImgFile))) {
        return UT_False;
    }

    if (!(fp = UT_FileOpen (name, "wb"))) {
        return UT_False;
    }
    spf->fp = fp;
    spf->chanType = chanType;
    ((pixfile *) px_f->pixprivate)->fmtprivate = spf;

    switch (px_f->channel[(UInt32)chanType]) {
        case FF_ImgFmtTypeUByte: {
            if (!UT_ImgRawWriteUInt8Header (fp, px_f->desc.width,
                                            px_f->desc.height, 1, topDown)) {
                UT_FileClose (fp);
                return UT_False;
            }
            break;
        }
        case FF_ImgFmtTypeFloat: {
            if (!UT_ImgRawWriteFloat32Header (fp, px_f->desc.width,
                                              px_f->desc.height, 1, topDown)) {
                UT_FileClose (fp);
                return UT_False;
            }
            break;
        }
        default: {
            UT_ErrFatal ("FF_ImgOpenWriteRaw", "unknown pixel format");
        }
    }

    /* Initialize the FF_ImgFileDesc. */
    pf = px_f->pixprivate;
    pf->readscan = NULL;
    pf->writescan = writeScan;
    pf->close = writeClose;
    px_f->scanorder = FF_ImgOrderTypeBottomUp;

    return UT_True;
}

/***************************************************************************
 *[@e
 *      Name:           FF_ImgOpenReadRaw
 *
 *      Usage:          Open a raw pixel file for reading.
 *
 *      Synopsis:       UT_Bool FF_ImgOpenReadRaw
 *                              (const char *name,
 *                              FF_ImgFileDesc *px_f)
 *
 *      Description:    Raw pixel file "name" is opened for reading.
 *
 *                      Only FF_ImgChanTypeRed, FF_ImgChanTypeGreen,
 *                      FF_ImgChanTypeBlue and FF_ImgChanTypeMatte channel
 *                      types are supported.
 *
 *      Return value:   UT_True if successful, else UT_False.
 *
 *      See also:       FF_ImgOpenWriteRaw
 *
 ***************************************************************************/

UT_Bool FF_ImgOpenReadRaw (const char *name, FF_ImgFileDesc *px_f)
{
    return UT_False;
#if OPA_TODO
    FILE *fp;
    pixfile *pf;
    RAWHEADER rawHeader;
    RAWFILE  *rf;
    UT_MemState memstate;
    Int32 chn;

    memstate = UT_MemRemember ();
    pf = px_f->pixprivate;
    if (!(rf = UT_MemTemp (RAWFILE))) {
        UT_MemRestore (memstate);
        return UT_False;
    }

    if (!(fp = UT_FileOpen (name, "rb"))) {
        return UT_False;
    }

    if (!readHeader (file, name, px_f, &rawHeader)) {
        UT_FileClose (file);
        return UT_False;
    }

    for (chn=0; chn<FF_NumImgChanTypes; chn++) {
        if (px_f->channel[chn] == FF_ImgFmtTypeFloat) {
            if (!(rf->rawbuf[chn] = UT_MemTempArray (px_f->desc.width, Float32))) {
                UT_MemRestore (memstate);
                UT_FileClose (fp);
                return UT_False;
            }
        }
    }

    /* Fill in the "pixfile". */
    pf->fmtprivate = rf;
    pf->readscan   = rawReadScan;
    pf->close      = rawClose;

    /* Fill in the "RAWFILE". */
    rf->rh = rawHeader;
    rf->fp = fp;
    UT_MemSave (memstate);
    return UT_True;
#endif
}
