/**************************************************************************//**
* @file
* @brief         Contains commands to the BierAlyzer, that perform requests
*                of users and events, as well as deleting and registering 
*                new ones, and clocksync and settings.
* @headerfile    Command.h
* @details       Each command function prints its results.
*                This file can be used as basis to create a BierAlyzer.dll
******************************************************************************
* @author        M. Eng. CCR (Technikreferent des Durstigen Donnerstags)
* @version       1.0
* @date          Q1 2016
******************************************************************************
* @bug
* @warning       Because of the lazyness of the author there are a lot of magic numbers
******************************************************************************
* @copyright     <b>CC-Software</b> - http://www.cc-software.de
*                Open Source Software for http://www.durstiger-donnerstag.de
* @section       License
*                This code is open source. Feel free to use it for non-commercial purposes.
*                However consider:
*                - always mention the origin (CC-Software and Durstiger Donnerstag)
*                - if you altered code, additionally mark it as altered by you
*                - the author doesn't guarantee functionality and is not liable for
*                  any accidents or other occurrences due to the usage of this code
*******************************************************************************/

#include "stdafx.h" 

#include "time.h"

#include "Command.h"
#include "CommandParser.h"
#include "DDProtocol.h"

/**************************************************************************//**
* @addtogroup AlcoLyzer Console
*****************************************************************************/

static char is_leap_year(char *two_digit_ascii_year);

/**************************************************************************//**
* @brief
*    Creates an empty payload.
*
* @param payload
*    Pointer to the payload.
*****************************************************************************/
void createPayload(unsigned char *payload)
{
    char i;
    for (i = 0; i < 61; i++){
        payload[i] = 0;
    }
}

