/*
Copyright (C) MOXA Inc. All rights reserved.

This software is distributed under the terms of the
MOXA License.  See the file COPYING-MOXA for details.
*/
#include <windows.h>
#include<stdio.h>
#include<stdlib.h>
#include<getopt.h>  
#pragma comment(lib,"getopt.lib") 
#include "mxdgio.h"
using namespace std;

#define UNSET 	-1

enum action_type {
	GET_DIN_STATUS = 0,
	GET_DOUT_STATUS = 1,
	SET_DOUT_STATUS = 2,
	GET_DIN_COUNT = 3,
	GET_DOUT_COUNT = 4
};

struct action_struct {
	int type;
	int port;
	int mode;
	int count;
};

void usage(FILE *fp)
{
	fprintf(fp, "Usage:\n");
	fprintf(fp, "	mx-dio-ctl <-i #DIN |-o #DOUT >\n");
	fprintf(fp, "	mx-dio-ctl <-o #DOUT > -m <status>\n");
	fprintf(fp, "	mx-dio-ctl <-c DIN:0 | DOUT:1 >\n");
	fprintf(fp, "OPTIONS:\n");
	fprintf(fp, "	-i <#DIN>\n");
	fprintf(fp, "		Get status of target DIN port\n");
	fprintf(fp, "		DIN index start from 0 \n");
	fprintf(fp, "	-o <#DOUT>\n");
	fprintf(fp, "		Get status of target DOUT port\n");
	fprintf(fp, "		DOUT index start from 0\n");
	fprintf(fp, "	-m <#Status>\n");
	fprintf(fp, "		Set status for target DOUT port\n");
	fprintf(fp, "		0 --> LOW\n");
	fprintf(fp, "		1 --> HIGH\n");
	fprintf(fp, "	-c <#Count>\n");
	fprintf(fp, "		Get DIN/DOUT port count\n");
	fprintf(fp, "		0 --> DIN\n");
	fprintf(fp, "		1 --> DOUT\n");
	fprintf(fp, "\n");
	fprintf(fp, "Example:\n");
	fprintf(fp, "	Get value from DIN port 1\n");
	fprintf(fp, "	# mx-dio-ctl -i 1\n");
	fprintf(fp, "\n");
	fprintf(fp, "	Get value from DOUT port 1\n");
	fprintf(fp, "	# mx-dio-ctl -o 1\n");
	fprintf(fp, "\n");
	fprintf(fp, "	Set DOUT port 2 value to LOW\n");
	fprintf(fp, "	# mx-dio-ctl -o 2 -m 0\n");
	fprintf(fp, "\n");
	fprintf(fp, "	Get DOUT port count\n");
	fprintf(fp, "	# mx-dio-ctl -c 1\n");
}

int my_atoi(const char *nptr, int *number)
{
	int tmp;

	tmp = atoi(nptr);
	if (tmp != 0) {
		*number = tmp;
		return 0;
	}
	else {
		if (!strcmp(nptr, "0")) {
			*number = 0;
			return 0;
		}
	}
	return -1;
}

void do_action(struct action_struct action)
{
	switch (action.type) {
	case GET_DIN_STATUS:
		action.mode = GetDinStatus(action.port);
		if (action.mode < 0) {
			fprintf(stderr, "Failed to get DIN status\n");
			exit(1);
		}
		printf("DIN port %d status: %d\n", action.port, action.mode);
		break;
	case GET_DOUT_STATUS:
		action.mode = GetDoutStatus(action.port);
		if (action.mode < 0) {
			fprintf(stderr, "Failed to get DOUT status\n");
			exit(1);
		}
		printf("DOUT port %d status: %d\n", action.port, action.mode);
		break;
	case SET_DOUT_STATUS:
		if (SetDoutStatus(action.port, action.mode) < 0) {
			fprintf(stderr, "Failed to set DOUT status\n");
			exit(1);
		}
		printf("DOUT port %d status: %d\n", action.port, action.mode);
		break;
	case GET_DIN_COUNT:
		action.count = GetDinCount();

		if (action.count < 0) {
			fprintf(stderr, "Failed to get DOUT count\n");
			exit(1);
		}
		printf("DIN port count: %d\n", action.count);
		break;
	case GET_DOUT_COUNT:
		action.count = GetDoutCount();

		if (action.count < 0) {
			fprintf(stderr, "Failed to get DOUT count\n");
			exit(1);
		}
		printf("DOUT port count: %d\n", action.count);
		break;
	}
}

int main(int argc, char**argv)
{
	struct action_struct action = { UNSET, UNSET, UNSET, UNSET };
	int cmd;

	while (1) {
		cmd = getopt(argc, argv, "hi:o:m:c:");
		if (cmd == -1)
			break;

		switch (cmd) {
		case 'h':
			usage(stdout);
			exit(0);
		case 'c':
			if (my_atoi(optarg, &action.count) != 0) {
				fprintf(stderr, "%s is not a number\n", optarg);
				exit(1);
			}

			if (action.count == 0)
				action.type = GET_DIN_COUNT;
			else if (action.count == 1)
				action.type = GET_DOUT_COUNT;
			else {
				fprintf(stderr, "Index error: Get DIN port count use -c 0 or Get DOUT port count use -c 1\n");
				exit(1);
			}
			
			break;
		case 'i':
			action.type = GET_DIN_STATUS;
			if (my_atoi(optarg, &action.port) != 0) {
				fprintf(stderr, "%s is not a number\n", optarg);
				exit(1);
			}
			break;
		case 'm':
			action.type = SET_DOUT_STATUS;
			if (my_atoi(optarg, &action.mode) != 0) {
				fprintf(stderr, "%s is not a number\n", optarg);
				exit(1);
			}
			break;
		case 'o':
			if(action.mode == UNSET)
				action.type = GET_DOUT_STATUS;
			else
				action.type = SET_DOUT_STATUS;
			if (my_atoi(optarg, &action.port) != 0) {
				fprintf(stderr, "%s is not a number\n", optarg);
				exit(1);
			}
			break;

		default:
			usage(stderr);
			exit(99);
		}
	}

	if (optind < argc) {
		fprintf(stderr, "non-option arguments found: ");
		while (optind < argc)
			fprintf(stderr, "%s ", argv[optind++]);
		fprintf(stderr, "\n");

		usage(stderr);
		exit(99);
	}

	if (action.count == UNSET && action.port == UNSET) {
		usage(stderr);
		exit(99);
	}

	do_action(action);
	exit(0);
}