#define F_CPU 8000000UL

#include <stdbool.h>
#include <stdint.h>
#include <avr/io.h>
#include <util/delay.h>
#include "lcd_lib.h"

#define NUM_BUTTONS 7
#define BUTTON_MASK 0x7F

enum MODE {
    PLUS = 0,
    MINUS = 1,
    MULTIPLY = 2,
    DIVIDE = 3
};

int16_t plus(int8_t a, int8_t b)     { return a + b; }

int16_t minus(int8_t a, int8_t b)    { return a - b; }

int16_t multiply(int8_t a, int8_t b) { return a * b; }

int16_t divide(int8_t a, int8_t b)   { return (a * 10) / b; }

int16_t(*ops[])(int8_t, int8_t) = { plus, minus, multiply, divide };

int main(void) {
  DDRD &= ~BUTTON_MASK;
  PORTD |= BUTTON_MASK;

  uint8_t prev_state = 0xFF;  // Initial: all buttons not pressed (HIGH)

  bool reverse = false;
  int8_t a = 0, b = 0;
  int16_t c = 0;
  enum MODE mode = 0;
  char mode_chars[] = {'+', '-', '*', '/'};

  LCDinit();
  LCDGotoXY(0, 0);
  LCDsend2digitNumber(a);
  LCDsendChar((uint8_t)mode_chars[mode]);
  LCDsend2digitNumber(b);

  while (1) {
    uint8_t curr_state = PIND & BUTTON_MASK;

    for (uint8_t bit = 0; bit < NUM_BUTTONS; bit++) {
      uint8_t bit_mask = (1 << bit);
      if ((curr_state & bit_mask) && !(prev_state & bit_mask)) {
        // LCDclr();
        switch (bit) {
          case 2: ++mode; mode %= 4; break;
          case 0: a += reverse ? -10 : 10; break;
          case 1: a += reverse ? -1  : 1;  break;
          case 3: b += reverse ? -10 : 10; break;
          case 4: b += reverse ? -1  : 1;  break;
          case 6: reverse = !reverse; break;
          default: break;
        }
        if (a > 99 || a < -99) a = 0;
        if (b > 99 || b < -99) b = 0;
        LCDGotoXY(0, 0);
        LCDsend2digitNumber(a);
        LCDsendChar((uint8_t)mode_chars[mode]);
        LCDsend2digitNumber(b);
        LCDsendChar((uint8_t)'=');
        if (b == 0 && mode == DIVIDE) LCDstring_P(PSTR("Error"));
        // if (b == 0 && mode == DIVIDE) LCDstring((uint8_t*)"Error");
        else {
          c = ops[mode](a, b); 
          if (c < 0) {
            c *= -1;
            LCDsendChar((uint8_t)'-');
          }
          if (mode == DIVIDE) {
            LCDsendChar((uint8_t)('0' + c / 10000));
          }
          LCDsendChar((uint8_t)('0' + c / 1000 % 10));
          LCDsendChar((uint8_t)('0' + c / 100 % 10));
          LCDsendChar((uint8_t)('0' + c / 10 % 10));
          if (mode == DIVIDE) {
            LCDsendChar((uint8_t)'.');
            LCDsendChar((uint8_t)('0' + c % 10));
          }
          else {
            LCDsendChar((uint8_t)('0' + c % 10));
          }
        }
        if (reverse) {
          LCDGotoXY(0, 1);
          LCDsendChar((uint8_t)'R');
        }
        _delay_ms(20);
      }
    }

    prev_state = curr_state;
    _delay_ms(10);
  }

  return 0;
}

