/**************************************************************************************
Filename:       ir_ac_apply.c
Revised:        Date: 2016-10-12
Revision:       Revision: 1.0

Description:    This file provides methods for AC IR applying functionalities

Revision log:
* 2016-10-12: created by strawmanbobi
**************************************************************************************/
#include "include/ir_utils.h"
#include "include/ir_ac_apply.h"

static INT8 apply_ac_power(struct ac_protocol *protocol, UINT8 power_status);

static INT8 apply_ac_mode(struct ac_protocol *protocol, UINT8 mode_status);

static INT8 apply_ac_temperature(struct ac_protocol *protocol, UINT8 temp_diff);

static INT8 apply_ac_wind_speed(struct ac_protocol *protocol, UINT8 wind_speed);

static INT8 apply_ac_swing(struct ac_protocol *protocol, UINT8 swing_mode);

static UINT8 has_function(struct ac_protocol *protocol, UINT8 function);


INT8 apply_ac_parameter_type_1(UINT8 *dc_data, t_tag_comp *comp_data, UINT8 current_seg, UINT8 is_temp)
{
    if (0 != (comp_data->seg_len & 0x01))
    {
        return IR_DECODE_FAILED;
    }

    if (1 == is_temp)
    {
        dc_data[comp_data->segment[current_seg]] += comp_data->segment[current_seg + 1];
    }
    else
    {
        dc_data[comp_data->segment[current_seg]] = comp_data->segment[current_seg + 1];
    }

    return IR_DECODE_SUCCEEDED;
}

