/* ==== fc_do_group.c =========================================================
 * Copyright (c) 1995 by Chris Provenzano, proven@mit.edu
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *  This product includes software developed by Chris Provenzano.
 * 4. The name of Chris Provenzano may not be used to endorse or promote 
 *	  products derived from this software without specific prior written
 *	  permission.
 *
 * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY 
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
 * SUCH DAMAGE.
 *
 * Description : Main fc functions.
 *
 *  1.00 95/08/03  proven
 *      -Started coding this file.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include "util.h"
#include "parse.h"
#include "fc.h"

/* TTT Remove printfs and use a generic error system. */

/* ==========================================================================
 * fc_do_ag()
 *
 * For now, only allow adding one group at a time.
 */
int fc_do_ag(struct fc * fc, char * data)
{
    struct fc_groups * fc_group, **fc_groupp;
	char * group_name;
	int result, i;

	/* if (group_name = parse_get_group(data, NULL)) { */
	if (group_name = parse_get_key(data, NULL)) { 
		/* Check if group name already exists */
		for (fc_groupp = &fc->groups; *fc_groupp; 
		  fc_groupp = &((*fc_groupp)->group_next)) {
			if ((result = strcmp(group_name, (*fc_groupp)->group_name)) == 0) {
				printf("Can't add currently used group name %s for command %s\n"
				  , group_name, "ag");
				return(NOTOK);
			}
			if (result < 0)
				break;
		}

		if (!parse_key_is_special(group_name)) {
			if (fc_group = fc_group_alloc(1)) {
				i = strlen(group_name) + 1;
				if (fc_group->group_name = (char*)malloc(i)) {
					fc_group->alloctype = IND_ALLOCED;
					strcpy(fc_group->group_name, group_name);
					fc_group->groupkey_first = NULL;
					fc_group->groupkey_count = 0;

					/* Insert group into group list */
					fc_group->group_next = *fc_groupp;
					*fc_groupp = fc_group;
					fc->groupcount++;
					return(OK);
				} else {
					printf("Can't alloc space for command %s\n", "ag");
					fc_group_free(fc_group);
				}
			} else {
				printf("Can't alloc space for command %s\n", "ag");
			}
		} else {
		printf("Can't add reserved key %s for command %s\n",group_name,"ag");
		}
	} else {
		printf("Not enough args for command %s\n", "af");
	}
	return(NOTOK);
}

/* ==========================================================================
 * fc_do_lg()
 */
enum fc_error fc_do_lg(struct fc * fc, char * data)
{
	struct fc_groups * fc_group = fc->groups;
	char ** strings;
	int i;

	if (fc->groupcount) {
		if (strings = (char **) malloc(sizeof(char *) * fc->groupcount)) {
			for (i = 0; fc_group; fc_group = fc_group->group_next) {
				strings[i++] = fc_group->group_name;
			}
			if (i != fc->groupcount) abort();
			fc_display(strings, i);
			free(strings);
		} else {
			return(FC_ENOMEM);
        }
	} else {
		printf("\n");
	}
	return(FC_OK);
}

/* ==========================================================================
 * fc_do_rg()
 */
enum fc_error fc_do_rg(struct fc * fc, char * data)
{
	return(FC_ENOSYS);
}

/* ==========================================================================
 * fc_do_agk()
 */
enum fc_error fc_do_agk(struct fc * fc, char * data)
{
	struct fc_groups * fc_group;
	struct fc_keys * fc_key;
	char * group_name, * key_name;
	int result, i, j, ok = 0;

