// MyScript.h : Declaration of the CMyScript


#ifndef __MYSCRIPT_H_
#define __MYSCRIPT_H_


//#include "stdafx.h"

#include "resource.h"       // main symbols

/* Interface implemented

  Create simple ATL object
  in classview rightclick "Implement Interface .."
  select blaxxunvrml.tbl
  select Script interface 

*/
#import "import\\blaxxunVRML.tlb" raw_interfaces_only, raw_native_types, no_namespace, named_guids 
// safe release of a COM ptr 
#define RELEASE(x) if (x) { x->Release(); x = NULL; }
#define FREE(x)    if (x) { free( x ); x = NULL; }

#define snprintf     _snprintf

#define PBL_LIST_PUSH( HEAD, TAIL, ITEM, NEXT, PREV )\
{\
    (ITEM)->PREV = 0;\
    if(( (ITEM)->NEXT = (HEAD) ))\
        { (ITEM)->NEXT->PREV = (ITEM); }\
    else\
        { (TAIL) = (ITEM); }\
    (HEAD) = (ITEM);\
}

#define PBL_LIST_APPEND( HEAD, TAIL, ITEM, NEXT, PREV )\
                         PBL_LIST_PUSH( TAIL, HEAD, ITEM, PREV, NEXT )

#define PBL_LIST_UNLINK( HEAD, TAIL, ITEM, NEXT, PREV )\
{\
    if( (ITEM)->NEXT )\
        { (ITEM)->NEXT->PREV = (ITEM)->PREV; }\
    else\
        { (TAIL) = (ITEM)->PREV; }\
    if( (ITEM)->PREV )\
        { (ITEM)->PREV->NEXT = (ITEM)->NEXT; }\
    else\
        { (HEAD) = (ITEM)->NEXT; }\
}

// includes we need 
#include <math.h>
#include <stdlib.h>
#include <time.h>

#include "Utils.h"


typedef struct _savedpacket_s
{
    char * packetid;
    char * packet;
    int    length;
    time_t saved;
    time_t lastsent;

    struct _savedpacket_s * prev;
    struct _savedpacket_s * next;

} CMyScript_savedpacket_t;
 
/////////////////////////////////////////////////////////////////////////////
/*! CMyScript

  An ATL class implementing
  the Script Interface from blaxxunVRML.tlb


*/
class ATL_NO_VTABLE CMyScript : 
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CMyScript, &CLSID_MyScript>,
    public IDispatchImpl<IMyScript, &IID_IMyScript, &LIBID_NATIVESCRIPTDEMOLib>,
    public IDispatchImpl<Script, &IID_Script, &LIBID_blaxxunVRMLLib>
{
public:

    CMyScript();
    virtual ~CMyScript();

DECLARE_REGISTRY_RESOURCEID(IDR_MYSCRIPT)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CMyScript)
    COM_INTERFACE_ENTRY(IMyScript)
//DEL     COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY2(IDispatch, IMyScript)
    COM_INTERFACE_ENTRY(Script)
END_COM_MAP()


private :
    // private script state

    // pointer to CC3D script node containing this object 

    CComPtr<Node> script;

    bool fieldsAreOk;

    // fields in Script node we are interested in 

    //field MFString serverUrl 
    CComQIPtr<EventOutMFString> serverUrl;

    //field SFBool echo
    CComQIPtr<EventOutSFBool> echo;

    //eventOut MFString receive
    CComQIPtr<EventInMFString> receive;

    //eventOut MFString errors
    CComQIPtr<EventInMFString> errors;

    //eventOut MFString traces
    CComQIPtr<EventInMFString> traces;


    // global state
    // simply shadowed here 

// IMyScript
public:

    // Script methods 


    // script instance is created
    // we get the pointer to the owning Script node
    // inorder to get access to fields (and browser object)

    STDMETHOD(setContainer)(Node * container);
    STDMETHOD(loadScriptObject)(BSTR urlData);

    STDMETHOD(initialize)();

    STDMETHOD(shutdown)();

    // main worker function, process  an eventIn
    
    STDMETHOD(processEvent)(
            BSTR name, // name of eventIn function
            INT eventId, // ID, for speed, numbered by definition order
                         // (+3) for built-in fields
            EventOut * value,    // the value 
            DOUBLE timeStamp
            );

    STDMETHOD(eventsProcessed)();


    // tools
private:

    // output COM MFString buffer 
    //
    BSTR* outValue;
    int outValueCnt; 
    int outValueMax;

    bool hasOutValue() const { return outValueCnt>0; }

    // append single string to output buffer
    //
    bool AppendOut(LPCTSTR v) 
    {
        if (outValueCnt >= outValueMax)
            return false;

        CComBSTR bstrv (v); // convert & allocate BSTR 
        outValue[outValueCnt]= bstrv.Detach();
        outValueCnt++;

        return true;
    }

    // output COM MFString buffer
    //
    BSTR* errValue;
    int errValueCnt;
    int errValueMax;

    bool hasErrValue() const { return errValueCnt>0; }

    // append single string to error buffer
    //
    bool AppendErr(LPCTSTR v)
    {

        if (errValueCnt >= errValueMax)
            return false;

        CComBSTR bstrv (v); // convert & allocate BSTR
        errValue[errValueCnt]= bstrv.Detach();
        errValueCnt++;

        return true;
    }

    // output COM MFString buffer
    //
    BSTR* traValue;
    int traValueCnt;
    int traValueMax;

    bool hasTraValue() const { return traValueCnt>0; }

    // append single string to trace buffer
    //
    bool AppendTra(LPCTSTR v)
    {

        if (traValueCnt >= traValueMax)
            return false;

        CComBSTR bstrv (v); // convert & allocate BSTR
        traValue[traValueCnt]= bstrv.Detach();
        traValueCnt++;

        return true;
    }


    // socket to use
    int             UdpSocket;
    unsigned long   UdpPacketId;       // each packet gets a different one
    char          * UdpConnectionId;   // each connection gets a different one

    unsigned long   UdpServerIp;
    char          * UdpServerAddress;
    int             UdpServerAddressLength;

    // the send buffer used for udp
    //
    char          * UdpSendBuffer;
    int             UdpSendBufferLength;
    int             UdpSendBufferSize;

    // List of server URL BSTRs to use for connection
    //
    BSTR          * ServerUrlList;
    int             ServerUrlToUse;

    CMyScript_savedpacket_t * senthead;
    CMyScript_savedpacket_t * senttail;
    CMyScript_savedpacket_t * recvhead;
    CMyScript_savedpacket_t * recvtail;

    // initialize connection, create server address structure
    //
    int     ConnectionInit( );
    int     GetHostByName( char * hostname, unsigned long * ip );
    int     GetServerAddress( unsigned long ip, int port, char ** s );
    int     SetSendString( const char * s );
    int     SendBuffer( char * buffer, int len );
    int     SendToServer();
    int     ReceivePacket( char * packet, int length );
    int     ReceiveFromServer();
    int     PacketSave( int sentlist, char * packetid,
                        char * packet, int length );
    void    PacketDelete( int sentlist, CMyScript_savedpacket_t * item );

    CMyScript_savedpacket_t * PacketFind( int sentlist, char * packetid ); 

    void    PacketsHandle();
    time_t  lastPacketsHandle;
};

#endif //__MYSCRIPT_H_

