// Pkt1.h : Declaration of the CPkt1

#pragma once
#include "resource.h"       // main symbols

#include <string>

#include "UdpEx.h"
#include "IadsTppCommon.h"
#include <comutil.h>


using namespace ATL;
using namespace std;

const __int64 tNanosecondsInSecond = (__int64)1000000000;
// CPkt1

class ATL_NO_VTABLE CPkt1 :
  public CComObjectRootEx<CComMultiThreadModel>,
  public CComCoClass<CPkt1, &CLSID_Pkt1>,
  public ISupportErrorInfo,
  public IDispatchImpl<IPkt1, &IID_IPkt1, &LIBID_UdpExLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
  public IDispatchImpl<IIadsTppUDPPlugin, &__uuidof(IIadsTppUDPPlugin)>
{
  CComPtr<IPluginMeasurement> Word1;
  CComPtr<IPluginMeasurement> Word2;
  unsigned __int64 nanoseconds;
public:
  CPkt1()
  {
    nanoseconds = 0I64;
  }

  DECLARE_REGISTRY_RESOURCEID(IDR_PKT1)


  BEGIN_COM_MAP(CPkt1)
    COM_INTERFACE_ENTRY(IPkt1)
    COM_INTERFACE_ENTRY2(IDispatch, IIadsTppUDPPlugin)
    COM_INTERFACE_ENTRY(ISupportErrorInfo)
    COM_INTERFACE_ENTRY(IIadsTppUDPPlugin)
  END_COM_MAP()

  // ISupportsErrorInfo
  STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);


  DECLARE_PROTECT_FINAL_CONSTRUCT()

  HRESULT FinalConstruct()
  {
    return S_OK;
  }

  void FinalRelease()
  {
  }

public:




  // IIadsTppUDPPlugin Methods
public:
  //Give your source a descriptive name -- This will appear later in the IADS start wizard's dropdown data source list.
  STDMETHOD(get_DataSourceName)(BSTR * pVal)
  {
    _bstr_t name = L"Example UDP Plugin";
    *pVal = name.Detach();
    return S_OK;
  }
  //Nothing to do here - reserved for future use.
  STDMETHOD(put_DataSourceName)(BSTR newVal)
  {
    return E_NOTIMPL;
  }
  //Create and register your parameters to the dataStream passed in. 
  //Parameter names must be unique.  
  STDMETHOD(Init)(IIadsTppUDPPluginDataStream * ds)
  {
    //Use the dataStream obj to define your IADS parameters, your UDP packet and time characteristics
    CComPtr<IIadsTppUDPPluginDataStream> dataStream = ds;
    if (dataStream == NULL) return E_POINTER;

    //Add a UDP packet definition.
    _bstr_t packetName = L"Pkt1";
    _bstr_t destinationIP = L"239.4.0.1";
    dataStream->AddPacketDefinition(packetName, 10.0, 128, destinationIP, 5000, NULL);

    //Add parameter definitions. Please see MeasurementInputDataType for a list of the possible types.
    //Blob type requires an addition function call : put_BlobSizeInBytes
    //hang onto to the parameter it creates because you'll need it later in dataStream->PutData()
    _bstr_t name = L"Word1";
    _bstr_t units = L"N/A";
    HRESULT hr = dataStream->CreateBasicMeasurement(name, name, name, units, UNSIGNED_BINARY_16, 0.0, &Word1.p );
    dataStream->addMeasurement(Word1);

    //set up time characteristics:
    //0 means aperiodic -- as long as time is monotonically increasing, it can appear at any interval
    //any other non-negative number mean time is periodic so tnterval between time samples is fixed. 
    //All sampling in IADS is very strict. Be certain your time and data are periodic before you declare them so.
    dataStream->put_TimeSampleRate(0.0);

    return S_OK;
  }
  /*
  ds: dataStream object that you pass data and time back to IadsTpp
  data : data payload of defined UDP packets
  packageSize : actual size of UDP packet
  */
  STDMETHOD(ProcessData)(IIadsTppUDPPluginDataStream * ds, VARIANT data, LONG packageSize)
  {
    HRESULT hr = S_OK;
    CComPtr<IIadsTppUDPPluginDataStream> dataStream = ds;

    //data is an safearray of bytes -- parse it and return pieces of data back to dataStream->PutTime() and dataStream->PutData()
    //in this case, you want to send time point, then data, data, data --- as many data points that pertain to that time point. 
    byte *data_ptr = NULL;
    SafeArrayAccessData(data.parray, (void **)&data_ptr);

    //Again, time must be monotonically increasing 
    nanoseconds = *((unsigned __int64 *)data_ptr);
    __int64 iadsTime = (__int64)nanoseconds;
    //Time first
    hr = dataStream->PutTime(iadsTime);

    VARIANT vdata;
    vdata.vt = VT_UI2;
    vdata.uiVal = (unsigned short )(*((unsigned __int64 *)&data_ptr[8]));

    //then data
    hr = dataStream->PutData(Word1, vdata);

    //Make sure you release the data array before you exit. Do not exit the function without calling this. 
    SafeArrayUnaccessData(data.parray);
    return S_OK;
  }
};

OBJECT_ENTRY_AUTO(__uuidof(Pkt1), CPkt1)
