from cffi import FFI
ffibuilder = FFI()
import pathlib
this_dir = pathlib.Path().absolute()

# cdef() expects a single string declaring the C types, functions and
# globals needed to use the shared object. It must be in valid C syntax.
ffibuilder.cdef("""
typedef struct {
    FILE* HdrFile_PS;      /* File handle for .JHR file */
    FILE* TxtFile_PS;      /* File handle for .JDT file */
    FILE* IdxFile_PS;      /* File handle for .JDX file */
    FILE* LrdFile_PS;      /* File handle for .JLR file */
    int   Errno_I;	   /* last i/o error */
    int   Locked_I;	   /* is area locked? */
    uint32_t LastUserPos_I;   /* last position of lastread record */
    uint32_t LastUserId_I;    /* userid for the last read lastread record */
} s_JamBase;

int JAM_OpenMB ( char* Basename_PC, s_JamBase** NewArea_PPS );
int JAM_CloseMB ( s_JamBase* Area_PS );

typedef struct {
    char  Signature[4];      /* <J><A><M> followed by <NUL> */
    uint32_t  DateCreated;       /* Creation date */
    uint32_t  ModCounter;        /* Last processed counter */
    uint32_t  ActiveMsgs;        /* Number of active (not deleted) msgs */
    uint32_t  PasswordCRC;       /* CRC-32 of password to access */
    uint32_t  BaseMsgNum;        /* Lowest message number in index file */
    char  RSRVD[1000];       /* Reserved space */
} s_JamBaseHeader;

typedef struct {
    char  Signature[4];              /* <J><A><M> followed by <NUL> */
    uint16_t Revision;                  /* CURRENTREVLEV */
    uint16_t ReservedWord;              /* Reserved */
    uint32_t  SubfieldLen;               /* Length of Subfields */
    uint32_t  TimesRead;                 /* Number of times message read */
    uint32_t  MsgIdCRC;                  /* CRC-32 of MSGID line */
    uint32_t  ReplyCRC;                  /* CRC-32 of REPLY line */
    uint32_t  ReplyTo;                   /* This msg is a reply to.. */
    uint32_t  Reply1st;                  /* First reply to this msg */
    uint32_t  ReplyNext;                 /* Next msg in reply chain */
    uint32_t  DateWritten;               /* When msg was written */
    uint32_t  DateReceived;              /* When msg was received/read */
    uint32_t  DateProcessed;             /* When msg was processed by packer */
    uint32_t  MsgNum;                    /* Message number (1-based) */
    uint32_t  Attribute;                 /* Msg attribute, see "Status bits" */
    uint32_t  Attribute2;                /* Reserved for future use */
    uint32_t  TxtOffset;                 /* Offset of text in text file */
    uint32_t  TxtLen;                    /* Length of message text */
    uint32_t  PasswordCRC;               /* CRC-32 of password to access msg */
    uint32_t  Cost;                      /* Cost of message */
} s_JamMsgHeader;

typedef struct {
    uint16_t LoID;       /* Field ID, 0 - 0xffff */
    uint16_t HiID;       /* Reserved for future use */
    uint32_t  DatLen;     /* Length of buffer that follows */
    char* Buffer;     /* DatLen bytes of data */
} s_JamSubfield;

typedef struct {
    uint16_t LoID;       /* Field ID, 0 - 0xffff */
    uint16_t HiID;       /* Reserved for future use */
    uint32_t  DatLen;     /* Length of buffer that follows */
} s_JamSaveSubfield;

typedef struct {
    uint32_t  UserCRC;    /* CRC-32 of destination username */
    uint32_t  HdrOffset;  /* Offset of header in .JHR file */
} s_JamIndex;

typedef struct {
    uint32_t  UserCRC;     /* CRC-32 of user name (lowercase) */
    uint32_t  UserID;      /* Unique UserID */
    uint32_t  LastReadMsg; /* Last read message number */
    uint32_t  HighReadMsg; /* Highest read message number */
} s_JamLastRead;

typedef struct {
    s_JamSubfield** Fields;
    uint32_t	    NumFields;
    uint32_t	    NumAlloc;
} s_JamSubPacket;

int JAM_LockMB( s_JamBase* Area_PS, int	Timeout_I );
int JAM_UnlockMB( s_JamBase* Area_PS );

int JAM_ReadMBHeader( s_JamBase* Area_PS, s_JamBaseHeader* Header_PS );				  
int JAM_WriteMBHeader( s_JamBase* Area_PS, s_JamBaseHeader* Header_PS );
int JAM_GetMBSize( s_JamBase* Area_PS, uint32_t* Messages_PI );

int JAM_ReadMsgHeader	( s_JamBase* 		Area_PS, 
			  uint32_t 		MsgNo_I,
			  s_JamMsgHeader*	Header_PS, 
			  s_JamSubPacket** 	SubfieldPack_PPS );
			  
int JAM_ReadMsgText	( s_JamBase* 		Area_PS, 
			  uint32_t 		Offset_I,
			  uint32_t 		Length_I,
			  char* 		Buffer_PC );
							  
int JAM_AddMessage	( s_JamBase* 		Area_PS,
			  s_JamMsgHeader*	Header_PS, 
			  s_JamSubPacket*	SubPack_PS,
			  char*		Text_PC,
			  uint32_t			TextLen_I );
							  
int JAM_AddEmptyMessage	( s_JamBase* 		Area_PS );

int JAM_DeleteMessage	( s_JamBase*		Base_PS,
			  uint32_t			MsgNo_I );

int JAM_ChangeMsgHeader	( s_JamBase* 		Area_PS,
			  uint32_t 		MsgNo_I,
			  s_JamMsgHeader* 	Header_PS );

int JAM_ClearMsgHeader	( s_JamMsgHeader* 	Header_PS );

int JAM_Errno		( s_JamBase* 		Area_PS );

s_JamSubPacket* JAM_NewSubPacket	( void );

int 		JAM_DelSubPacket	( s_JamSubPacket* SubPack_PS );

s_JamSubfield* 	JAM_GetSubfield		( s_JamSubPacket* SubPack_PS );

s_JamSubfield*	JAM_GetSubfield_R	( s_JamSubPacket* SubPack_PS , 
					  uint32_t* Count_PI);

int 		JAM_PutSubfield		( s_JamSubPacket* SubPack_PS,
					  s_JamSubfield*  Field_PS );

uint32_t JAM_Crc32		( char* Buffer_PC, uint32_t Length_I );
void free(void*);
""")

# int JAM_CloseMB         ( s_JamBase* 		Area_PS );
# 
# """)

# set_source() gives the name of the python extension module to
# produce, and some C source code as a string.  This C code needs
# to make the declarated functions, types and globals available,
# so it is often just the "#include".
ffibuilder.set_source("_pi_cffi",
"""
     #include "jam.h"   // the C header of the library
""",
     # libraries=['jamlib.a'],
     # library_dirs=[this_dir.as_posix()],
     # extra_link_args=["-Wl,-rpath,."],
     extra_link_args=["jamlib.a"],
     )   # library name, for the linker

if __name__ == "__main__":
    ffibuilder.compile(verbose=True)