#include "Row.h"

/* constructor
init() is called once for each row, to set scanner's uC strobePin to output.
*/
Row::Row(ScannerInterface& refScanner, const uint8_t strobePin,
         Key* const ptrsKeys[], const uint8_t keyCount)
    : refScanner(refScanner), strobePin(strobePin),
      ptrsKeys(ptrsKeys), keyCount(keyCount), debounced(0)
{
    refScanner.init(strobePin);
}

/* process() scans the row and calls any newly pressed or released keys.
Bit pattern variables are 1 bit per key.
*/
void Row::process()
{
    read_pins_t readState;                      //bits, 1 means key is pressed, 0 means released
    read_pins_t debouncedChanged;               //bits, 1 means debounced changed

    readState = refScanner.scan(strobePin);
    debouncedChanged = debouncer.debounce(readState, debounced);
    send(keyCount, debouncedChanged);
}

/*
send() calls key's press() or release() function if key was pressed or released.
Parameter debouncedChanged is bit a pattern.
*/
void Row::send(const uint8_t keyCount, const read_pins_t debouncedChanged)
{
    read_pins_t isFallingEdge;                  //bits, 1 means falling edge
    read_pins_t isRisingEdge;                   //bits, 1 means rising edge
    read_pins_t readPosition;                   //bits, active bit is 1
    uint8_t i;                                  //index for ptrsKeys[i] array

    //bit=1 if last debounced changed from 1 to 0, else bit=0
    isFallingEdge = debouncedChanged & ~debounced;

    //bit=1 if last debounced changed from 0 to 1, else bit=0
    isRisingEdge = debouncedChanged & debounced;

    for (readPosition=1, i=0; i < keyCount; readPosition<<=1, i++) //for each key in row
    {
        //release before press avoids impossible key sequence
        if (readPosition & isFallingEdge)       //if key was released
        {
            ptrsKeys[i]->release();
        }

        if (readPosition & isRisingEdge)        //if key was pressed
        {
            ptrsKeys[i]->press();
            keyWasPressed();
        }
    }
}

void Row::keyWasPressed()
{
    //empty in Row class.  To unstick sticky keys, override keyWasPressed() in derived Row class.
}
