/************************************************************
 *
 * COPYRIGHT (C) HITACHI,LTD. 2002-2003 ALL RIGHTS RESERVED.
 * WRITTEN BY HITACHI SYSTEMS DEVELOPMENT LABORATORY,
 *            HITACHI CENTRAL RESEARCH LABORATORY.
 *
 * Created by K.Hatasaki <keisukeh@crl.hitachi.co.jp>
 *
 ************************************************************/

#include "command.h"

#define LKST_ETYPE_DEF_MNEMONICS
#include <linux/lkst_events.h>

int lkst_maskset_getid(int fd, const char *name)
{
	int ret;
	struct lkst_maskset_getparam mgp;
	if(!name || name[0]=='\0')return -EINVAL;
	strncpy(mgp.name, name, LKST_MASKSET_NAME_LEN-1);
	if( (ret = ioctl(fd, LKST_IOC_MASKSET_GETID, &mgp)) < 0)
		return ret;
	return mgp.id;
}

char * lkst_maskset_getname(int fd, char *buf, lkst_maskset_id id, size_t len)
{
	int i, retval;
	struct lkst_maskset_listparam lp;
	struct lkst_maskset_listent listent[LKST_MASKSET_TBL_MAX];

	lp.listent_size = LKST_MASKSET_LISTENT_SIZE(LKST_MASKSET_TBL_MAX);
	lp.listent = listent;

	retval = ioctl(fd, LKST_IOC_MASKSET_LIST, &lp);	/* maskset list */
	if (retval < 0) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_LIST) error: %s\n", strerror(errno));
		return NULL;
	}

	for (i = 0; i < LKST_MASKSET_TBL_MAX; i++) {
		if (id == listent[i].id && listent[i].name[0]) {
			strncpy(buf,lp.listent[i].name, len);
			return buf;
		}
	}
	return NULL;
}

int lkst_maskset_getcurrent(int fd)
{
	int ret;
	struct lkst_maskset_listparam lp;
	struct lkst_maskset_listent listent[1];

	lp.listent_size = LKST_MASKSET_LISTENT_SIZE(1);
	lp.listent = listent;

	ret = ioctl(fd, LKST_IOC_MASKSET_LIST, &lp);	/* maskset list */
	
	return (ret < 0) ? ret : lp.current_id;
}

void maskset_getid(const char *name )
{
	int fd;
	int ret;
	fd = open_dev();
	if((ret =lkst_maskset_getid(fd, name))< 0){
		fprintf(stderr, "error: failed to get id from name %s\n", name );
		exit(1);
	}
	close(fd);
	printf("%d (0x%02x)\n", ret, ret);
}

int lkst_maskset_get_uniqname(int fd, char *buf, const char *prefix, int size)
{
	int i,j,ret,jmax;
	struct lkst_maskset_listparam lp;
	struct lkst_maskset_listent listent[LKST_MASKSET_TBL_MAX];

	if ( strlen(prefix) >= size-4 ) {
		buf[0]='\0';
		return 0;
	}
	lp.listent_size = LKST_MASKSET_LISTENT_SIZE(LKST_MASKSET_TBL_MAX);
	lp.listent = listent;

	ret = ioctl(fd, LKST_IOC_MASKSET_LIST, &lp);	/* maskset list */
	if (ret < 0) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_LIST) error: %s\n", strerror(errno));
		buf[0]='\0';
		return 0;
	}

	for (j =0;listent[j].id != LKST_MASKSET_ID_VOID && 
	     j<LKST_MASKSET_TBL_MAX;j++);
	jmax =j;
	
	for (i = 0;i<255-32;i++){
		snprintf(buf, size, "%s%d", prefix, i);
		for (j =0;j<jmax;j++) {
			if (strcmp(listent[j].name, buf)==0)break;
		}
		if(j==jmax)break;
	}
	return (i==255-32)?0:1;
}

	
void maskset_list(void)
{
	int retval;
	int fd;
	int i;

	lkst_maskset_id id;
	struct lkst_maskset_listparam lp;
	struct lkst_maskset_listent listent[LKST_MASKSET_TBL_MAX];

	fd = open_dev();

	lp.listent_size = LKST_MASKSET_LISTENT_SIZE(LKST_MASKSET_TBL_MAX);
	lp.listent = listent;

	retval = ioctl(fd, LKST_IOC_MASKSET_LIST, &lp);	/* maskset list */

	if (retval < 0) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_LIST) error: %s\n", strerror(errno));
		exit(1);
	}

	printf("maskset_id\tlength\t\tname\n");
	for (i = 0; i < LKST_MASKSET_TBL_MAX; i++) {
		id = lp.listent[i].id;
		if (id != LKST_MASKSET_ID_VOID) {
			printf(" %3d%c (0x%02x)", id, 
			       (id == lp.current_id) ? '*': ' ', 
			       id);
			printf("\t %4d\t\t%s\n",
			       lp.listent[i].len,
			       lp.listent[i].name);
		}
	}

	close(fd);
}

