#ifndef PLANTINPUT_H
#define PLANTINPUT_H

#include <LiquidCrystal.h>
#include "PlantMonitor.h"
#include "avr_macros.h"

#define SPEAKERPIN 9
#include "tunes.h"
namespace PlIn
{

enum PlantIssueBitFlag
{
    Overwater=0b1, Underwater=0b10,
    Dark=0b100,
    Cold=0b1000, Hot=0b10000
};

// const static int rs = 3, en = 8, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
const static int rs = 3, en = 8, d4 = 5, d5 = 6, d6 = 7, d7 = 8;

LiquidCrystal lcd = LiquidCrystal(rs, en, d4, d5, d6, d7);

PlantMonitor pm = PlantMonitor(10, 11);

struct PlantPoll
{
    int wetness;
    float temp;
    float humidity;
    float light;
};

void initPeriphs()
{
    // set up the LCD's number of columns and rows:
    lcd.begin(16, 2);
}

float getTemp()
{
    float therm_volt = (analogRead(A0)/1023.0) * 5.0;
    float volt_to_c = (therm_volt * 1000.0 - 500.0) / 10.0;
    float c_to_f = (volt_to_c * 9.0/5.0) + 32;
    return c_to_f;
}

float getTempAveraged(size_t num_samples)
{
    float val = 0;
    for(int i = 0; i < num_samples; i++)
        val += getTemp()/num_samples;
    return val;
}

float getLight()
{
    return analogRead(A1);
}

PlantPoll pollPlant()
{
    return {.wetness=pm.getWater(), 
            .temp=getTemp(), 
            .humidity=pm.getHumidity(), 
            .light=getLight()};
}

uint8_t IssueManager(PlantPoll data)
{
    uint8_t issues = 0;
    if(data.temp < 75)
    {
        issues |= Cold;
    }

    if(data.temp > 80)
    {
        issues |= Hot;
    }

    if(data.light < 600)
    {
        issues |= Dark;
    }

    if(data.wetness < 20)
    {
        issues |= Underwater;
    }

    if(data.wetness > 100)
    {
        issues |= Overwater;
    }

    
    return issues;
}

void RequestHelpText(uint8_t issue_flags)
{
    if(!issue_flags)
        return;
    PlIn::lcd.setCursor(0, 0);
    if(issue_flags & Overwater)
    {
        PlIn::lcd.print("Overwater! ");
    }

    if(issue_flags & Underwater)
    {
        // send underwatered help request
        PlIn::lcd.print("Water! ");
    }

    if(issue_flags & Dark)
    {
        // send light help request
        PlIn::lcd.print("Dark! ");
    }

    if(issue_flags & Cold)
    {
        // send temp help request
        PlIn::lcd.print("Cold! ");
    }

    if(issue_flags & Hot)
    {
        // send temp help request
        PlIn::lcd.print("Cold! ");
    }
}

void RequestHelp(uint8_t issue_flags)
{
    if(!issue_flags)
        return;
    if(issue_flags & Overwater)
    {
    }

    if(issue_flags & Underwater)
    {
        // send underwatered help request
        Serial.println("--Underwatered Melody Playing--");
        tunes::playTune(tunes::underwaterMelody, tunes::underwaterDurations, sizeof(tunes::underwaterMelody)/sizeof(uint16_t));
    }

    if(issue_flags & Dark)
    {
        // send light help request
        Serial.println("--Dark Melody Playing--");
        tunes::playTune(tunes::caveMelody, tunes::caveDurations, sizeof(tunes::caveMelody)/sizeof(uint16_t));
    }

    if(issue_flags & Cold)
    {
        // send temp help request
        Serial.println("--Cold Melody Playing--");
        tunes::playTune(tunes::ringtoneMelody, tunes::ringtoneDurations, sizeof(tunes::ringtoneMelody)/sizeof(uint16_t));
    }

    if(issue_flags & Hot)
    {
        // send temp help request
        Serial.println("--Hot Melody Playing--");
        tunes::playTune(tunes::desertMelody, tunes::desertDurations, sizeof(tunes::desertMelody)/sizeof(uint16_t));
    }
}

void LCD_show_data()
{
    PlIn::lcd.setCursor(0, 0);
    PlIn::lcd.print("T");
    PlIn::lcd.print(PlIn::getTempAveraged(20), 2);
    PlIn::lcd.print(" L");
    PlIn::lcd.print(PlIn::getLight());
    PlIn::lcd.setCursor(0, 1);
    PlIn::lcd.print("M");
    PlIn::lcd.print(PlIn::pm.getWater());

    PlIn::lcd.print(" T2 ");
    PlIn::lcd.print(PlIn::pm.getTemp() * 9/5.0 + 32);


}

inline char* state_to_string(size_t cur_state)
{
    switch(cur_state)
    {
        case 0:
            return "Idle";
        case 1:
            return "DataCollect";
        case 2:
            return "RequestHelp";
        case 3:
            return "AwaitHelp";
        case 4:
            return "Error";
    }
}

void face_to_lcd(size_t state, unsigned char flag)
{
    if(flag)
    {
        PlIn::lcd.setCursor(0, 1);
        PlIn::lcd.print("0 _ 0 ***");
    }
    else
    {
        PlIn::lcd.setCursor(0, 1);
        PlIn::lcd.print("-.- zzz...");
    }
}

void print_state(size_t cur_state, unsigned char flag, bool to_lcd)
{
    char* name = state_to_string(cur_state);
    if(to_lcd)
    {
        lcd.clear();
        PlIn::lcd.setCursor(0, 0);
        PlIn::lcd.print(name);
        PlIn::lcd.setCursor(0, 1);
        PlIn::lcd.print(flag, BIN);
    }
    else
    {
        Serial.print("state: ");
        Serial.print(name);
        Serial.print(" flag: ");
        Serial.println(flag, BIN);

    }
}

}



#endif