	if (group_name = parse_get_key(data, &data)) {
		for (fc_group = fc->groups; fc_group; fc_group = fc_group->group_next) {
			if ((result = strcmp(group_name, fc_group->group_name)) < 0) 
				return(FC_BAD_GROUP);
			if (result == 0) 
				break;
		}
		while (key_name = parse_get_key(data, &data)) { 
			for (fc_key = fc->keys; fc_key; fc_key = fc_key->key_next) {
				if ((result = strcmp(key_name, fc_key->key_name)) < 0) 
					return(FC_BAD_KEY);
				if (result == 0) 
					break;
			}
			if (fc_group->groupkey_count) {
				for (i = 0; i < fc_group->groupkey_count; i++) {
					if (fc_key->key_num == fc_group->groupkey_first[i]->key_num)
						return(FC_GROUP_KEY_EXISTS);
					if (fc_key->key_num < fc_group->groupkey_first[i]->key_num)
						break;
				}
				if (fc_group->groupkey_first = 
				  (struct fc_keys **)realloc(fc_group->groupkey_first,
				  sizeof(struct fc_keys *) * fc_group->groupkey_count + 1)) {
					for (j = fc_group->groupkey_count; j > i; j--) {
						fc_group->groupkey_first[j] = 
						  fc_group->groupkey_first[j - 1];
					}
				} else {
					return(FC_ENOMEM);
				}
			} else {
				if ((fc_group->groupkey_first = (struct fc_keys **)malloc(
				  sizeof(struct fc_keys *))) == NULL) {
					return(FC_ENOMEM);
				}
				i = 0;
			}
			fc_group->groupkey_first[i] = fc_key;
			fc_group->groupkey_count++;
			ok++;
		}
	}
	return(ok ? FC_OK : FC_EINARGS);
}

/* ==========================================================================
 * fc_do_lgk()
 */
enum fc_error fc_do_lgk(struct fc * fc, char * data)
{
	struct fc_groups * fc_group;
	char * group_name, ** strings;
	int result, i;

	if (group_name = parse_get_key(data, &data)) { 
		for (fc_group = fc->groups; fc_group; fc_group = fc_group->group_next) {
			if ((result = strcmp(group_name, fc_group->group_name)) < 0) 
				return(FC_BAD_GROUP);
			if (result == 0) 
				break;
		}
		if (fc_group) {
			if (fc_group->groupkey_count) {
				if ((strings = (char **)malloc(sizeof(char *) * 
				  fc_group->groupkey_count)) == NULL) {
					return(FC_ENOMEM);
				}
				for (i = 0; i < fc_group->groupkey_count; i++) {
					strings[i] = fc_group->groupkey_first[i]->key_name;
				}
				fc_display(strings, fc_group->groupkey_count);
				free(strings);
			} else {
				printf("\n");
			}
		} else {
			return(FC_BAD_GROUP);
		}
	} else {
		return(FC_EINARGS);
	}
	return(FC_OK);
}

/* ==========================================================================
 * fc_do_rgk()
 */
enum fc_error fc_do_rgk(struct fc * fc, char * data)
{
	char * group_name, * key_name;
	struct fc_groups * fc_group;
	struct fc_keys * fc_key;
	int result, i, j, ok = 0;

	if (group_name = parse_get_key(data, &data)) {
		for (fc_group = fc->groups; fc_group; fc_group = fc_group->group_next) {
			if ((result = strcmp(group_name, fc_group->group_name)) < 0) 
				return(FC_BAD_GROUP);
			if (result == 0) 
				break;
		}
		while (key_name = parse_get_key(data, &data)) { 
			for (i = 0; i < fc_group->groupkey_count; i++) {
				if (!(strcmp(key_name, fc_group->groupkey_first[i]->key_name)))
					break;
			}
			if (i != fc_group->groupkey_count--) {
				for (j = i; j < fc_group->groupkey_count; j++) {
					fc_group->groupkey_first[j] = fc_group->groupkey_first[j+1];
				}
			} else {
				return(FC_GROUP_KEY_EXISTS_NOT);
			}
			if (fc_group->groupkey_count == 0) {
				free(fc_group->groupkey_first);
				fc_group->groupkey_first=NULL;
			}
			ok++;
		}
	}
	return(ok ? FC_OK : FC_EINARGS);
}