/**************************************************************************//**
* @brief
*    Request all users from the BierAlyzer and prints them together with 
*    their beer list.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t requestAllUsers(void)
{
    unsigned char i, j, payload[61], recv_content, recv_type;    

    for (i = 0; i < 64; i++){
        createPayload(payload);
        //request user with hex id i
        payload[1] = i;
        payload[DDP_PACKET_PAYLOAD_INDEX_USER_NAME] = 0; //to not display one user multiple times, when BierAlyzer doesn't have more
        sendPacket(payload, DDP_PACKET_TYPE_REQUEST, DDP_PACKET_CONTENT_USER);

        //wait for answer of BierAlyzer
        if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
            printf("<> ERROR: Timeout error\n");
            return COMMAND_ERROR_TIMEOUT;
        }

        //print user
        else if (recv_content == DDP_PACKET_CONTENT_USER && recv_type == DDP_PACKET_TYPE_RESPONSE){
            if (i == 0){
                printf("\n\nUserliste:\nUser      Events ");
                for (j = 0; j < 32; j++){
                    printf("%d%d   ", j / 10, j % 10);
                }
                printf("\n\n");
            }
            //check if user is active
            if (payload[DDP_PACKET_PAYLOAD_INDEX_USER_STATUS] == 0){
                char name[DDP_PACKET_NAME_LENGTH + 2];
                CommandParseDecodeString((char*)payload + DDP_PACKET_PAYLOAD_INDEX_USER_NAME, name, '\0', DDP_PACKET_NAME_LENGTH);
                printf(" 0x%x%x %s", i >> 4, i & 0xF, name);
                //print bierliste
                for (j = 17; j <= 48; j++){
                    if (payload[j] > 99){
                        printf("%i,%i ", payload[j] / 10, payload[j] % 10);
                    }
                    else if (payload[j] == 0){
                        printf(" --  ");
                    }
                    else{
                        printf(" %i,%i ", payload[j] / 10, payload[j] % 10);
                    }
                }
                printf("\n");
            }
            else{
                printf(" 0x%x%x - n./a. -\n", i >> 4, i & 0xF);
            }
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests one single user and prints its data.
*
* @param hexId
*    The hex-ID of the user that is requested.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t requestSingleUser(unsigned char hexId)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //request user
    payload[1] = hexId;
    sendPacket(payload, DDP_PACKET_TYPE_REQUEST, DDP_PACKET_CONTENT_USER);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print user
    else if (recv_content == DDP_PACKET_CONTENT_USER && recv_type == DDP_PACKET_TYPE_RESPONSE){
        //check if user is active
        printf("\n\n> User 0x%X%X", hexId >> 4, hexId & 0xF);
        if (payload[DDP_PACKET_PAYLOAD_INDEX_USER_STATUS] == 0){
            //print name
            char name[DDP_PACKET_NAME_LENGTH + 2];
            CommandParseDecodeString((char*)payload + DDP_PACKET_PAYLOAD_INDEX_USER_NAME, name, '\0', 0);
            printf(" - %s", name);

            //print RFID-ID
            printf(" - RFID-ID: %02X %02X %02X %02X %02X\n", payload[2], payload[3], payload[4], payload[5], payload[6]);

            char j;
            printf("\n      Events  ");
            for (j = 0; j < 32; j++){
                printf("%d%d   ", j / 10, j % 10);
            }
            printf("\n\n");

            //print bierliste
            printf("\n  Bierliste  ");
            for (j = 17; j <= 48; j++){
                if (payload[j] > 99){
                    printf("%i,%i ", payload[j] / 10, payload[j] % 10);
                }
                else if (payload[j] == 0){
                    printf(" --  ");
                }
                else{
                    printf(" %i,%i ", payload[j] / 10, payload[j] % 10);
                }
            }
            printf("\n");
        }
        else{
            printf(" - n./a. -\n", hexId >> 4, hexId & 0xF);
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests all events from the BierAlyzer and prints them.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t requestAllEvents(void)
{
    unsigned char i, payload[61], recv_content, recv_type;

    for (i = 0; i < 32; i++){
        createPayload(payload);
        //request event with event id i
        payload[1] = i;
        payload[DDP_PACKET_PAYLOAD_INDEX_EVENT_DESCRIPTION] = 0; //to not display one event multiple times, when BierAlyzer doesn't have more
        sendPacket(payload, DDP_PACKET_TYPE_REQUEST, DDP_PACKET_CONTENT_EVENT);
        createPayload(payload); //clear payload

        //wait for answer of BierAlyzer
        if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
            printf("<> ERROR: Timeout error\n");
            return COMMAND_ERROR_TIMEOUT;
        }

        //print events
        else if (recv_content == DDP_PACKET_CONTENT_EVENT && recv_type == DDP_PACKET_TYPE_RESPONSE){
            if (i == 0){
                printf("\n\n> Eventliste:\n");
            }
            //check event status
            if (payload[DDP_PACKET_PAYLOAD_INDEX_EVENT_STATUS] == 0){
                char description[DDP_PACKET_EVENT_DESCRIPTION_LENGTH + 2];
                CommandParseDecodeString((char*)payload + DDP_PACKET_PAYLOAD_INDEX_EVENT_DESCRIPTION, description, '\0', DDP_PACKET_EVENT_DESCRIPTION_LENGTH);
                printf("  %d%d   %s", i / 10, i % 10, description);
                //print datum
                printf("  %i%i.%i%i.20%i%i\n", payload[39] >> 4, payload[39] & 0x0F, payload[38] >> 4, payload[38] & 0x0F, payload[37] >> 4, payload[37] & 0x0F);
            }
            else{
                printf("  %d%d   - n./a. -\n", i / 10, i % 10);
            }
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests one single event and prints its data.
*
* @param eventId
*    The event-ID of the event that is requested.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t requestSingleEvent(unsigned char eventId)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //request event
    payload[1] = eventId;
    sendPacket(payload, DDP_PACKET_TYPE_REQUEST, DDP_PACKET_CONTENT_EVENT);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print event
    else if (recv_content == DDP_PACKET_CONTENT_EVENT && recv_type == DDP_PACKET_TYPE_RESPONSE){
        //check event status
        if (payload[DDP_PACKET_PAYLOAD_INDEX_EVENT_STATUS] == 0){
            char description[DDP_PACKET_EVENT_DESCRIPTION_LENGTH + 2];
            CommandParseDecodeString((char*)payload + DDP_PACKET_PAYLOAD_INDEX_EVENT_DESCRIPTION, description, '\0', DDP_PACKET_EVENT_DESCRIPTION_LENGTH);
            printf("> Event\n");
            printf("  %d%d   %s", eventId / 10, eventId % 10, description);
            //print datum
            printf("  %i%i.%i%i.20%i%i\n", payload[39] >> 4, payload[39] & 0x0F, payload[38] >> 4, payload[38] & 0x0F, payload[37] >> 4, payload[37] & 0x0F);
        }
        else{
            printf("  %d%d   - nicht registriert -\n", eventId / 10, eventId % 10);
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests all settings from the BierAlyzer and prints them in a summary.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t requestSettings(void)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //request event
    sendPacket(payload, DDP_PACKET_TYPE_REQUEST, DDP_PACKET_CONTENT_SETTINGS);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print settings
    else if (recv_content == DDP_PACKET_CONTENT_SETTINGS && recv_type == DDP_PACKET_TYPE_RESPONSE){
        printf("> ------------------------------\n");
        printf("> Einstellungen im BierAlyzer:\n>\n");
        printf(">> Firmware:               v%d.%d ", payload[8]>>6, (payload[8]>>2)& 0xF);
        switch (payload[8] & 0x03){
        case 0:
            printf("experimental\n");
            break;
        case 1:
            printf("alpha\n");
            break;
        case 2:
            printf("beta\n");
            break;
        case 3:
            printf("stable\n");
            break;
        }
        printf(">> Eingestellte Event ID:  %d%d\n", payload[9] / 10, payload[9] % 10);

        //check if current RFID ID indicates, that no card is on the BierAlyzer
        if (payload[10] == 0xFF && payload[11] == 0xFF && payload[12] == 0xFF && payload[13] == 0xFF && payload[14] == 0xFF){
            printf(">> Aufgelegte RFID-ID:     - keine Karte -\n");
        }
        else{

        
            printf(">> Aufgelegte RFID-ID:     %X%X %X%X %X%X %X%X %X%X\n", payload[10] >> 4, payload[10] & 0x0F, \
                                                                payload[11] >> 4, payload[11] & 0x0F, \
                                                                payload[12] >> 4, payload[12] & 0x0F, \
                                                                payload[13] >> 4, payload[13] & 0x0F, \
                                                                payload[14] >> 4, payload[14] & 0x0F);
        }
        printf(">> Datum:                  ");
        switch (payload[7]){
        case 1: printf("Montag");
            break;
        case 2: printf("Dienstag");
            break;
        case 3: printf("Mittwoch");
            break;
        case 4: printf("Donnerstag");
            break;
        case 5: printf("Freitag");
            break;
        case 6: printf("Samstag");
            break;
        case 7: printf("Sonntag");
            break;
        }
        printf(", %i%i.%i%i.20%i%i\n", payload[6] >> 4, payload[6] & 0x0F, payload[5] >> 4, payload[5] & 0x0F, payload[4] >> 4, payload[4] & 0x0F);
        printf(">> Uhrzeit:                %i%i:%i%i:%i%i\n", payload[1] >> 4, payload[1] & 0x0F, payload[2] >> 4, payload[2] & 0x0F, payload[3] >> 4, payload[3] & 0x0F);
        printf("> ------------------------------\n");
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }

    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Performs a ping request from the BierAlyzer and prints its response.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t requestPing(void)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //request event
    sendPacket(payload, DDP_PACKET_TYPE_REQUEST, DDP_PACKET_CONTENT_PING);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print settings
    else if (recv_content == DDP_PACKET_CONTENT_PING && recv_type == DDP_PACKET_TYPE_RESPONSE){
        printf("> Ping Response vom BierAlyzer empfangen\n\n");
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }

    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests to delete a user, asks for cancellation before.
*
* @param hexId
*    The hex-ID of the user that is to be deleted.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t deleteSingleUser(unsigned char hexId)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //FRAGEN ob wirklich loeschen!
    printf("<> User 0x%X%X wirklich loeschen? Zum bestaetigen y eingeben, andere Taste andernfalls\n", hexId >> 4, hexId & 0x0F);
    if (getchar() != 'y'){
        printf("<> Abbruch: User 0x%X%X wurde nicht geloescht\n", hexId >> 4, hexId & 0x0F);
        getchar(); //catch Return
        return COMMAND_ERROR_CANCELED;
    }

    getchar(); //catch Return

    //delete event
    payload[0] = 0x33; //delete command
    payload[1] = hexId;
    sendPacket(payload, DDP_PACKET_TYPE_DATA, DDP_PACKET_CONTENT_USER);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print response
    else if (recv_content == DDP_PACKET_CONTENT_USER){
        if (recv_type == DDP_PACKET_TYPE_ACKNOWLEDGE){
            printf("> User 0x%X%X erfolgreich geloescht!\n", hexId >> 4, hexId & 0x0F);
        }
        else if (recv_type == DDP_PACKET_TYPE_NOT_ACKNOWLEDGE){
            printf("> Fehler beim Loeschen von User %X%X.\n", hexId >> 4, hexId & 0x0F);
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests to delete an event, asks for cancellation before.
*
* @param eventId
*    The event-ID of the event that is to be deleted.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t deleteSingleEvent(unsigned char eventId)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //FRAGEN ob wirklich loeschen!
    printf("> Event %d wirklich loeschen? Zum bestaetigen y eingeben\n", eventId);
    if (getchar() != 'y'){
        printf("<> Abbruch: Event %d wurde nicht geloescht\n", eventId);
        getchar(); //catch Return
        return COMMAND_ERROR_CANCELED;
    }
    getchar(); //catch Return

    //delete event
    payload[0] = 0x33; //delete command
    payload[1] = eventId;
    sendPacket(payload, DDP_PACKET_TYPE_DATA, DDP_PACKET_CONTENT_EVENT);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print response
    else if (recv_content == DDP_PACKET_CONTENT_EVENT){
        if (recv_type == DDP_PACKET_TYPE_ACKNOWLEDGE){
            printf("> Event %d erfolgreich geloescht!\n", eventId);
        }
        else if (recv_type == DDP_PACKET_TYPE_NOT_ACKNOWLEDGE){
            printf("> Fehler beim Loeschen von Event %d.\n", eventId);
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests to register a new user.
*
* @param hexId
*    The hex-ID of the new user.
*
* @param name
*    The name of the new user, zero-terminated ASCII.
*
* @param rfidId
*    The RFID-ID of the new user's RFID card, as 5-digit binary.
*    If pointer is set to zero, the currently available card on the
*    BierAlyzer is used as RFID-ID.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t registerUser(unsigned char hexId, char *name, char *rfidId)
{
    unsigned char payload[61], recv_content, recv_type, rfidId_local[5], i;
    createPayload(payload);

    //use current user ID?
    if (!rfidId){
        //request setting für akktuelle RFID id
        sendPacket(payload, DDP_PACKET_TYPE_REQUEST, DDP_PACKET_CONTENT_SETTINGS);
        createPayload(payload); //clear payload

        //wait for answer of BierAlyzer
        if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
            printf("<> ERROR: Timeout error\n");
            return COMMAND_ERROR_TIMEOUT;
        }

        //store rfid id
        else if (recv_content == DDP_PACKET_CONTENT_SETTINGS && recv_type == DDP_PACKET_TYPE_RESPONSE){
            for (i = 0; i < 5; i++){
                rfidId_local[i] = payload[i + 10];
            }
            if (rfidId_local[0] == 0xFF && rfidId_local[1] == 0xFF && rfidId_local[2] == 0xFF && rfidId_local[3] == 0xFF && rfidId_local[4] == 0xFF){
                printf("> Keine RFID Karte auf dem BierAlyzer erkannt\n");
                return COMMAND_ERROR;
            }
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    else{
		for (i = 0; i < 5; i++){
			rfidId_local[i] = rfidId[i];
		}
    }

    //register user
    payload[0] = 0xDD; //command for new event
    payload[1] = hexId;
    payload[49] = 0;//status = active
    
    //save rfid id
    for (i = 0; i < 5; i++){
        payload[i + 2] = rfidId_local[i];
    }

    //save name
    for (i = 0; name[i] != '\0'; i++){
        payload[i + 7] = name[i];
        if (i > (DDP_PACKET_NAME_LENGTH - 1)){
            printf("> Der Name darf maximal 9 Zeichen lang sein\n");
            return COMMAND_ERROR;
        }
    }
    payload[i + 7] = '\0';

    sendPacket(payload, DDP_PACKET_TYPE_DATA, DDP_PACKET_CONTENT_USER);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print response
    else if (recv_content == DDP_PACKET_CONTENT_USER){
        if (recv_type == DDP_PACKET_TYPE_ACKNOWLEDGE){
            printf("> User %X%X erfolgreich angelegt!\n", hexId >> 4, hexId & 0xF);
        }
        else if (recv_type == DDP_PACKET_TYPE_NOT_ACKNOWLEDGE){
            printf("> Fehler beim Registrieren von User %X%X, wahrscheinlich noch ein anderer User an dieser Stelle present.\n", hexId >> 4, hexId & 0xF);
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Requests to register a new event.
*
* @param eventId
*    The event-ID of the new event.
*
* @param name
*    The description of the new event, zero-terminated ASCII.
*
* @param date
*    The date of the new event, as numerical string with dots for separation,
*    example "12.06.16".
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t registerEvent(unsigned char eventId, char *description, char *date)
{
    unsigned char payload[61], recv_content, recv_type, i;
    createPayload(payload);

    //register event
    payload[0] = 0xDD; //command for new event
    payload[1] = eventId;
    payload[40] = 1;//dauer: 1 day default
    payload[41] = 0; //status = active
    for (i = 0; description[i] != '\0'; i++){
        payload[i + 2] = description[i];
    }

    //set event date. Format must be dd.mm.yy
    if (date[2] != '.' || date[5] != '.'){
        printf("<> ERROR: Date needs to be entered with dots and only two digits respectively, like 12.06.16\n");
        return COMMAND_ERROR;
    }
    //check for absolute numbers
    if (date[0] < '0' || date[0] > '3' || date[1] < '0' || date[1] > '9' || /*day: 01 - 31*/ \
        date[3] < '0' || date[3] > '1' || date[4] < '0' || date[4] > '9' || /*month: 01 -12*/ \
        date[6] < '0' || date[6] > '9' || date[7] < '0' || date[7] > '9'){  /*year: 00 - 99*/
        printf("<> ERROR: No valid date entered!\n");
        return COMMAND_ERROR;
    }
    //check for relative numbers
    if ((date[0] == '0' && date[1] == '0') || (date[3] == '0' && date[4] == '0') || /*no day 00 and no month 00 allowed*/ \
        (date[0] == '3' && date[1] > '1') || (date[3] == '1' && date[4] > '2') || /*no day bigger than 31 and no month bigger than 12 allowed*/ \
        (date[0] == '3' && date[1] > '0' && date[3] == '0' && (date[4] == '4' || date[4] == '6' || date[4] == '9')) || /*no day bigger than 30 for months 04, 06 and 09 allowed*/ \
        (date[0] == '3' && date[1] > '0' && date[3] == '1' && date[4] == '1') || /*no day bigger than 30 for month 11 allowed*/ \
        ((date[0] == '3' || (date[0] == '2' && date[1] > '9')) && date[3] == '0' && date[4] == '2') || /*no day bigger than 29 for month 02 allowed*/ \
        ((date[0] == '3' || (date[0] == '2' && date[1] > '8')) && date[3] == '0' && date[4] == '2' && !is_leap_year(date + 6))){ /*no day bigger than 28 for months 02 for non-leap years allowed*/ \

        printf("<> ERROR: No valid date entered!\n");
        return COMMAND_ERROR;
    }

    payload[37] = ((date[6] - '0') << 4) | (date[7] - '0'); //year
    payload[38] = ((date[3] - '0') << 4) | (date[4] - '0'); //month
    payload[39] = ((date[0] - '0') << 4) | (date[1] - '0'); //day

    sendPacket(payload, DDP_PACKET_TYPE_DATA, DDP_PACKET_CONTENT_EVENT);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print response
    else if (recv_content == DDP_PACKET_CONTENT_EVENT){
        if (recv_type == DDP_PACKET_TYPE_ACKNOWLEDGE){
            printf("> Event %d erfolgreich angelegt!\n", eventId);
        }
        else if (recv_type == DDP_PACKET_TYPE_NOT_ACKNOWLEDGE){
            printf("> Fehler beim Anlegen von Event %d, wahrscheinlich noch ein anderes Event an dieser Stelle present.\n", eventId);
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Sets the given event-ID as current event-ID in the BierAlyzer.
*
* @param eventId
*    The event-ID of the event that is to be selected as current event.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t setEventID(unsigned char eventId)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //register event
    payload[0] = 0x02; //command for set new current event id
    payload[9] = eventId;

    sendPacket(payload, DDP_PACKET_TYPE_DATA, DDP_PACKET_CONTENT_SETTINGS);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print response
    else if (recv_content == DDP_PACKET_CONTENT_SETTINGS){
        if (recv_type == DDP_PACKET_TYPE_ACKNOWLEDGE){
            printf("> Event %d wurde eingestellt!\n", eventId);
        }
        else if (recv_type == DDP_PACKET_TYPE_NOT_ACKNOWLEDGE){
            printf("> Fehler beim Einstellen der Event %d.\n", eventId);
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Synchronizes the clock of the BierAlyzer with the computer.
*
* @return
*    Indicates whether an error occurred or if command was conducted successfully.
*****************************************************************************/
command_error_t clockSync(void)
{
    unsigned char payload[61], recv_content, recv_type;
    createPayload(payload);

    //register event
    payload[0] = 0x01; //command for set new date & time

    //aquire current time and data
    time_t t;
    struct tm *ts;

    t = time(NULL);
    ts = localtime(&t);

    payload[1] = (((ts->tm_hour) / 10) << 4) | (ts->tm_hour) % 10;
    payload[2] = (((ts->tm_min) / 10) << 4) | (ts->tm_min) % 10;
    payload[3] = (((ts->tm_sec) / 10) << 4) | (ts->tm_sec) % 10;
    payload[4] = ((((ts->tm_year) - 100) / 10) << 4) | ((ts->tm_year) - 100) % 10;
    payload[5] = ((((ts->tm_mon) + 1) / 10) << 4) | ((ts->tm_mon) + 1) % 10;
    payload[6] = (((ts->tm_mday) / 10) << 4) | (ts->tm_mday) % 10;
    if ((ts->tm_wday) == 0){
        payload[7] = 7;
    }
    else{
        payload[7] = ts->tm_wday;
    }

    sendPacket(payload, DDP_PACKET_TYPE_DATA, DDP_PACKET_CONTENT_SETTINGS);
    createPayload(payload); //clear payload

    //wait for answer of BierAlyzer
    if (!receivePacket(payload, &recv_type, &recv_content, COMMAND_TIMEOUT)){
        printf("<> ERROR: Timeout error\n");
        return COMMAND_ERROR_TIMEOUT;
    }

    //print response
    else if (recv_content == DDP_PACKET_CONTENT_SETTINGS){
        if (recv_type == DDP_PACKET_TYPE_ACKNOWLEDGE){
            printf("> Uhrzeit und Datum wurden auf ");
            switch (payload[7]){
            case 1: printf("Montag,");
                break;
            case 2: printf("Dienstag,");
                break;
            case 3: printf("Mittwoch,");
                break;
            case 4: printf("Donnerstag,");
                break;
            case 5: printf("Freitag,");
                break;
            case 6: printf("Samstag,");
                break;
            case 7: printf("Sonntag,");
                break;
            }
            printf(" %X%X.%X%X.20%X%X  %X%X:%X%X:%X%X synchronisiert!\n", payload[6] >> 4, payload[6] & 0xF, \
                                                                          payload[5] >> 4, payload[5] & 0xF, \
                                                                          payload[4] >> 4, payload[4] & 0xF, \
                                                                          payload[1] >> 4, payload[1] & 0xF, \
                                                                          payload[2] >> 4, payload[2] & 0xF, \
                                                                          payload[3] >> 4, payload[3] & 0xF);
        }
        else if (recv_type == DDP_PACKET_TYPE_NOT_ACKNOWLEDGE){
            printf("> Fehler beim Synchronisieren.\n");
        }
        else{
            printf("<> ERROR: Non-valid packet received\n");
            return COMMAND_ERROR;
        }
    }
    else{
        printf("<> ERROR: Non-valid packet received\n");
        return COMMAND_ERROR;
    }
    return COMMAND_SUCCESS;
}

/**************************************************************************//**
* @brief
*    Checks if the given year is a leap year or not.
*
* @param two_digit_ascii_year
*    Expects the two digits (for 2016 -> 16) as ascii.
*
* @return
*    1 if year is a leap year, 0 if not.
*****************************************************************************/
static char is_leap_year(char *two_digit_ascii_year)
{
    unsigned char year_bcd = ((two_digit_ascii_year[0] - '0') << 4) | (two_digit_ascii_year[1] - '0');

    //odd 10th years: 12,16,32,36, ...
    if (year_bcd & 0x10){
        if (((year_bcd & 0x0F) == 0x02) || ((year_bcd & 0x0F) == 0x06)){
            return 1;
        }
        return 0;
    }
    //even 10th years: 00,04,08,20,24,28, ...
    else{
        if (((year_bcd & 0x0F) == 0x00) || ((year_bcd & 0x0F) == 0x04) || ((year_bcd & 0x0F) == 0x08)){
            return 1;
        }
        return 0;
    }
}