/*
 * Copyright (C) 2007 Speecys Corporation
 *		Toshiaki Nozawa <nozawa@speecys.com>
 * All rights reserved.
 */
#include <netinet/in.h>
#include <stdbool.h>
#include <assert.h>

#include "../scifTrafMain.h"
#include "../libutil.h"
#include "clientUtil.h"

/**
 * edit 'ReqCmd' packet. using writePacket().
 *
 * return writePacket() value.
 */
int
writeReqCmdPacket(
    int d,		/** write descriptor	*/
    uint32_t seq,	/** sequence no	*/
    enum e_Priority pri,/** priority. valid any priority except 'PrioReqOnce'.*/
    enum e_cmnHF chflg,	/** common header flags	*/
    struct reqCmd *req, /** request. this area overwrite if htonF is true.*/
    bool htonF		/** hton flag to edit data*/
)
{
    if (htonF) {
	static const enum e_utype {NOUSE, LONG, SHORT, CHAR}
	unionType[NUM_e_reqCmd] = {
	    [reqCancel]		= LONG,

	    [ledDisp]		= LONG,
	    [ledSrvOn]		= LONG,
	    [ledSrvMv]		= SHORT,

	    [servoReset]	= NOUSE,
	    [servoMove]		= SHORT,
	    [servoPower]	= CHAR,
	    [servoCmpMgn]	= CHAR,
	    [servoCmpSlope]	= CHAR,
	    [servoPunch]	= SHORT,
	    [servoTorque]	= CHAR,
	    [servoTempLim]	= SHORT
	};

	assert(req->cmd < NUM_e_reqCmd);
	enum e_utype ut = unionType[(enum e_reqCmd)req->cmd];
	req->cmd = htonl(req->cmd);
	switch (ut) {
	case LONG:
	    req->arg.arg32_t = htonl(req->arg.arg32_t);
	    break;

	case SHORT:
	    for (u_int i = 0; i < ARR_LEN(req->arg.arg16_t); i++) {
		req->arg.arg16_t[i] = htons(req->arg.arg16_t[i]);
	    }
	    break;

	case CHAR:
	case NOUSE:
	    //NOP
	    break;

	default:
	    assert(false);
	    break;
	}
    }

    return writePacket(d, seq, pri, ReqCmd, chflg
	, sizeof(struct reqCmd), req, htonF);
}

/**
 * edit 'ReqOnce' packet. using writePacket().
 *
 * return writePacket() value.
 */
int
writeReqOncePacket(
    int d,		/** write descriptor	*/
    uint32_t seq,	/** sequence no	*/
    bool immeF,		/**
			 * immediate request flag.
			 * edit ReqOnce header to immediate req.
			 */
    enum e_cmnHF chflg,	/** common header flags	*/
    struct reqOnce *req,/** request. this area overwrite if htonF is true.*/
    uint16_t cmdLen,	/** req->cmd length	*/
    bool htonF		/** hton flag to edit data*/
)
{
    if (immeF) {
	req->flg |= FLG_END_OF_SEQ;	/** IMPORTANT!!	*/
	req->msec = 0;
	req->revive_msec = 0;
    }

    if (htonF) {
	req->flg = htonl(req->flg);
	req->msec = htonl(req->msec);
	req->revive_msec = htonl(req->revive_msec);
    }

    return writePacket(d, seq, PrioReqOnce, ReqOnce, chflg
		, cmdLen + sizeof(struct reqOnce), req, htonF);
}

/**
 * edit 'ReqDevPolling' packet. using writePacket().
 *
 * return writePacket() value.
 */
int
writeReqDevPollPacket(
    int d,		/** write descriptor	*/
    uint32_t seq,	/** sequence no	*/
    enum e_Priority pri,/** priority. valid any priority except 'PrioReqOnce'.*/
    enum e_cmnHF chflg,	/** common header flags	*/
    struct reqDevPoll *req, /** request. this area overwrite if htonF is true.*/
    bool htonF		/** hton flag to edit data*/
)
{
    if (htonF) {
	req->grp = htons(req->grp);
	req->enb = ntohs(req->enb);
	req->intervalMs = ntohl(req->intervalMs);
    }

    return writePacket(d, seq, pri, ReqDevPolling, chflg
	, sizeof(struct reqDevPoll), req, htonF);
}

/**
 * edit 'ReqEventHndling' packet. using writePacket().
 *
 * return writePacket() value.
 */
int
writeReqEventHndlPacket(
    int d,		/** write descriptor	*/
    uint32_t seq,	/** sequence no	*/
    enum e_Priority pri,/** priority. valid any priority except 'PrioReqOnce'.*/
    enum e_cmnHF chflg,	/** common header flags	*/
    struct reqEventHndl *req, /** request. this area overwrite if htonF is true.*/
    bool htonF		/** hton flag to edit data*/
)
{
    if (htonF) {
	enum e_reqEventHndlCat cat = req->cat;
	req->id = htons(req->id);
	req->cat = htons(req->cat);

	switch (cat) {
	case EHC_gt:
	case EHC_ge:
	case EHC_eq:
	case EHC_le:
	case EHC_lt:
	case EHC_ledBtn:
	    req->th.arg32_t = htonl(req->th.arg32_t);
	    break;

	case EHC_btwn:
	case EHC_ob:
	    for (u_int i = 0; i < ARR_LEN(req->th.arg16_t); i++) {
		req->th.arg16_t[i] = htons(req->th.arg16_t[i]);
	    }
	    break;

	default:
	    break;
	}
    }

    return writePacket(d, seq, pri, ReqEventHndl, chflg
	, sizeof(struct reqEventHndl), req, htonF);
}

int
writeReqDevStsPacket(
    int d,		/** write descriptor	*/
    uint32_t seq,	/** sequence no	*/
    enum e_Priority pri,/** priority. valid any priority except 'PrioReqOnce'.*/
    enum e_cmnHF chflg,	/** common header flags	*/
    struct reqDevSts *req, /** request. this area overwrite if htonF is true.*/
    bool htonF		/** hton flag to edit data*/
)
{
    if (htonF)	req->reqStsFlg = htonl(req->reqStsFlg);

    return writePacket(d, seq, pri, ReqDevSts, chflg
	, sizeof(struct reqEventHndl), req, htonF);
}
