#include <stdbool>

/**
  * @brief  Мониторинг бита LainFail
  */

void UPS_LineFailMonitor(void)
{
	static bool isValueRecv = false;
	static uint8_t lineFailOldState = 0;
	uint8_t lineFailCurrent;
	char log_string[50];
	uint8_t len;

	lineFailCurrent = ((UPS.Status >> 7) & 0x01);
	lineFailCurrent |= UPS_VACinputRangeAlarm();

    // Заходит в условие только 1 раз.
	if (!isValueRecv) {
		isValueRecv = true;
		lineFailOldState = lineFailCurrent;

	    if (lineFailCurrent != 0) {
		    memset(log_string, 0, sizeof(log_string));
		    strcat(log_string, "Авария");
		    len = strlen(log_string);
		    sprintf(&log_string[len], " (%0.1f В)", UPS.VAC_in);
		    log_event_data(LOG_ALARM_LINE, log_string);
	        SNMP_SendUserTrap(LINE_ALARM);
		    syslog(SYSLOG_ERROR, "Авария сети (%0.1f В)", UPS.VAC_in);
		    flUpdateLog = true;
		}
	    else {
		    log_event_data(LOG_ALARM_LINE, "Норма");
		    SNMP_SendUserTrap(LINE_NORM);
		    syslog(SYSLOG_NOTICE, "Сеть в норме (%0.1f В)", UPS.VAC_in);
		    flUpdateLog = true;
	    }
	    return;
	}
	
	if (lineFailCurrent != 0) {
	    flCriticalAlarm = true;
	    flLedAlarm = true;
	}

	// Значение параметра изменилось
	if (lineFailCurrent != lineFailOldState)
	{
	    if (lineFailCurrent != 0) {
		    memset(log_string, 0, sizeof(log_string));
		    strcat(log_string, "Авария");
		    len = strlen(log_string);
	        sprintf(&log_string[len], " (%0.1f В)", UPS.VAC_in);  
	        log_event_data(LOG_ALARM_LINE, log_string);
	        SNMP_SendUserTrap(LINE_ALARM);
	        syslog(SYSLOG_ERROR, "Авария сети (%0.1f В)", UPS.VAC_in);
		    flUpdateLog = true;
	    }
	    else {
		    if (UPS.VAC_in == 0) {
		        return;
		    }
		    log_event_data(LOG_ALARM_LINE, "Норма");
		    SNMP_SendUserTrap(LINE_NORM);
		    syslog(SYSLOG_NOTICE, "Сеть в норме (%0.1f В)", UPS.VAC_in);
		    flUpdateLog = true;
	    }
	}
	lineFailOldState = lineFailCurrent;
}


