#include <avr/io.h>
#include <stdbool.h>
#include <util/delay.h>
#include <math.h>
#include "util.h"
#include "7segment.h"

uint8_t display[4] = { 0, 0, 0, 0 };
uint8_t current_digit = 0;

/**
 * Display pins should be mapped like this:
 * a  b  c  d  e  f  g  DP
 * 0  1  2  3  4  5  6  7
 * 
 * 
*/

void display_value(uint8_t digit, uint8_t data) {
    // The left part sets the last 4 bits high (turns the
    // according digit off) except for the one we want to address.
    // The right part makes sure the first 4 bits remain unchanged.
    PORTK = (0b00001111 & ~(1 << digit)) | (PORTK & 0b11110000);

    PORTF = data;
}

void set_display_value(uint8_t digit, uint8_t data) {
    display[digit] = data;
}

void update_next_digit() {
    update_display_digit(current_digit++);
    if (current_digit >= 4) current_digit = 0;
}

void update_display_digit(int digit) {
    display_value(digit, display[digit]);
}

// Returns the amount of microseconds we blocked for
float update_display_all_sync() {
    int sleep_time = 2000;
    for (int i = 0; i < 4; i++) {
        display_value(i, display[i]);
        _delay_us(sleep_time);
    }
    return sleep_time * 4;
}

void show_float(float value) {
    if (value >= 10000 || value < 0) {
        for (int i = 0; i < 4; i++) {
            set_display_value(i, 0b01000000); // minus character
        }
        return;
    }

    int digits = num_digits((int)value);
    int full_number = value * (int)roundf(powf(10, 4 - digits));

    for (int i = 0; i < 4; i++) {
        bool show_period = digits == i + 1;
        int digit = get_digit_at_position(full_number, 3 - i);
        set_display_value(i, digit_to_binary(show_period << 7, digit));
    }
}
