#include "Shield_MultiFunction.h"

// Segment Maps (Active Low)
const uint8_t SEGMENT_SELECT[] = {0xF1, 0xF2, 0xF4, 0xF8};
const uint8_t SEGMENT_MAP_DIGIT[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};

Shield_MultiFunction::Shield_MultiFunction() : 
  btn1(A1), btn2(A2), btn3(A3), _lastDisplayUpdate(0), _currentDigit(0),
  _buzzerTurnOffTime(0), _buzzerToneActive(false) {
  clearDisplay();
}

void Shield_MultiFunction::begin() {
  // LEDs (13, 12, 11, 10)
  for(int i=10; i<=13; i++) {
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH); // HIGH = AUS bei diesem Shield
  }
  
  // Buzzer (3)
  pinMode(_buzzerPin, OUTPUT);
  digitalWrite(_buzzerPin, HIGH); // HIGH = AUS

  // Display Shift Register
  pinMode(_latchPin, OUTPUT);
  pinMode(_clkPin, OUTPUT);
  pinMode(_dataPin, OUTPUT);

  // Buttons initialisieren
  btn1.begin();
  btn2.begin();
  btn3.begin();
}

void Shield_MultiFunction::update() {
  // 1. Taster aktualisieren
  btn1.update();
  btn2.update();
  btn3.update();

  // 2. Display Multiplexing (alle 4000 Mikrosekunden = 4ms pro Ziffer -> flimmerfrei)
  if (micros() - _lastDisplayUpdate > 4000) {
    _lastDisplayUpdate = micros();
    
    _writeDigit(_currentDigit, _displayMemory[_currentDigit]);
    
    _currentDigit++;
    if (_currentDigit > 3) _currentDigit = 0;
  }

  // 3. Buzzer abschalten, wenn die Zeit abgelaufen ist
  if (_buzzerToneActive && millis() >= _buzzerTurnOffTime) {
    noTone(_buzzerPin);
    digitalWrite(_buzzerPin, HIGH); // Zwingt den Pin auf AUS (Active-Low)
    _buzzerToneActive = false;
  }
}

// --- LEDs ---
void Shield_MultiFunction::setLED(uint8_t ledNum, bool state) {
  uint8_t pin = 14 - ledNum; // D1=13, D2=12, D3=11, D4=10
  if(pin >= 10 && pin <= 13) {
    digitalWrite(pin, !state); // Invertiert, da Low-Aktiv
  }
}

void Shield_MultiFunction::setLEDPWM(uint8_t ledNum, uint8_t value) {
  uint8_t pin = 14 - ledNum;
  if(pin == 11 || pin == 10) { // Nur D3 und D4 können PWM
    analogWrite(pin, 255 - value); // Invertiertes PWM
  }
}

// --- Buzzer ---
void Shield_MultiFunction::setBuzzer(bool state) {
  noTone(_buzzerPin); // Falls ein Ton lief, abwürgen
  _buzzerToneActive = false;
  digitalWrite(_buzzerPin, !state);
}

void Shield_MultiFunction::playTone(uint16_t freq, uint32_t ms) {
  tone(_buzzerPin, freq); // Kein ms-Parameter für die Arduino-Funktion
  _buzzerTurnOffTime = millis() + ms;
  _buzzerToneActive = true;
}

// --- Poti ---
uint16_t Shield_MultiFunction::readPoti() {
  return analogRead(A0);
}

// --- Display ---
void Shield_MultiFunction::showNumber(int num) {
  if (num > 9999 || num < -999) {
    showWord('E', 'R', 'R', ' '); // Overflow Error
    return;
  }
  
  clearDisplay(); // Array mit 0xFF (Leer) füllen
  
  bool isNegative = (num < 0);
  if (isNegative) num = -num;
  
  if (num == 0) {
    _displayMemory[3] = SEGMENT_MAP_DIGIT[0];
    return;
  }

  uint8_t idx = 3;
  while (num > 0 && idx < 4) { // idx ist unsigned, also Trick mit Abbruchbedingung < 4 nutzen (overflow nach 0)
    _displayMemory[idx] = SEGMENT_MAP_DIGIT[num % 10];
    num /= 10;
    idx--;
  }
  
  if (isNegative && idx < 4) {
    _displayMemory[idx] = 191; // Minus-Zeichen
  }
}

void Shield_MultiFunction::showWord(char c1, char c2, char c3, char c4) {
  _displayMemory[0] = _charToSegment(c1);
  _displayMemory[1] = _charToSegment(c2);
  _displayMemory[2] = _charToSegment(c3);
  _displayMemory[3] = _charToSegment(c4);
}

void Shield_MultiFunction::clearDisplay() {
  for(int i=0; i<4; i++) {
    _displayMemory[i] = 255; // 255 = Alle Segmente aus
  }
}

void Shield_MultiFunction::_writeDigit(uint8_t digit, uint8_t value) {
  digitalWrite(_latchPin, LOW);
  shiftOut(_dataPin, _clkPin, MSBFIRST, value); 
  shiftOut(_dataPin, _clkPin, MSBFIRST, SEGMENT_SELECT[digit]);
  digitalWrite(_latchPin, HIGH);
}

uint8_t Shield_MultiFunction::_charToSegment(char c) {
  // Stark vereinfachter ASCII zu 7-Segment Konverter für unsere Dropdowns
  switch (c) {
    case 'A': case 'a': return 136;
    case 'B': case 'b': return 131;
    case 'C':           return 167;
    case 'c':           return 167; 
    case 'D': case 'd': return 161;
    case 'E': case 'e': return 134;
    case 'F': case 'f': return 142;
    case 'H': case 'h': return 137;
    case 'I': case 'i': return 249;
    case 'L': case 'l': return 199;
    case 'O': case 'o': return 163;
    case 'P': case 'p': return 140;
    case 'S': case 's': return 146;
    case 'U': case 'u': return 193;
    case '-':           return 191;
    default:            return 255; // Leerzeichen oder Unbekannt
  }
}