uint8_t UPS_VACinputRangeAlarm(void)
{
    uint8_t flag = 0;
    static uint8_t stateCurrentVACinput_low = HYST_IDLE;
    static uint8_t stateCurrentVACinput_high = HYST_IDLE;
    float VACinputCurrent = UPS.VAC_in;
    static uint8_t cnt = 0;
    
    if (test_akb_flag) {
        if (UPS.VAC_in > 255) {
            test_akb_flag = false;
            cnt = 0;
            ups_metac_service_pdu(ups_cancel_test);
            log_event_data(LOG_TEST_UPS, "Ошибка");
        } 
        else {
            if (cnt < 20){
                cnt++;
            } 
            else {
                if (UPS.Mode == 'L') {
                    test_akb_flag = false;
                }
                cnt = 0;
            }
        }
    }

    /* Отслеживается переход через нижнию границу */
    if (VACinputCurrent < sSettings.sAlarmManager.ac_input_range.low)
    {
        if (stateCurrentVACinput_low == HYST_IDLE || stateCurrentVACinput_low == HYST_DOWN) {
            stateCurrentVACinput_low = HYST_DOWN;
            flag |= (1 << 1);
        }
        } 
        else if (VACinputCurrent > (sSettings.sAlarmManager.ac_input_range.low + sSettings.sAlarmManager.ac_input_range.hyst))
        {
            if (stateCurrentVACinput_low == HYST_DOWN)
	        {
                stateCurrentVACinput_low = HYST_IDLE;
                flag &= 0xfd;
            }
        } 
        else {
            if (stateCurrentVACinput_low == HYST_DOWN) {
                flag |= (1 << 1);
        }
    }

    /* Отслеживается переход через верхнюю границу */
    if (VACinputCurrent > sSettings.sAlarmManager.ac_input_range.high)
    {
        if (stateCurrentVACinput_high == HYST_IDLE || stateCurrentVACinput_high == HYST_UP) {
            stateCurrentVACinput_high = HYST_UP;
            flag |= (1 << 2);
        }
    } 
    else if (VACinputCurrent < (sSettings.sAlarmManager.ac_input_range.high - sSettings.sAlarmManager.ac_input_range.hyst))
    {
        if (stateCurrentVACinput_high == HYST_UP)
	    {
            stateCurrentVACinput_high = HYST_IDLE;
            flag &= 0xfb;
        }
    } 
    else {
        if (stateCurrentVACinput_high == HYST_UP) {
            flag |= (1 << 2);
        }
    }
    return flag;
}


void UPS_TestFinishMonitor(void)
{
    static uint8_t TestFinishState = 0;
    uint8_t TestFinishStateCurrent;
    char log_string[50];
    static uint32_t start_time_test = 0;

    TestFinishStateCurrent = (UPS.Status >> 2) & 0x01;

    // Значение параметра изменилось
    if (TestFinishStateCurrent != TestFinishState)
    {
        if (!TestFinishStateCurrent)
        {
            printf("Test finish\r\n");
#ifdef TEST_ALARM_AKB_MONITOR
            float time_test_actual = ((float)(xTaskGetTickCount() - start_time_test)) / (1000*60);
            UPSReadTestStatus();

            float Uakb_av = voltage_bat_average();
            float Pload_av = power_load_average();
            float k_eff;
            printf("Uakb_av: %0.2f", Uakb_av);
            printf("Pload_av: %0.2f", Pload_av);
            
            if (UPS.Test_Status != 2 && Pload_av >= 3) 
            {
                GetUPSEfficiencyFactorInt(&k_eff);
                float Ccalc = (sSettings.UPS_Setting.ups_power*Pload_av*time_test_actual)/(100*60*Uakb_av*(k_eff));
                printf("Ccalc: %0.2f", Ccalc);
                float Ccalc_percent = (100*Ccalc)/sSettings.UPS_Setting.common_capacity;

                if (Ccalc_percent >= 80) 
                {
                    sprintf(log_string, "Авария(%0.2f Ач)", Ccalc);
                    log_event_data(LOG_TEST_ALARM_AKB, log_string);
	                syslog(SYSLOG_INFORMATIONAL, "Ёмкость АКБ: %s", log_string);
                    SNMP_SendUserTrap(BATTERY_FAIL);
                } 
                else 
                {
                    sprintf(log_string, "Норма(%0.2f Ач)", Ccalc);
                    log_event_data(LOG_TEST_ALARM_AKB, log_string);
	                syslog(SYSLOG_INFORMATIONAL, "Ёмкость АКБ: %s", log_string);
                    SNMP_SendUserTrap(BATTERY_NORM);
                }
            }

            memset(log_string, 0, sizeof(log_string));
            
            if (UPS.Test_Status == 2 || ((time_test_actual <= 0.9*test_time || time_test_actual >= 1.1*test_time) && (test_time != 0 && test_time != 100)))
            { 
                strcpy(log_string, "Ошибка");
            } 
            else 
            {
                strcpy(log_string, "Завершен");
            }

            uint8_t len1 = strlen(log_string);
            sprintf(&log_string[len1], "(%0.1f мин)", time_test_actual);
            log_event_data(LOG_TEST_UPS, log_string);
            syslog(SYSLOG_INFORMATIONAL, "Тест батареи: %s", log_string);
            test_time = 0;
            SNMP_SendUserTrap(TEST_BAT_STOP);
#else
            log_event_data(LOG_TEST_UPS, "Завершен");
            syslog_str(SYSLOG_INFORMATIONAL, "Тест батареи: Завершён");
#endif
            flUpdateLog = true;
        } 
        else 
        {
            test_akb_flag = true;
            memset(log_string, 0, sizeof(log_string));
            switch (get_act_source()) 
            {
                case WEB_ACT:
                    strcpy(log_string, name_login);
                break;
                case SNMP_ACT:
                case OTHER_ACT:
                    strcpy(log_string, "Администратор");
                break;
#ifdef CLI_ENABLE
                case CLI_ACT:
                    strcpy(log_string, "Администратор");
                break;
#endif
                case AUTO_ACT:
                    strcpy(log_string, "Автоматический");
                break;
                default:
                break;
            }
#ifdef TEST_ALARM_AKB_MONITOR
            start_time_test = xTaskGetTickCount();
            if (test_time == 0) {
                strcat(log_string, " (авто)");
            } else if (test_time == 100) {
                strcat(log_string, " (до разряда)");
            } else {
                uint8_t len = strlen(log_string);
                sprintf(&log_string[len], "(%i мин)", test_time);
            }
#else
            strcat(log_string, " (Запущен)");
#endif
            printf("Test start\r\n");
            log_event_data(LOG_TEST_UPS, log_string);
            syslog(SYSLOG_INFORMATIONAL, "Тест батареи: %s", log_string);
            SNMP_SendUserTrap(TEST_BAT_RUN);
            flUpdateLog = true;
        }
    }
    TestFinishState = TestFinishStateCurrent;
}


