/**
 * Copyright JDSU 2013
 *
 * Author: <NAME>
 * Purpose: TFT packet filter payload component factory
 */
#include <iostream>  // NOLINT
#include "xtreme/dataservice/internal/ds_tftpacketfiltercomponents.h"

namespace xtreme {
namespace ds {

// #define TFT_DEBUG
// TODO(bob): Add LOG TRACE for DEBUG
// TODO(bob): Better way that #ifdefs for debug info

TftPacketFilterComponent *TftPacketFilterComponent::BuildComponent(const uint8_t *component, uint16_t &comp_len) {
    #ifdef TFT_DEBUG
        std::cout << "Building component " << static_cast<int>(component[0]) << std::endl;
    #endif
    switch (component[0]) {
    case 0x10:  // ipv4 remote
        {
            comp_len = 9;
            const uint32_t remote_addr = *reinterpret_cast<const uint32_t*>(&component[1]);
            const uint32_t remote_mask = *reinterpret_cast<const uint32_t*>(&component[5]);
            return new TftPacketFilterComponent_Ipv4Remote(remote_addr, remote_mask);
        }
        break;
    case 0x20:  // ipv6 remote
        {
            comp_len = 33;
            const uint64_t *remote6_addr = reinterpret_cast<const uint64_t*>(&component[1]);
            const uint64_t *remote6_mask = reinterpret_cast<const uint64_t*>(&component[17]);
            return new TftPacketFilterComponent_Ipv6Remote(remote6_addr, remote6_mask);
        }
        break;
    case 0x30:  // protocol_id / next header
        {
            comp_len = 2;
            const uint8_t pid = component[1];
            return new TftPacketFilterComponent_ProtocolId(pid);
        }
        break;
    case 0x40:  // single local port
        {
            comp_len = 3;
            const uint16_t port = *reinterpret_cast<const uint16_t*>(&component[1]);
            return new TftPacketFilterComponent_SingleLocalPort(port);
        }
        break;
    case 0x41:  // local port range
        {
            comp_len = 5;
            const uint16_t port_start = *reinterpret_cast<const uint16_t*>(&component[1]);
            const uint16_t port_end = *reinterpret_cast<const uint16_t*>(&component[3]);
            return new TftPacketFilterComponent_LocalPortRange(port_start, port_end);
        }
        break;
    case 0x50:  // single remote port
        {
            comp_len = 3;
            const uint16_t port = *reinterpret_cast<const uint16_t*>(&component[1]);
            return new TftPacketFilterComponent_SingleRemotePort(port);
        }
        break;
    case 0x51:  // remote port range
        {
            comp_len = 5;
            const uint16_t port_start = *reinterpret_cast<const uint16_t*>(&component[1]);
            const uint16_t port_end = *reinterpret_cast<const uint16_t*>(&component[3]);
            return new TftPacketFilterComponent_RemotePortRange(port_start, port_end);
        }
        break;
    case 0x60:  // spi
        {
            comp_len = 5;
            const uint32_t spi = *reinterpret_cast<const uint32_t*>(&component[1]);
            return new TftPacketFilterComponent_SPI(spi);
        }
        break;
    case 0x70:  // traffic class
        {
            comp_len = 3;
            return new TftPacketFilterComponent_TrafficClass(component[1], component[2]);
        }
        break;
    case 0x80:  // flow label
        comp_len = 4;
        uint32_t label = ((component[0] & 0x0f) << 16) + (component[1] << 8) + component[0];
        return new TftPacketFilterComponent_FlowLabel(label);
        break;
    }
    return NULL;   // TODO(bob) nullptr
}
}}  // xtreme::ds
