/*
 * Copyright (c) 1999 The University of Utah and
 * the Computer Systems Laboratory at the University of Utah (CSL).
 *
 * This file is part of Flick, the Flexible IDL Compiler Kit.
 *
 * Flick is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * Flick is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Flick; see the file COPYING.  If not, write to
 * the Free Software Foundation, 59 Temple Place #330, Boston, MA 02111, USA.
 */

#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>

#include <mom/compiler.h>
#include <mom/libmeta.h>

data_channel_index meta_add_channel(meta *m, io_file_index input,
				    const char *id)
{
	data_channel_index retval;
	
	retval = m->channels.channels_len++;
	m->channels.channels_val = (data_channel *)
		mustrealloc(m->channels.channels_val,
			    sizeof(data_channel) * m->channels.channels_len);
	m->channels.channels_val[retval].input = input;
	m->channels.channels_val[retval].id = ir_strlit(id);
	m->channels.channels_val[retval].flags = 0;
	m->channels.channels_val[retval].outputs.outputs_len = 0;
	m->channels.channels_val[retval].outputs.outputs_val = 0;
	return( retval );
}

data_channel_index meta_find_channel(meta *m, io_file_index input,
				     const char *id, int flags)
{
	data_channel_index retval = -1;
	unsigned int lpc;
	
	for( lpc = 0;
	     (lpc < m->channels.channels_len) && (retval == -1);
	     lpc++ ) {
		if( (m->channels.channels_val[lpc].input == input) &&
		    (m->channels.channels_val[lpc].flags & flags) &&
		    (!strcmp(m->channels.channels_val[lpc].id, id)) )
			retval = lpc;
	}
	return( retval );
}

void meta_add_channel_output(meta *m, data_channel_index channel,
			     io_file_index output)
{
	data_channel *dc;
	int i;
	
	dc = &m->channels.channels_val[channel];
	if( dc->flags & DATA_CHANNEL_SQUELCHED )
		return;
	i = dc->outputs.outputs_len++;
	dc->outputs.outputs_val = (io_file_index *)
		mustrealloc(dc->outputs.outputs_val,
			    sizeof(io_file_index) * dc->outputs.outputs_len);
	dc->outputs.outputs_val[i] = output;
}

data_channel_mask meta_make_channel_mask(int tag, ...)
{
	data_channel_mask retval;
	va_list args;
	
	retval.mask_flags = 0;
	retval.input = 0;
	retval.id = "";
	retval.set_flags = 0;
	retval.unset_flags = 0;
	va_start(args, tag);
	while( tag != CMA_TAG_DONE ) {
		switch( tag ) {
		case CMA_MatchesInput:
			retval.input = va_arg(args, io_file_mask *);
			retval.mask_flags |= DATA_CHANNEL_MASK_HAS_INPUT;
			break;
		case CMA_ExcludesInput:
			retval.input = va_arg(args, io_file_mask *);
			break;
		case CMA_MatchesID:
			retval.id = va_arg(args, char *);
			retval.mask_flags |= DATA_CHANNEL_MASK_HAS_ID;
			break;
		case CMA_ExcludesID:
			retval.id = va_arg(args, char *);
			break;
		case CMA_SetFlags:
			retval.set_flags = va_arg(args, unsigned int);
			break;
		case CMA_UnsetFlags:
			retval.unset_flags = va_arg(args, unsigned int);
			break;
		default:
			panic("CMA_ Tag %d not understood", tag);
			break;
		}
		tag = va_arg(args, int);
	}
	va_end(args);
	return( retval );
}

int meta_match_channel_mask(meta *m, data_channel_mask *dcm,
			    data_channel_index channel)
{
	data_channel *dc;
	int retval = 1;
	
	dc = &m->channels.channels_val[channel];
	if( dcm->input ) {
		if( dcm->mask_flags & DATA_CHANNEL_MASK_HAS_INPUT )
			retval = meta_match_file_mask(m, dcm->input,
						      dc->input);
		else
			retval = !meta_match_file_mask(m, dcm->input,
						       dc->input);
	}
	if( retval && dcm->id[0] ) {
		if( ((dcm->mask_flags & DATA_CHANNEL_MASK_HAS_ID) &&
		     strcmp(dcm->id, dc->id)) ||
		    (!(dcm->mask_flags & DATA_CHANNEL_MASK_HAS_ID) &&
		     !strcmp(dcm->id, dc->id)) )
			retval = 0;
	}
	if( retval && ((dc->flags & dcm->set_flags) != dcm->set_flags) )
		retval = 0;
	if( retval && (dc->flags & dcm->unset_flags) )
		retval = 0;
	return( retval );
}

