#ifndef SREGISTER_H
#define SREGISTER_H

#include <stdint.h>

template <typename T, uint8_t MAX_LENGTH>
class ShiftRegister {
private:
    T data;
    uint8_t length;
    uint8_t position;
    uint8_t mapping[MAX_LENGTH];

public:
    ShiftRegister() : data(0), length(0), position(0) {
        for (uint8_t i = 0; i < MAX_LENGTH; i++) {
            mapping[i] = 0;
        }
    }
    
    ShiftRegister(const int (&_mapping)[MAX_LENGTH]) : data(0), length(0), position(0) {
        for (uint8_t i = 0; i < MAX_LENGTH; i++) {
            mapping[i] = _mapping[i];
        }
    }
    
    uint8_t add(T newData){
        data = (data << 1) | (newData & 1);
        length = length == MAX_LENGTH ? MAX_LENGTH : length + 1;
        return position;
    }

    void map(uint8_t pos, int value) {
        mapping[pos] = value;
    }

    int val() const {
        return mapping[position];
    }

    uint8_t incr() {
        position = (position + 1) % MAX_LENGTH;
        data = (data << 1) | ((data >> (MAX_LENGTH - 1)) & 1);
        return position;
    }

    uint8_t decr() {
        position = (position == 0) ? MAX_LENGTH - 1 : position - 1;
        data = (data >> 1) | ((data & 1) << (MAX_LENGTH - 1));
        return position;
    }

    uint8_t pos() const {
        return position;
    }

    uint8_t reset() {
        data = 0;
        length = 0;
        position = 0;
        return position;
    }

    uint8_t move(int direction, int steps) {
        for (int i = 0; i < steps; i++) {
            if (direction > 0) {
                incr();
            } else if (direction < 0) {
                decr();
            }
        }
        return position;
    }

    bool isEnd() const {
        return position == (length - 1) % MAX_LENGTH;
    }

    ShiftRegister& operator++() {
        incr();
        return *this;
    }

    ShiftRegister& operator--() {
        decr();
        return *this;
    }
};


/*
Write a class, for C++, implementing a shift register
- as template, to specify the type for the storage, eg: int, unsigned int, ...
- implement this methods : incr, decr, position, reset, move(int direction, int steps), isEnd
- let me specify the max. length of the register
- dont use std, at all
- use bit shift operators
- return the current position in all methods, using uint8_t as return type
*/
#endif