/*
 * Copyright (C) 2020-2021 Aloysius Indrayanto
 *
 * This file is part of the eCxx library, see LICENSE file for the license details.
 */


#ifndef ECXX_PLATFORM_X86_LED_SIMULATOR_SDF_1D_H
#define ECXX_PLATFORM_X86_LED_SIMULATOR_SDF_1D_H


namespace eCxx {


//
// For convenience
//
using SDFFile = FILE*;


//
// Internal helper functions
//
static inline SDFFile __beginSDF_XD_RowMajor_impl(
    const char* fileName,    // Name of the simulation data file
    uint16_t    xPixelCount, // The number of X pixels
    uint16_t    yPixelCount, // The number of Y pixels
    const char* colorType,   // Color type
    uint8_t     frameDelay,  // Frame delay in multiple of 10 mS
    int16_t     exitDelay    // < 0 : loop mode ; >= 0 : no loop mode with the specified exit delay
)
{
    // Open the file for writing
    SDFFile h = fopen(fileName, "wb");

    // Write the specifications (see "tools/src/LEDSimulator_SDF_Format.txt" for more details)
                       fprintf( h, "RowMajor\n"                     ); // Memory layout
                       fprintf( h, "%s\n", colorType                ); // Color type
                       fprintf( h, "%d\n", (int) xPixelCount        ); // The number of X pixels (columns)
                       fprintf( h, "%d\n", (int) yPixelCount        ); // The number of Y pixels (rows)
                       fprintf( h, "0\n"                            ); // LED size (0 = default)
                       fprintf( h, "%d\n", (int) frameDelay         ); // Frame delay - in multiple of 10 mS
    if(exitDelay >= 0) fprintf( h, "noloop %d\n\n", (int) exitDelay ); // Loop mode - no loop
    else               fprintf( h, "loop\n\n"                       ); // Loop mode - loop

    // Return the handle
    return h;
}


template <typename colorFX1D_T>
static inline SDFFile __beginSDF_1D_RowMajor_impl(
    const char*        fileName,   // Name of the simulation data file
    const colorFX1D_T& colorFX1D,  // ColorFX1D<T> instance that will be used to generate the simulation data
    const char*        colorType,  // Color type
    uint8_t            frameDelay, // Frame delay in multiple of 10 mS
    int16_t            exitDelay   // < 0 : loop mode ; >= 0 : no loop mode with the specified exit delay
)
{
    eCxx::ignoreUnused(colorFX1D);

    return __beginSDF_XD_RowMajor_impl(
        fileName,
        colorFX1D_T::BufferElementCount,
        1,
        colorType,
        frameDelay,
        exitDelay
    );
}


//
// Helper functions to generate simulation data files for 1-dimensional LED simulation
//
template <typename colorFX1D_T>
static inline SDFFile beginSDF_1D_RowMajor_HSV(
    const char*        fileName,   // Name of the simulation data file
    const colorFX1D_T& colorFX1D,  // ColorFX1D<T> instance that will be used to generate the simulation data
    uint8_t            frameDelay, // Frame delay in multiple of 10 mS
    int16_t            exitDelay   // < 0 : loop mode ; >= 0 : no loop mode with the specified exit delay
)
{ return __beginSDF_1D_RowMajor_impl(fileName, colorFX1D, "HSV", frameDelay, exitDelay); }


template <typename colorFX1D_T>
static inline SDFFile beginSDF_1D_RowMajor_HSL(
    const char*        fileName,   // Name of the simulation data file
    const colorFX1D_T& colorFX1D,  // ColorFX1D<T> instance that will be used to generate the simulation data
    uint8_t            frameDelay, // Frame delay in multiple of 10 mS
    int16_t            exitDelay   // < 0 : loop mode ; >= 0 : no loop mode with the specified exit delay
)
{ return __beginSDF_1D_RowMajor_impl(fileName, colorFX1D, "HSL", frameDelay, exitDelay); }


template <typename colorFX1D_T>
static inline SDFFile beginSDF_1D_RowMajor_W(
    const char*        fileName,   // Name of the simulation data file
    const colorFX1D_T& colorFX1D,  // ColorFX1D<T> instance that will be used to generate the simulation data
    uint8_t            frameDelay, // Frame delay in multiple of 10 mS
    int16_t            exitDelay   // < 0 : loop mode ; >= 0 : no loop mode with the specified exit delay
)
{ return __beginSDF_1D_RowMajor_impl(fileName, colorFX1D, "W", frameDelay, exitDelay); }


template <typename colorFX1D_T>
static inline SDFFile beginSDF_1D_RowMajor_RGB(
    const char*        fileName,   // Name of the simulation data file
    const colorFX1D_T& colorFX1D,  // ColorFX1D<T> instance that will be used to generate the simulation data
    uint8_t            frameDelay, // Frame delay in multiple of 10 mS
    int16_t            exitDelay   // < 0 : loop mode ; >= 0 : no loop mode with the specified exit delay
)
{ return __beginSDF_1D_RowMajor_impl(fileName, colorFX1D, "RGB", frameDelay, exitDelay); }


template <typename colorFX1D_T>
static inline SDFFile beginSDF_1D_RowMajor_RGBW(
    const char*        fileName,   // Name of the simulation data file
    const colorFX1D_T& colorFX1D,  // ColorFX1D<T> instance that will be used to generate the simulation data
    uint8_t            frameDelay, // Frame delay in multiple of 10 mS
    int16_t            exitDelay   // < 0 : loop mode ; >= 0 : no loop mode with the specified exit delay
)
{ return __beginSDF_1D_RowMajor_impl(fileName, colorFX1D, "RGBW", frameDelay, exitDelay); }


template <typename colorFX1D_T>
static inline void writeSDF_1D_HSV(SDFFile h, const colorFX1D_T& colorFX1D)
{
    // Write the frame color data (each line is one pixel)
    for(typename colorFX1D_T::BufferSizeType i = 0; i < colorFX1D_T::BufferElementCount; ++i) {
        const HSVColor& color = colorFX1D.get(i);
        fprintf( h, "%d,%d,%d\n", (int) color.h(), (int) color.s(), (int) color.v() );
    }

    // Add a new line for frame separator
    fprintf( h, "\n" );
}


template <typename colorFX1D_T>
static inline void writeSDF_1D_HSL(SDFFile h, const colorFX1D_T& colorFX1D)
{
    // Write the frame color data (each line is one pixel)
    for(typename colorFX1D_T::BufferSizeType i = 0; i < colorFX1D_T::BufferElementCount; ++i) {
        const HSLColor& color = colorFX1D.get(i);
        fprintf( h, "%d,%d,%d\n", (int) color.h(), (int) color.s(), (int) color.l() );
    }

    // Add a new line for frame separator
    fprintf( h, "\n" );
}


template <typename colorFX1D_T>
static inline void writeSDF_1D_W(SDFFile h, const colorFX1D_T& colorFX1D)
{
    // Write the frame color data (each line is one pixel)
    for(typename colorFX1D_T::BufferSizeType i = 0; i < colorFX1D_T::BufferElementCount; ++i) {
        const WColor& color = colorFX1D.get(i);
        fprintf( h, "%d\n", (int) color.w() );
    }

    // Add a new line for frame separator
    fprintf( h, "\n" );
}


template <typename colorFX1D_T>
static inline void writeSDF_1D_RGB(SDFFile h, const colorFX1D_T& colorFX1D)
{
    // Write the frame color data (each line is one pixel)
    for(typename colorFX1D_T::BufferSizeType i = 0; i < colorFX1D_T::BufferElementCount; ++i) {
        const RGBColor& color = colorFX1D.get(i);
        fprintf( h, "%d,%d,%d\n", (int) color.r(), (int) color.g(), (int) color.b() );
    }

    // Add a new line for frame separator
    fprintf( h, "\n" );
}


template <typename colorFX1D_T>
static inline void writeSDF_1D_RGBW(SDFFile h, const colorFX1D_T& colorFX1D)
{
    // Write the frame color data (each line is one pixel)
    for(typename colorFX1D_T::BufferSizeType i = 0; i < colorFX1D_T::BufferElementCount; ++i) {
        const RGBWColor& color = colorFX1D.get(i);
        fprintf( h, "%d,%d,%d,%d\n", (int) color.r(), (int) color.g(), (int) color.b(), (int) color.w() );
    }

    // Add a new line for frame separator
    fprintf( h, "\n" );
}


static inline void endSDF(SDFFile h)
{ fclose(h); }


static inline void execSDF(const char* fileName)
{
    char cmd[1024];
    snprintf(cmd, sizeof(cmd), "java -jar tools/LEDSimulator.jar %s", fileName);

    system(cmd);
}


} // namespace eCxx


#endif