void meta_squelch_channel(meta *m, data_channel_index channel)
{
	data_channel *dc;
	
	dc = &m->channels.channels_val[channel];
	dc->flags |= DATA_CHANNEL_SQUELCHED;
}

void meta_squelch_channels(meta *m, data_channel_mask dcm)
{
	int lpc;
	
	for( lpc = 0; lpc < m->channels.channels_len; lpc++ ) {
		if( meta_match_channel_mask(m, &dcm, lpc) )
			meta_squelch_channel(m, lpc);
	}
}

void meta_check_channel(meta *m, data_channel_index channel)
{
	unsigned int lpc;
	data_channel *dc;
	
	dc = &m->channels.channels_val[channel];
	assert(dc->input >= 0);
	assert(dc->input < m->files.files_len);
	assert(dc->id);
	for( lpc = 0; dc->outputs.outputs_len; lpc++ ) {
		assert( dc->outputs.outputs_val[lpc] >= 0 );
		assert( dc->outputs.outputs_val[lpc] < m->files.files_len);
	}
}

static void my_i_fprintf(FILE *file, int indent, char *format, ...)
{
	va_list args;
	int lpc;
	
	for( lpc = 0; lpc < indent; lpc++ )
		fprintf(file, " ");
	va_start(args, format);
	vfprintf(file, format, args);
	va_end(args);
}

void meta_print_channel(meta *m, FILE *file, int indent,
			data_channel_index channel)
{
	data_channel *dc;
	unsigned int lpc;
	
	dc = &m->channels.channels_val[channel];
	my_i_fprintf(file, indent, "Channel #%d = {\n", channel);
	indent++;
	my_i_fprintf(file, indent, "Input:      %d\n", dc->input);
	my_i_fprintf(file, indent, "ID:         %s\n", dc->id);
	my_i_fprintf(file, indent, "Flags:     ");
	if( dc->flags & DATA_CHANNEL_SQUELCHED )
		fprintf(file, " DATA_CHANNEL_SQUELCHED");
	if( dc->flags & DATA_CHANNEL_DECL )
		fprintf(file, " DATA_CHANNEL_DECL");
	if( dc->flags & DATA_CHANNEL_IMPL )
		fprintf(file, " DATA_CHANNEL_IMPL");
	fprintf(file, "\n");
	my_i_fprintf(file, indent, "Outputs:   ");
	for( lpc = 0; lpc < dc->outputs.outputs_len; lpc++ ) {
		fprintf(file, " [%d]", dc->outputs.outputs_val[lpc]);
	}
	fprintf(file, "\n");
	indent--;
	my_i_fprintf(file, indent, "}\n");
}

void meta_print_channel_mask(FILE *file, int indent, data_channel_mask dcm)
{
	my_i_fprintf(file, indent, "mask_flags: ");
	if( dcm.mask_flags & DATA_CHANNEL_MASK_HAS_INPUT )
		fprintf(file, " has_input");
	if( dcm.mask_flags & DATA_CHANNEL_MASK_HAS_ID )
		fprintf(file, " has_id");
	fprintf(file, "\n");
	my_i_fprintf(file, indent, "input:\n");
	if( dcm.input )
		meta_print_file_mask(file, indent + 1, dcm.input);
	else
		my_i_fprintf(file, indent + 1, "(ignored)\n");
	my_i_fprintf(file, indent, "id:               ");
	if( dcm.id[0] )
		fprintf(file, "(ignored)\n");
	else
		fprintf(file, "%s\n", dcm.id);
	my_i_fprintf(file, indent, "set_flags:        ");
	if( dcm.set_flags & DATA_CHANNEL_SQUELCHED )
		fprintf(file, " DATA_CHANNEL_SQUELCHED");
	if( dcm.set_flags & DATA_CHANNEL_DECL )
		fprintf(file, " DATA_CHANNEL_DECL");
	if( dcm.set_flags & DATA_CHANNEL_IMPL )
		fprintf(file, " DATA_CHANNEL_IMPL");
	fprintf(file, "\n");
	my_i_fprintf(file, indent, "unset_flags:      ");
	if( dcm.unset_flags & DATA_CHANNEL_SQUELCHED )
		fprintf(file, " DATA_CHANNEL_SQUELCHED");
	if( dcm.unset_flags & DATA_CHANNEL_DECL )
		fprintf(file, " DATA_CHANNEL_DECL");
	if( dcm.unset_flags & DATA_CHANNEL_IMPL )
		fprintf(file, " DATA_CHANNEL_IMPL");
	fprintf(file, "\n");
}


syntax highlighted by Code2HTML, v. 0.9.1