char *HTTP_UPSTest(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut)
{
    uint8_t valueLen = 0;
    char tempValue[20];
    char tempValue2[20];
    int8_t res = 0;
    char log_string[50];

    (void)lenBufIn;
    (void)reqNum;

    if (seclevel == USER) {
      return 0;
    }

    memset(tempValue, 0, 20);
    memset(tempValue2, 0, 20);
    memset(log_string, 0, 50);

    strcpy(bufOut, HTTP_200_OK);

    GetParamValue(bufIn, "func", tempValue, &valueLen);
    if (strcmp(tempValue, "stop") == 0) {
        res = ups_metac_service_pdu(ups_cancel_test);
        if (res == 1 || res == 0) {
            strcat(bufOut, "Команда \"Останов теста\" принята ИБП!");
            strcpy(log_string, name_login);
            strcat(log_string, " (Останов)");
            log_event_data(LOG_TEST_UPS, log_string);
        }
        if (res == -1) {
            strcat(bufOut, "Команда \"Останов теста\" отклонена ИБП!");
        }
    } else if (strcmp(tempValue, "discharge") == 0) {
        res = ups_metac_service_pdu(ups_test_low_bat);
        set_act_source(WEB_ACT);
        if (res == 1 || res == 0) {
            strcat(bufOut, "Команда \"Запуск теста\" принята ИБП!");
        }
        if (res == -1) {
            strcat(bufOut, "Команда \"Запуск теста\" отклонена ИБП!");
        }
    } else if (strncmp(tempValue, "time", 6) == 0) {
        GetParamValue(bufIn, "time", tempValue2, &valueLen);
        TimeParam = atoi(tempValue2);
        res = ups_metac_service_pdu(ups_test_time);
        if (res == 1 || res == 0) {
            strcat(bufOut, "Команда \"Запуск теста\" принята ИБП!");
        }
        if (res == -1) {
            strcat(bufOut, "Команда \"Запуск теста\" отклонена ИБП!");
        }
    }
    *lenBufOut = strlen(bufOut);

    return bufOut;
}