/* dictcli.c
 * sdyoung@well.com
 *
 * This is an example program using libdict.  It is just a simple commandline
 * interface to the functions provided by libdict.
 *
 *   Copyright (c) 2001, 2002 Steven Young
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the
 *   "Software"), to deal in the Software without restriction, including
 *   without limitation the rights to use, copy, modify, merge, publish,
 *   distribute, sublicense, and/or sell copies of the Software, and to
 *   permit persons to whom the Software is furnished to do so, subject to
 *   the following conditions:
 *
 *   The above copyright notice and this permission notice shall be
 *   included in all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 *   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 *   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include <stdio.h>
#include <sysexits.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include "libdict.h"

struct ld_conn *conn = NULL;
int debug;

void discofn(char *arg) {
	printf("Disconnecting...\n");
	ld_freeconn(conn);
	conn = NULL;
}

void connfn(char *arg) {
	if(!arg) {
		printf("usage: connect server.\n");
		return;
	}

	if(conn) {
		printf("Error: You are already connected to a server.\n");
		return;
	}

	conn = ld_newconn(arg, 0, 10, NULL, debug ? LD_True : LD_False);
	
	if(ld_geterrno(conn) != LDOK) {
		printf("Connect failed: %s\n", ld_strerror(ld_geterrno(conn)));
		ld_freeconn(conn);
		conn = NULL;
		return;
	}
	printf("Connected to %s.\n", arg);
}

void helpfn(char *arg) {
	printf("Command summary:\n");
	printf("connect [server] - connect to a server.\n");
	printf("disconnect - disconnect from a server.\n");
	printf("auth [username] - authenticate.\n");
	printf("info - display server information.\n");
	printf("listdbs - list databases available.\n");
	printf("liststrats - list strategies available.\n");
	printf("setstrat [strategy] - set strategy to use.\n");
	printf("setdb [db] - set database to use.\n");
	printf("define [word] - define a word.\n");
	printf("match [word] - match a word.\n");
	printf("getrep - get server response to last command.\n");
	printf("prerr - print error status.\n");
	printf("quit - exit.\n");
}

void infofn(char *arg) {
	printf("Server information:\n");
	printf("%s\n", ld_serverinfo(conn));
}

void dblistfn(char *arg) {
	struct ld_dbs **dblist;
	int i = 0;

	printf("Database list:\n");
	dblist = ld_getdbs(conn);
	while(dblist[i]) {
		printf("%s\n\t%s\n", dblist[i]->ld_dbname, dblist[i]->ld_dbdesc);
		i++;
	}
}

void stratlistfn(char *arg) {
	struct ld_dbs **stratlist;
	int i = 0;

	printf("Strategy list:\n");
	stratlist = ld_getstrats(conn);
	while(stratlist[i]) {
		printf("%s\n\t%s\n", stratlist[i]->ld_dbname, stratlist[i]->ld_dbdesc);
		i++;
	}
}

void authfn(char *arg) {
	char *pw;
	
	pw = getpass("Password: ");

	if(ld_auth(conn, arg, pw) == LD_False) {
		printf("Authentication failed.\n");
	} else {
		printf("Authentication succeeded.\n");
	}
}

void setstratfn(char *arg) {
	if(ld_setstrat(conn, arg) == LD_False) {
		printf("Invalid strategy selected.\n");
	} else {
		printf("Strategy changed to '%s'.\n", arg);
	}
}

void setdbfn(char *arg) {
	if(ld_setdb(conn, arg) == LD_False) {
		printf("Invalid database selected.\n");
	} else {
		printf("Database changed to '%s'.\n", arg);
	}
}

void deffn(char *arg) {
	struct ld_defanswer **ans;
	int i = 0;

	if(!(ans = ld_define(conn, arg))) {
		printf("No results for '%s'.\n", arg);
	} else {
		while(ans[i]) {
			printf("Found in dictionary '%s':\n", ans[i]->ld_ansdict);
			printf("%s\n", ans[i]->ld_ansdef);
			i++;
		}
	}
}

void matchfn(char *arg) {
	struct ld_matchanswer **ans;
	int i = 0;

	if(!(ans = ld_match(conn, arg))) {
		printf("No results for '%s'.\n", arg);
	} else {
		while(ans[i]) {
			printf("'%s' found in dictionary '%s'.\n", ans[i]->ld_answord,
				   ans[i]->ld_ansdict);
			i++;
		}
	}
}

void getrepfn(char *arg) {
	printf("Last server response:\n");
	printf("%s\n", ld_getsrvreply(conn));
}

void prerrfn(char *arg) {
	printf("Error status:\n");
	printf("ld errno: %d (%s)\n", ld_geterrno(conn), ld_strerror(ld_geterrno(conn)));
	printf("errno: %d (%s)\n", errno, strerror(errno));
}

void cliloop() {
	char quit = 0, ok, *p1;
	char inbuf[BUFSIZ];
	int idx = 0;
	struct {
		char *keyword;
		char connreqd;
		char argreqd;
		void (*fn)(char *);
	} fns[] = { { "disconnect", 1, 0, discofn },
	            { "connect", 0, 1, connfn },
			    { "auth", 1, 1, authfn },
			    { "info", 1, 0, infofn },
			    { "listdbs", 1, 0, dblistfn },
			    { "liststrats", 1, 0, stratlistfn },
			    { "help", 0, 0, helpfn },
			    { "setstrat", 1, 1, setstratfn },
 			    { "setdb", 1, 1, setdbfn },
			    { "define", 1, 1, deffn },
			    { "match", 1, 1, matchfn },
			    { "getrep", 1, 0, getrepfn },
			    { "prerr", 1, 0, prerrfn },
			    { NULL, 0, 0, NULL } };

	while(!quit) {
		printf("dict> ");
		fgets(inbuf, BUFSIZ, stdin);
		inbuf[strlen(inbuf) - 1] = '\0';
		if((p1 = strchr(inbuf, ' '))) {
			*p1 = '\0';
			p1++;
		}
		if(!strcasecmp(inbuf, "quit")) {
			quit++;
			continue;
		}
		for(idx = 0, ok = 0; fns[idx].keyword && !ok; idx++) {
			if(!strcasecmp(inbuf, fns[idx].keyword)) {
				ok++;
				if(fns[idx].connreqd && (!conn)) 
					printf("Error: You are not connected to a server.\n");
				else 
					if(fns[idx].argreqd && (!p1)) 
						printf("Error: That command requires an argument.\n");
					else
						(*fns[idx].fn)(p1);
			}
		}
		if(!ok) 
			printf("Error: Invalid command.  Type \"help\" for a command list.\n");
	}
}

int main(int argc, char **argv) {
	char optch;

	while((optch = getopt(argc, argv, "dh")) != EOF) {
		switch(optch) {
			case 'd': 
				debug++;
				break;
			case 'h':
				printf("usage: dictcli [-d]\n");
				exit(EX_USAGE);
		}
	}

	if(debug) 
		printf("Debugging enabled.\n");

	cliloop();
	if(conn) 
		ld_freeconn(conn);
	return(EX_OK);
}
