#include <iostream>


template <typename T, uint8_t MAX_LENGTH>
class ShiftRegister {
private:
    T data;        // Underlying storage
    uint8_t length; // Actual length of data in the _register
    uint8_t position; // Current position
    int mapping[MAX_LENGTH]; // Array for position-to-integer mapping

public:
    // Constructor (initialize with zero and mapping)
    ShiftRegister() : data(0), length(0), position(0) {
        for (uint8_t i = 0; i < MAX_LENGTH; i++) {
            mapping[i] = i; // Default mapping: position to itself
        }
    }

    //add data
    uint8_t add(T newData) {
        //add the data
        data = (data << 1) | (newData & 1);
        //increase length, but not over the MAX_LENGTH
        length = length == MAX_LENGTH ? MAX_LENGTH : length + 1;
        return position;
    }

    // Set the mapping for a specific position
    void setMapping(uint8_t pos, int value) {
        mapping[pos] = value;
    }

    // Get the mapped integer for the current position
    int getMappedValue() const {
        return mapping[position];
    }

    // Increase the position, wrap around if necessary, shift data
    uint8_t increase() {
        position = (position + 1) % MAX_LENGTH;
        data = (data << 1) | ((data >> (MAX_LENGTH - 1)) & 1); // Shift left with wrap-around
        return position;
    }

    // Decrease the position, wrap around if necessary, shift data
    uint8_t decrease() {
        position = (position == 0) ? MAX_LENGTH - 1 : position - 1;
        data = (data >> 1) | ((data & 1) << (MAX_LENGTH - 1)); // Shift right with wrap-around
        return position;
    }

    // Get the current position
    uint8_t getPosition() const {
        return position;
    }

    // Reset the _register (clear data and position)
    uint8_t reset() {
        data = 0;
        length = 0;
        position = 0;
        return position;
    }

    // Move the position by a specified number of steps in a direction
    uint8_t move(int direction, int steps) {
        for (int i = 0; i < steps; i++) {
            if (direction > 0) {
                increase();
            }
            else if (direction < 0) {
                decrease();
            }
        }
        return position;
    }

    // Check if the position is at the end
    bool isEnd() const {
        return position == (length - 1) % MAX_LENGTH; // Handle wrapping
    }

    // Overload ++ operator for incrementing position
    ShiftRegister& operator++() {
        increase();
        return *this;
    }

    // Overload -- operator for decrementing position
    ShiftRegister& operator--() {
        decrease();
        return *this;
    }
};

#include <iostream> 

// (Include your ShiftRegister class header here)

int main() {
    using namespace std;
    const uint8_t MAX_LENGTH = 4;

    // Create a shift _register with a specific length
    ShiftRegister<int, MAX_LENGTH> _register;

    // Set up a custom mapping
    _register.setMapping(0, 100);
    _register.setMapping(1, 101);
    _register.setMapping(2, 102);
    _register.setMapping(3, 103);

    cout << "Shift Register CLI Example" << endl;

    char command;
    while (true) {
        cout << "Enter command (a: add, +: increase, -: decrease, r: reset, m: move, p: print, e: exit): ";
        cin >> command;

        switch (command) {
        case 'a': {
            unsigned int value;
            cout << "Enter value to add: ";
            cin >> value;
            _register.add(value);
            break;
        }

        case '+':
            ++_register;
            break;

        case '-':
            --_register;
            break;

        case 'r':
            _register.isEnd();
            break;

        case 'm': {
            int direction, steps;
            cout << "Enter direction (1: forward, -1: backward): ";
            cin >> direction;
            cout << "Enter number of steps: ";
            cin >> steps;
            _register.move(direction, steps);
            break;
        }

        case 'p':
            cout << "Position: " << (int)_register.getPosition()
                << ", Mapped Value: " << _register.getMappedValue() << endl;
            break;
        case 'e':
            return 0;
        default:
            cout << "Invalid command" << endl;
        }
    }
}
