#include <LiquidCrystal_I2C.h>
#include <Encoder.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "LcdBarGraphX.h"

#define TEMP_SENSORS 4
#define TEMP_UPDATE_INTERVAL 1000

LiquidCrystal_I2C lcd(0x27, 20, 4);
LcdBarGraphX lbg(&lcd, 20, 0, 0);
Encoder encoder(2, 3);

OneWire ds18x20[TEMP_SENSORS] = {4, 5, 6, 7};
DallasTemperature tempSensors[TEMP_SENSORS];
float temperatureValues[TEMP_SENSORS];

int pwmValue = 0;
unsigned long lastTempUpdateTime = 0;

void handleEncoder()
{
    static long oldPosition = 0;

    long newPosition = encoder.read() / 4;
    if (newPosition != oldPosition)
    {
        pwmValue += newPosition - oldPosition;
        pwmValue = constrain(pwmValue, 0, 100);
        oldPosition = newPosition;

        analogWrite(9, (255 * pwmValue) / 100);

        updateDisplay();
    }
}

void updateTemperature()
{
    for (int i = 0; i < TEMP_SENSORS; i++)
    {
        tempSensors[i].requestTemperatures();
    }

    for (int i = 0; i < TEMP_SENSORS; i++)
    {
        temperatureValues[i] = tempSensors[i].getTempCByIndex(0);
    }
}

void insertStringAt(String& input, String data, int pos, bool clear)
{
    if (clear)
    {
        input = "";
        for (int i = 0; i < 20; i++)
        {
            input += ' ';
        }
    }

    for (int i = 0; i < data.length(); i++)
    {
        if (i + pos >= 20)
        {
            return;
        }

        input[i + pos] = data[i];
    }
}

void updateDisplay()
{
    String str = "";

    lbg.drawValue(pwmValue, 100);

    insertStringAt(str, String("PWM = ") + String(pwmValue) + '%', 6, true);
    lcd.setCursor(0, 1);
    lcd.print(str);

    lcd.setCursor(0, 2);
    insertStringAt(str, String("T.GL:") + String(temperatureValues[0], 1), 0, true);
    insertStringAt(str, String("T.ZB:") + String(temperatureValues[1], 1), 11, false);
    lcd.print(str);

    lcd.setCursor(0, 3);
    insertStringAt(str, String("T.1OP:") + String(temperatureValues[2], 1), 0, true);
    insertStringAt(str, String("T.WO:") + String(temperatureValues[3], 1), 11, false);
    lcd.print(str);
}

void setup()
{
    lcd.init();
    lcd.backlight();
    lcd.clear();

    pinMode(9, OUTPUT);

    for (int i = 0; i < TEMP_SENSORS; i++)
    {
        DeviceAddress deviceAddress;
        tempSensors[i].setOneWire(&ds18x20[i]);
        tempSensors[i].begin();
        if (tempSensors[i].getAddress(deviceAddress, 0))
        {
            tempSensors[i].setResolution(deviceAddress, 12);
        }
    }

    updateTemperature();
    updateDisplay();
}

void loop()
{
    handleEncoder();

    if (millis() - lastTempUpdateTime >= TEMP_UPDATE_INTERVAL)
    {
        updateTemperature();
        updateDisplay();
        lastTempUpdateTime = millis();
    }
}