static void maskset_read_disp(struct lkst_maskset_param *param,
			      int all, int disp)
{
	struct lkst_maskset_body *maskset;
	int	event_type;
	char	*event_type_name;
	int i;

	maskset = param->maskset;

	printf("# ID=%d\n", param->id);
	printf("# maskset name=%s\n# length=%d\n",
	       maskset->name, maskset->len);

	if (disp) {
		printf("# event_type	event_handler_ID\n");
		for (i = 0; i < maskset->len; i++) {
			printf(" 0x%03x		 0x%02x\n",
			       maskset->entry[i].event_type,
			       maskset->entry[i].id);
		}
	} else {
		printf("# event_type\tevent_name\t\tevent_handler_ID\n");
		for (i = 0; i < maskset->len; i++) {
			event_type = maskset->entry[i].event_type,
				event_type_name = lkst_event_type_mnemonics[event_type];
			if (event_type_name || all)
				printf(" 0x%03x\t\t%-24s\t0x%02x\n",
				       event_type,
				       event_type_name,
				       maskset->entry[i].id);
		}
	}
}


void maskset_read(lkst_maskset_id id, const char * name, int all, int disp)
{
	int retval;
	int fd;
	struct lkst_maskset_param param;
	struct lkst_maskset_body maskset;

	fd = open_dev();

	if(name && name[0]){
		retval = lkst_maskset_getid(fd, name);
		if ( retval < 0 || retval == LKST_MASKSET_ID_VOID ) {
			fprintf(stderr, "error: %s is not found\n", name);
			exit(1);
		}
		id = (lkst_maskset_id)retval;
	}
	
	param.id = id;
	param.maskset_size = LKST_MASKSET_SIZE(LKST_MASKSET_TABLE_LEN_MAX);
	param.maskset = &maskset;


	retval = ioctl(fd, LKST_IOC_MASKSET_READ, &param); /* maskset read */

	if (retval) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_READ) error: %s\n", strerror(errno));
		exit(1);
	}

	maskset_read_disp(&param, all, disp);

	close(fd);
}

void maskset_read_all(int all, int disp)
{
	int retval;
	int fd;
	int i;
	struct lkst_maskset_param param;
	struct lkst_maskset_body maskset;
	struct lkst_maskset_listparam lp;
	struct lkst_maskset_listent listent[LKST_MASKSET_TBL_MAX];

	fd = open_dev();

	lp.listent_size = LKST_MASKSET_LISTENT_SIZE(LKST_MASKSET_TBL_MAX);
	lp.listent = listent;

	retval = ioctl(fd, LKST_IOC_MASKSET_LIST, &lp);	/* maskset list */

	if (retval) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_LIST) error: %s\n", strerror(errno));
		exit(1);
	}

	for (i = 0; i < LKST_MASKSET_TBL_MAX; i++) {
		if (lp.listent[i].id != LKST_MASKSET_ID_VOID) {

			param.id = lp.listent[i].id;
			param.maskset_size = 
				LKST_MASKSET_SIZE(LKST_MASKSET_TABLE_LEN_MAX);
			param.maskset = &maskset;

			retval = ioctl(fd,  LKST_IOC_MASKSET_READ, &param);

			if (retval) {
				fprintf(stderr, "ioctl(LKST_IOC_MASKSET_READ) error: %s\n",
					strerror(errno));
				exit(1);
			}
			maskset_read_disp(&param, all, disp);
		}
	}

	close(fd);
}


void maskset_set(lkst_maskset_id id, const char *name)
{
	int retval;
	lkst_maskset_id maskset_id;
	int fd;

	fd = open_dev();

	if(name && name[0]){
		retval = lkst_maskset_getid(fd, name);
		if ( retval < 0 || retval == LKST_MASKSET_ID_VOID ) {
			fprintf(stderr,"error: %s is not found\n", name);
			exit(1);
		}
		id = (lkst_maskset_id)retval;
	}

	maskset_id = id;

	retval = ioctl(fd, LKST_IOC_MASKSET_SET, maskset_id); /* maskset set */

	if (retval) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_SET) error: %s\n", strerror(errno));
		exit(1);
	}

	printf("Currently selected maskset was changed to id=%d\n", maskset_id);

	close(fd);
}