INT8 apply_ac_parameter_type_2(UINT8 *dc_data, t_tag_comp *comp_data, UINT8 current_seg, UINT8 is_temp)
{
    UINT8 start_bit = 0;
    UINT8 end_bit = 0;
    UINT8 cover_byte_pos_hi = 0;
    UINT8 cover_byte_pos_lo = 0;
    UINT8 value;
    UINT8 move_bit = 0;

    if (0 != (comp_data->seg_len % 3))
    {
        return IR_DECODE_FAILED;
    }

    start_bit = comp_data->segment[current_seg];
    end_bit = comp_data->segment[current_seg + 1];
    cover_byte_pos_hi = start_bit >> 3;
    cover_byte_pos_lo = (UINT8) (end_bit - 1) >> 3;
    if (cover_byte_pos_hi == cover_byte_pos_lo)
    {
        // cover_byte_pos_hi or cover_bytes_pos_lo is target byte to be applied with AC parameter
        // try get raw value of byte to be applied
        UINT8 raw_value = comp_data->segment[current_seg + 2];
        UINT8 int_start_bit = start_bit - (cover_byte_pos_hi << 3);
        UINT8 int_end_bit = end_bit - (cover_byte_pos_lo << 3);
        UINT8 bit_range = end_bit - start_bit;
        UINT8 mask = (UINT8) ((0xFF << (8 - int_start_bit)) | (0xFF >> int_end_bit));
        UINT8 origin = dc_data[cover_byte_pos_lo];

        if (TRUE == is_temp)
        {
            move_bit = (UINT8) (8 - int_end_bit);
            value = (origin & mask) | (((((origin & ~mask) >> move_bit) + raw_value) << move_bit) & ~mask);
        }
        else
        {
            value = (origin & mask) | ((raw_value << (8 - int_start_bit - bit_range)) & ~mask);
        }
        dc_data[cover_byte_pos_lo] = value;
    }
    else
    {
        UINT8 origin_hi = 0;
        UINT8 origin_lo = 0;
        UINT8 mask_hi = 0;
        UINT8 mask_lo = 0;
        UINT8 raw_value = 0;
        UINT8 int_start_bit = 0;
        UINT8 int_end_bit = 0;

        if (cover_byte_pos_hi > cover_byte_pos_lo)
        {
            return IR_DECODE_FAILED;
        }
        // calculate the bit scope
        UINT8 bit_range = end_bit - start_bit;

        raw_value = comp_data->segment[current_seg + 2];
        origin_hi = dc_data[cover_byte_pos_hi];
        origin_lo = dc_data[cover_byte_pos_lo];

        int_start_bit = start_bit - (cover_byte_pos_hi << 3);
        int_end_bit = end_bit - (cover_byte_pos_lo << 3);

        mask_hi = (UINT8) 0xFF << (8 - int_start_bit);
        mask_lo = (UINT8) 0xFF >> int_end_bit;

        value = ((origin_hi & ~mask_hi) << int_end_bit) | ((origin_lo & ~mask_lo) >> (8 - int_end_bit));

        if (TRUE == is_temp)
        {
            raw_value += value;
        }

        dc_data[cover_byte_pos_hi] = (UINT8) ((origin_hi & mask_hi) |
                                     (((0xFF >> (8 - bit_range)) & raw_value) >> int_end_bit));

        dc_data[cover_byte_pos_lo] = (UINT8) ((origin_lo & mask_lo) |
                                     (((0xFF >> (8 - bit_range)) & raw_value) << (8 - int_end_bit)));
    }

    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_ac_power(struct ac_protocol *protocol, UINT8 power_status)
{
    UINT16 i = 0;
    if (0 == protocol->power1.len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    if (0 == protocol->power1.comp_data[power_status].seg_len)
    {
        // force to apply power in any cases
        return IR_DECODE_SUCCEEDED;
    }
    for (i = 0; i < protocol->power1.comp_data[power_status].seg_len; i += 2)
    {
        apply_ac_parameter_type_1(ir_hex_code, &(protocol->power1.comp_data[power_status]), (UINT8) i, FALSE);
    }
    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_ac_mode(struct ac_protocol *protocol, UINT8 mode_status)
{
    UINT16 i = 0;

    if (0 == protocol->mode1.len)
    {
        goto try_applying_mode2;
    }

    if (0 == protocol->mode1.comp_data[mode_status].seg_len)
    {
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->mode1.comp_data[mode_status].seg_len; i += 2)
    {
        apply_ac_parameter_type_1(ir_hex_code, &(protocol->mode1.comp_data[mode_status]), (UINT8) i, FALSE);
    }

    // get return here since wind mode 1 is already applied
    return IR_DECODE_SUCCEEDED;

    try_applying_mode2:
    if (0 == protocol->mode2.len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    if (0 == protocol->mode2.comp_data[mode_status].seg_len)
    {
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->mode2.comp_data[mode_status].seg_len; i += 3)
    {
        apply_ac_parameter_type_2(ir_hex_code,
                                  &(protocol->mode2.comp_data[mode_status]),
                                  (UINT8) i, FALSE);
    }
    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_ac_wind_speed(struct ac_protocol *protocol, UINT8 wind_speed)
{
    UINT16 i = 0;

    if (0 == protocol->speed1.len)
    {
        goto try_applying_wind_speed2;
    }

    if (0 == protocol->speed1.comp_data[wind_speed].seg_len)
    {
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->speed1.comp_data[wind_speed].seg_len; i += 2)
    {
        apply_ac_parameter_type_1(ir_hex_code, &(protocol->speed1.comp_data[wind_speed]), (UINT8) i, FALSE);
    }

    // get return here since wind speed 1 is already applied
    return IR_DECODE_SUCCEEDED;

    try_applying_wind_speed2:
    if (0 == protocol->speed2.len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    if (0 == protocol->speed2.comp_data[wind_speed].seg_len)
    {
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->speed2.comp_data[wind_speed].seg_len; i += 3)
    {
        apply_ac_parameter_type_2(ir_hex_code,
                                  &(protocol->speed2.comp_data[wind_speed]),
                                  (UINT8) i, FALSE);
    }
    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_ac_temperature(struct ac_protocol *protocol, UINT8 temp_diff)
{
    UINT16 i = 0;

    if (0 == protocol->temp1.len)
    {
        goto try_applying_temp2;
    }

    if (0 == protocol->temp1.comp_data[temp_diff].seg_len)
    {
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->temp1.comp_data[temp_diff].seg_len; i += 2)
    {
        if (TEMP_TYPE_DYNAMIC == protocol->temp1.type)
        {
            apply_ac_parameter_type_1(ir_hex_code, &(protocol->temp1.comp_data[temp_diff]), (UINT8) i, TRUE);
        }
        else if (TEMP_TYPE_STATIC == protocol->temp1.type)
        {
            apply_ac_parameter_type_1(ir_hex_code, &(protocol->temp1.comp_data[temp_diff]), (UINT8) i, FALSE);
        }
    }

    // get return here since temperature 1 is already applied
    return IR_DECODE_SUCCEEDED;

    try_applying_temp2:
    if (0 == protocol->temp2.len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    if (0 == protocol->temp2.comp_data[temp_diff].seg_len)
    {
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->temp2.comp_data[temp_diff].seg_len; i += 3)
    {
        if (0 != protocol->temp2.comp_data[temp_diff].seg_len)
        {
            if (TEMP_TYPE_DYNAMIC == protocol->temp2.type)
            {
                apply_ac_parameter_type_2(ir_hex_code, &(protocol->temp2.comp_data[temp_diff]), (UINT8) i, TRUE);
            }
            else if (TEMP_TYPE_STATIC == protocol->temp2.type)
            {
                apply_ac_parameter_type_2(ir_hex_code, &(protocol->temp2.comp_data[temp_diff]), (UINT8) i, FALSE);
            }
        }
    }
    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_ac_swing(struct ac_protocol *protocol, UINT8 swing_mode)
{
    UINT16 i = 0;

    if (0 == protocol->swing1.len)
    {
        goto try_applying_swing2;
    }

    if (swing_mode >= protocol->swing1.count)
    {
        return IR_DECODE_FAILED;
    }

    if (0 == protocol->swing1.comp_data[swing_mode].seg_len)
    {
        // swing does not have any empty data segment
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->swing1.comp_data[swing_mode].seg_len; i += 2)
    {
        apply_ac_parameter_type_1(ir_hex_code, &(protocol->swing1.comp_data[swing_mode]), (UINT8) i, FALSE);
    }

    // get return here since temperature 1 is already applied
    return IR_DECODE_SUCCEEDED;

    try_applying_swing2:
    if (0 == protocol->swing2.len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    if (swing_mode >= protocol->swing2.count)
    {
        return IR_DECODE_FAILED;
    }

    if (0 == protocol->swing2.comp_data[swing_mode].seg_len)
    {
        // swing does not have any empty data segment
        return IR_DECODE_FAILED;
    }

    for (i = 0; i < protocol->swing2.comp_data[swing_mode].seg_len; i += 3)
    {
        apply_ac_parameter_type_2(ir_hex_code,
                                  &(protocol->swing2.comp_data[swing_mode]),
                                  (UINT8) i, FALSE);
    }
    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_checksum_byte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
{
    UINT16 i = 0;
    UINT8 checksum = 0x00;

    if (cs.len < 3)
    {
        return IR_DECODE_SUCCEEDED;
    }

    for (i = cs.start_byte_pos; i < cs.end_byte_pos; i++)
    {
        checksum += ac_code[i];
    }

    checksum += cs.checksum_plus;

    if (TRUE == inverse)
    {
        checksum = ~checksum;
    }

    // apply checksum
    ac_code[cs.checksum_byte_pos] = checksum;

    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_checksum_halfbyte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
{
    UINT16 i = 0;
    UINT8 checksum = 0x00;

    if (cs.len < 3)
    {
        return IR_DECODE_SUCCEEDED;
    }

    for (i = cs.start_byte_pos; i < cs.end_byte_pos; i++)
    {
        checksum += (ac_code[i] >> 4) + (ac_code[i] & 0x0F);
    }

    checksum += cs.checksum_plus;

    if (TRUE == inverse)
    {
        checksum = ~checksum;
    }

    // apply checksum
    ac_code[cs.checksum_byte_pos] = checksum;

    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_checksum_spec_byte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
{
    UINT16 i = 0;
    UINT8 apply_byte_pos = 0;
    UINT8 checksum = 0x00;

#if 1
    if (cs.len < 4)
    {
        return IR_DECODE_SUCCEEDED;
    }
#endif

    for (i = 0; i < cs.len - 3; i++)
    {
        UINT8 pos = cs.spec_pos[i];
        UINT8 byte_pos = pos >> 1;

        if (0 == (pos & 0x01))
        {
            checksum += ac_code[byte_pos] >> 4;
        }
        else
        {
            checksum += ac_code[byte_pos] & 0x0F;
        }
    }

    checksum += cs.checksum_plus;

    if (TRUE == inverse)
    {
        checksum = ~checksum;
    }

    // apply checksum, for specific-half-byte checksum, the byte pos actually indicates the half-byte pos
    apply_byte_pos = cs.checksum_byte_pos >> 1;
    if (0 == (cs.checksum_byte_pos & 0x01))
    {
        // save low bits and add checksum as high bits
        ac_code[apply_byte_pos] = (UINT8) ((ac_code[apply_byte_pos] & 0x0F) | (checksum << 4));
    }
    else
    {
        // save high bits and add checksum as low bits
        ac_code[apply_byte_pos] = (UINT8) ((ac_code[apply_byte_pos] & 0xF0) | (checksum & 0x0F));
    }

    return IR_DECODE_SUCCEEDED;
}

static INT8 apply_checksum_spec_byte_onebyte(UINT8 *ac_code, t_tag_checksum_data cs, BOOL inverse)
{
    UINT16 i = 0;
    UINT8 apply_byte_pos = 0;
    UINT8 checksum = 0x00;

#if 1
    if (cs.len < 4)
    {
        return IR_DECODE_SUCCEEDED;
    }
#endif

    for (i = 0; i < cs.len - 3; i++)
    {
        UINT8 pos = cs.spec_pos[i];
        UINT8 byte_pos = pos >> 1;

        if (0 == (pos & 0x01))
        {
            checksum += ac_code[byte_pos] >> 4;
        }
        else
        {
            checksum += ac_code[byte_pos] & 0x0F;
        }
    }

    checksum += cs.checksum_plus;

    if (TRUE == inverse)
    {
        checksum = ~checksum;
    }

    // apply checksum, for specific-half-byte checksum, the byte pos actually indicates the half-byte pos
    apply_byte_pos = cs.checksum_byte_pos >> 1;
    ac_code[apply_byte_pos] = checksum;

    return IR_DECODE_SUCCEEDED;
}

static UINT8 has_function(struct ac_protocol *protocol, UINT8 function)
{
    if (function < AC_FUNCTION_POWER || function > AC_FUNCTION_WIND_FIX)
    {
        return FALSE;
    }

    if (0 != protocol->function1.len)
    {
        if (0 != protocol->function1.comp_data[function - 1].seg_len)
        {
            return TRUE;
        }
    }

    if (0 != protocol->function2.len)
    {
        if (0 != protocol->function2.comp_data[function - 1].seg_len)
        {
            return TRUE;
        }
    }

    return FALSE;
}

INT8 apply_function(struct ac_protocol *protocol, UINT8 function)
{
    UINT16 i = 0;

    if (function < AC_FUNCTION_POWER || function > AC_FUNCTION_WIND_FIX)
    {
        return IR_DECODE_FAILED;
    }

    // function index starts from 1 (AC_FUNCTION_POWER), do -1 operation at first
    if (0 == protocol->function1.len)
    {
        goto try_applying_function2;
    }

    if (0 == protocol->function1.comp_data[function - 1].seg_len)
    {
        // force to apply function in any case
        return IR_DECODE_SUCCEEDED;
    }

    for (i = 0; i < protocol->function1.comp_data[function - 1].seg_len; i += 2)
    {
        apply_ac_parameter_type_1(ir_hex_code, &(protocol->function1.comp_data[function - 1]), (UINT8) i, FALSE);
    }

    // get return here since function 1 is already applied
    return IR_DECODE_SUCCEEDED;

    try_applying_function2:
    if (0 == protocol->function2.len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    if (0 == protocol->function2.comp_data[function - 1].seg_len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    for (i = 0; i < protocol->function2.comp_data[function - 1].seg_len; i += 3)
    {
        apply_ac_parameter_type_2(ir_hex_code,
                                  &(protocol->function2.comp_data[function - 1]),
                                  (UINT8) i, FALSE);
    }
    return IR_DECODE_SUCCEEDED;
}

INT8 apply_checksum(struct ac_protocol *protocol)
{
    UINT16 i = 0;

    if (0 == protocol->checksum.len)
    {
        return IR_DECODE_SUCCEEDED;
    }

    for (i = 0; i < protocol->checksum.count; i++)
    {
        switch (protocol->checksum.checksum_data[i].type)
        {
            case CHECKSUM_TYPE_BYTE:
                apply_checksum_byte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
                break;
            case CHECKSUM_TYPE_BYTE_INVERSE:
                apply_checksum_byte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
                break;
            case CHECKSUM_TYPE_HALF_BYTE:
                apply_checksum_halfbyte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
                break;
            case CHECKSUM_TYPE_HALF_BYTE_INVERSE:
                apply_checksum_halfbyte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
                break;
            case CHECKSUM_TYPE_SPEC_HALF_BYTE:
                apply_checksum_spec_byte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
                break;
            case CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE:
                apply_checksum_spec_byte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
                break;
            case CHECKSUM_TYPE_SPEC_HALF_BYTE_ONE_BYTE:
                apply_checksum_spec_byte_onebyte(ir_hex_code, protocol->checksum.checksum_data[i], FALSE);
                break;
            case CHECKSUM_TYPE_SPEC_HALF_BYTE_INVERSE_ONE_BYTE:
                apply_checksum_spec_byte_onebyte(ir_hex_code, protocol->checksum.checksum_data[i], TRUE);
                break;
            default:
                break;
        }
    }

    return IR_DECODE_SUCCEEDED;
}

INT8 apply_power(t_remote_ac_status ac_status, UINT8 function_code)
{
    (void) function_code;
    apply_ac_power(context, ac_status.ac_power);
    return IR_DECODE_SUCCEEDED;
}

INT8 apply_mode(t_remote_ac_status ac_status, UINT8 function_code)
{
    (void) function_code;
    if (IR_DECODE_FAILED == apply_ac_mode(context, ac_status.ac_mode))
    {
        // do not implement this mechanism since mode, temperature, wind
        // speed would have unspecified function
        //if(FALSE == has_function(context, AC_FUNCTION_MODE))
        {
            return IR_DECODE_FAILED;
        }
    }

    return IR_DECODE_SUCCEEDED;
}

INT8 apply_wind_speed(t_remote_ac_status ac_status, UINT8 function_code)
{
    if (FALSE == context->n_mode[ac_status.ac_mode].all_speed)
    {
        // if this level is not in black list
        if (!is_in(context->n_mode[ac_status.ac_mode].speed,
                   ac_status.ac_wind_speed,
                   context->n_mode[ac_status.ac_mode].speed_cnt))
        {
            if (IR_DECODE_FAILED == apply_ac_wind_speed(context, ac_status.ac_wind_speed) &&
                function_code == AC_FUNCTION_WIND_SPEED)
            {
                // do not implement this mechanism since mode, temperature, wind
                // speed would have unspecified function
                //if(FALSE == has_function(context, AC_FUNCTION_WIND_SPEED))
                {
                    return IR_DECODE_FAILED;
                }
            }
        }
        else
        {
            // if this level is in black list, do not send IR wave if user want to apply this function
            if (function_code == AC_FUNCTION_WIND_SPEED)
            {
                // do not implement this mechanism since mode, temperature, wind
                // speed would have unspecified function
                //if(FALSE == has_function(context, AC_FUNCTION_WIND_SPEED))
                {
                    return IR_DECODE_FAILED;
                }
            }
        }
    }
    else
    {
        // if this level is in black list, do not send IR wave if user want to apply this function
        if (function_code == AC_FUNCTION_WIND_SPEED)
        {
            // do not implement this mechanism since mode, temperature, wind
            // speed would have unspecified function
            //if(FALSE == has_function(context, AC_FUNCTION_WIND_SPEED))
            {
                return IR_DECODE_FAILED;
            }
        }
    }
    return IR_DECODE_SUCCEEDED;
}

INT8 apply_swing(t_remote_ac_status ac_status, UINT8 function_code)
{
    (void) ac_status;
    if (function_code == AC_FUNCTION_WIND_FIX)
    {
        // adjust fixed wind direction according to current status
        if (context->si.type == SWING_TYPE_NORMAL && context->si.mode_count > 1)
        {
            if (TRUE == context->change_wind_direction)
            {
                context->si.dir_index++;
            }

            if (context->si.dir_index == context->si.mode_count)
            {
                // reset dir index
                context->si.dir_index = 1;
            }
            context->swing_status = context->si.dir_index;
        }
    }
    else if (function_code == AC_FUNCTION_WIND_SWING)
    {
        context->swing_status = 0;
    }
    else
    {
        // do nothing
    }

    if (IR_DECODE_FAILED == apply_ac_swing(context, context->swing_status))
    {
        if (function_code == AC_FUNCTION_WIND_SWING &&
            FALSE == has_function(context, AC_FUNCTION_WIND_SWING))
        {
            return IR_DECODE_FAILED;
        }
        else if (function_code == AC_FUNCTION_WIND_FIX &&
                 FALSE == has_function(context, AC_FUNCTION_WIND_FIX))
        {
            return IR_DECODE_FAILED;
        }
    }
    return IR_DECODE_SUCCEEDED;
}

INT8 apply_temperature(t_remote_ac_status ac_status, UINT8 function_code)
{
    if (FALSE == context->n_mode[ac_status.ac_mode].all_temp)
    {
        if (!is_in(context->n_mode[ac_status.ac_mode].temp,
                   ac_status.ac_temp,
                   context->n_mode[ac_status.ac_mode].temp_cnt))
        {
            if (IR_DECODE_FAILED == apply_ac_temperature(context, ac_status.ac_temp))
            {
                if (function_code == AC_FUNCTION_TEMPERATURE_UP
                    /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_UP)*/)
                {
                    return IR_DECODE_FAILED;
                }
                else if (function_code == AC_FUNCTION_TEMPERATURE_DOWN
                    /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_DOWN)*/)
                {
                    return IR_DECODE_FAILED;
                }
            }
        }
        else
        {
            // if this level is in black list, do not send IR wave if user want to apply this function
            if (function_code == AC_FUNCTION_TEMPERATURE_UP
                /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_UP)*/)
            {
                return IR_DECODE_FAILED;
            }
            else if (function_code == AC_FUNCTION_TEMPERATURE_DOWN
                /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_DOWN)*/)
            {
                return IR_DECODE_FAILED;
            }
        }
    }
    else
    {
        // if this level is in black list, do not send IR wave if user want to apply this function
        if (function_code == AC_FUNCTION_TEMPERATURE_UP
            /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_UP)*/)
        {
            return IR_DECODE_FAILED;
        }
        else if (function_code == AC_FUNCTION_TEMPERATURE_DOWN
            /*&& FALSE == has_function(context, AC_FUNCTION_TEMPERATURE_DOWN)*/)
        {
            return IR_DECODE_FAILED;
        }
    }
    return IR_DECODE_SUCCEEDED;
}