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


//
// Instantiate the switch debouncer
//
static eCxx::Debounce8Switch db8sw;


//
// Instantiate the MAX72XX LED matrix driver
//
static eCxx::MAX72XXMatrixDriver max72xx;


//
// Animation-related variables
//

// Uncomment this to test a stacked 16x16 LED matrix instead
// #define TEST_STACKED_16X16

// Create a 16x16 or 32x8 LED matrix
#ifdef TEST_STACKED_16X16
typedef eCxx::ColorFX2D<eCxx::WColor, 16, 16, eCxx::CBP::RInterRowMajorRX, eCxx::CBP::RawBuffer, 0, 0, 8> CFXRawGrayscale;
#else
typedef eCxx::ColorFX2D<eCxx::WColor, 32, 8, eCxx::CBP::RowMajor, eCxx::CBP::RawBuffer, 0, 0, 0> CFXRawGrayscale;
#endif

static CFXRawGrayscale cfx;


//
// Helper functions
//
static void eCxx_user_init_initializeSwitchAndMAX72XXLEDMatrix()
{
    // Set the switch pin as input
    App::setPinMode(INP_SW, App::PinMode::InputPullUp);

    // Initialize the driver
    max72xx.begin( PIN_DATA, PIN_CLOCK, PIN_LATCH, cfx.XElementCount, cfx.YElementCount, cfx.colorBufferData() );

    // Create test content
#ifdef TEST_STACKED_16X16
    for(eCxx::uint8_t x = 0; x < 8; ++x) {
        cfx.setXY(  0 + x,  0, eCxx::WColor( (x == 7) ? 255 : (x + 1) ) );
        cfx.setXY( 15 - x, 15, eCxx::WColor( (x == 7) ? 255 : (x + 1) ) );
    }
    cfx.setXY( 15,  0, eCxx::WColor(255) );
    cfx.setXY(  0, 15, eCxx::WColor(255) );
#else
    for(eCxx::uint8_t x = 0; x < 8; ++x) {
        cfx.setXY(  0 + x, 0, eCxx::WColor( (x == 7) ? 255 : (x + 1) ) );
        cfx.setXY( 31 - x, 0, eCxx::WColor( (x == 7) ? 255 : (x + 1) ) );
        cfx.setXY(  8 + x, 7, eCxx::WColor( (x == 7) ? 255 : (x + 1) ) );
        cfx.setXY( 23 - x, 7, eCxx::WColor( (x == 7) ? 255 : (x + 1) ) );
    }
#endif
}


static void eCxx_user_task_updateMAX72XXLEDMatrixAnimation()
{
    // Process event and delay
    static eCxx::uint32_t prvMillis = 0;
           eCxx::uint32_t curMillis = App::processEvent();
    if(curMillis - prvMillis < 10) return;
    else                           prvMillis = curMillis;

    // Read the switch and change the mode as needed
    static bool extMode = true;

    if( App::digitalRead(INP_SW) ) db8sw.debounce(0b00000000); // The switch is active low
    else                           db8sw.debounce(0b00000001);

    if( db8sw.pressed(0b00000001) ) {
        for(eCxx::uint8_t i = 0; i <= eCxx::MAX72XXMatrixDriver::DefIntensity; ++i) {
            max72xx.setIntensity(eCxx::MAX72XXMatrixDriver::DefIntensity - i);
            App::delayMS(50);
        }
        if(extMode) {
            extMode = false;
            max72xx.update();
        }
        else {
            extMode = true;
            max72xx.updateExt();
        }
        for(eCxx::uint8_t i = 0; i <= eCxx::MAX72XXMatrixDriver::DefIntensity; ++i) {
            max72xx.setIntensity(i);
            App::delayMS(50);
        }
    }

    // Update the LEDs as needed
    static eCxx::uint8_t updateDelayCnt = 0;
    ++updateDelayCnt;
    if(updateDelayCnt < 10) return;
    updateDelayCnt = 0;

    if(extMode) max72xx.updateExt();
    else        max72xx.update   ();
}