void maskset_config(lkst_maskset_id id, const char *name,
		    int	event_type, lkst_evhandler_id evhandler_id)
{
	int retval;
	int fd;

	struct lkst_maskset_param param;
	struct lkst_maskset_body body;

	body.name[0] = '\0';
	body.len = 1;
	body.entry[0].event_type = event_type;
	body.entry[0].id = evhandler_id;

	fd = open_dev();

	if(name && name[0]){
		retval = lkst_maskset_getid(fd, name);
		if ( retval < 0 || retval == LKST_MASKSET_ID_VOID ) {
			fprintf(stderr,"error: %s is not found\n", name);
			exit(1);
		}
		id = (lkst_maskset_id)retval;
	}else if(id == LKST_MASKSET_ID_VOID) {
		/*both omitted, then get current maskset id*/
		retval = lkst_maskset_getcurrent(fd);
		if ( retval < 0 || retval == LKST_MASKSET_ID_VOID ) {
			fprintf(stderr,"error: failed to get current maskset\n");
			exit(1);
		}
		id = (lkst_maskset_id)retval;
	}
	
	/* content of new maskset */
	param.id = id;
	param.maskset_size = LKST_MASKSET_SIZE(body.len);
	param.maskset = &body;

	retval = ioctl(fd, LKST_IOC_MASKSET_WRITE, &param); /* maskset write */

	if (retval) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_WRITE) error: %s\n", strerror(errno));
		exit(1);
	}

	close(fd);
}

	
void maskset_write(lkst_maskset_id *id, const char *file_name,
		   const char *maskset_name)
{
	int retval;
	int fd;
	FILE *fp_i;

	char line[255], *buf[10];
	struct lkst_maskset_param param;
	int	i;
	int	event_type;
	int lcnt = 0;
	lkst_evhandler_id	evhandler_id;

	struct lkst_maskset_body body = {
		name:"",
		len:0,
		entry:{
			{LKST_ETYPE_MAX, 0}
		}
	};

	if (0 == strncmp("-", file_name, 2)) {
		fp_i = stdin;
		printf("event_type	event_handler_ID\n");
	} else if ((fp_i = fopen(file_name, "r")) == NULL) {
		perror("input");
		exit(1);
	}

				/* read maskset body from an input file */
	while (NULL != fgets (line, 255, fp_i)) {

		lcnt++;

		if( line[0] == '#' )
			continue;
		if ((buf[0] = (char *) strtok(line, "\t \n")) == NULL)
			continue;

		for(i=1; (buf[i] = (char *)strtok(NULL,"\t \n")) != NULL; i++);

		if (buf[1] == NULL) {
			fprintf(stderr, "Error: Invalid data at line %d\n",
				lcnt - 1);
			exit(1);
		}

		event_type = strtol(buf[0], NULL, 0);

		evhandler_id = (lkst_evhandler_id) 
			strtol(buf[i-1], NULL, 0);

		body.entry[body.len].event_type = event_type;
		body.entry[body.len].id = evhandler_id;
		body.len++;
	}
	
	fd = open_dev();
	/* decide maskset name */
	if (maskset_name==NULL || maskset_name[0]=='\0') {
		if (lkst_maskset_getname(fd, body.name, *id,
				     LKST_MASKSET_NAME_LEN) == NULL){
			lkst_maskset_get_uniqname(fd, body.name, "new_maskset",
						  LKST_MASKSET_NAME_LEN);
		}
	} else {
		strncpy(body.name, maskset_name, LKST_MASKSET_NAME_LEN);
	}

	/* content of new maskset */
	param.id = *id;
	param.maskset_size = LKST_MASKSET_SIZE(body.len);
	param.maskset = &body;

	retval = ioctl(fd, LKST_IOC_MASKSET_WRITE, &param); /* maskset write */

	if (retval < 0) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_WRITE) error: %s\n", strerror(errno));
		exit(1);
	}

	*id = param.id;

	printf("New maskset id=%d was written. (Name:%s)\n", param.id, 
	       body.name);

	close(fd);
}

void maskset_delete(lkst_maskset_id id, const char *name)
{
	int retval;
	int fd;

	fd = open_dev();

	if(name && name[0]){
		retval = lkst_maskset_getid(fd, name);
		if ( retval < 0 || retval == LKST_MASKSET_ID_VOID ) {
			fprintf(stderr,"error: %s is not found\n", name);
			exit(1);
		}
		id = (lkst_maskset_id)retval;
	}

	retval = ioctl(fd, LKST_IOC_MASKSET_DELETE, id); /* maskset_delete */

	if (retval) {
		fprintf(stderr, "ioctl(LKST_IOC_MASKSET_DELETE) error: %s\n", strerror(errno));
		exit(1);
	}

	printf("Maskset id=%d was deleted.\n", id);

	close(fd);
}
