/* lp_smpr.c
 * Neil Moore <neil@cs.uky.edu>
 * 17 Jul 1999
 *
 * Part of liblp.  See COPYRIGHT for copyright information.
 */
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <lp.h>
#include <lp_util.h>
#include <lp_lists.h>
#include <lp_smpr.h>

static void lp_sm_print_stratum(FILE *of, FILE *sf, struct lp *prog, struct lp_rlist *stratum);
static void lp_sm_print_header(FILE *f, struct lp *prog);
static void lp_sm_print_rule(FILE *f, struct lp *prog, struct lp_rule *rule);
static void lp_sm_print_atoms(FILE *f, struct lp *prog);
static void lp_sm_print_compute(FILE *f, struct lp *prog);


/* Print a (stratified) program in smodels 1 format to the stream ofile;
 * print the stratification to the stream sfile.  The smodels 1 format
 * is the input format of smodels 1.x, and the output format of lparse -1.
 * The statification file produced is in DeReS format.
 *
 * This function returns 0 for success, nonzero for failure.
 *
 */
int lp_sm_print_program_str(FILE *ofile, FILE *sfile, struct lp *prog,
			    struct lp_rlist **strata, int nstrata)
{
	int i;

	lp_assert(prog != NULL);
	lp_assert(outfilename != NULL);
	lp_assert(strfilename != NULL);	
	
	
	lp_sm_print_header(ofile, prog);
	for(i=0; i<nstrata; i++) {
		lp_assert(strata[i] != NULL);
		lp_sm_print_stratum(ofile, sfile, prog, strata[i]);
	}
	
	lp_sm_print_atoms(ofile, prog);
	lp_sm_print_compute(ofile, prog);

	return 0;
}


/* Print a program in smodels 1 format to the stream ofile.  This format is
 * the input format of smodels 1.x, and the output format of lparse -1.
 *
 * This function returns 0 for success, nonzero for failure.
 *
 */
int lp_sm_print_program(FILE *ofile, struct lp *prog)
{
	int i;

	lp_assert(prog != NULL);
	lp_assert(outfilename != NULL);
	
	lp_sm_print_header(ofile, prog);
	
	for(i=0; i<prog->nrules; i++)
		lp_sm_print_rule(ofile, prog, &prog->rules[i]);
	
	lp_sm_print_atoms(ofile, prog);
	lp_sm_print_compute(ofile, prog);
	
	return 0;
}


/* Print a stratum.  Stratification information is printed to sf, and the
 * rules in the stratum are printed to of.
 *
 */
void lp_sm_print_stratum(FILE *of, FILE *sf, struct lp *prog, struct lp_rlist *stratum) 
{
	int nrules=0;
	struct lp_rlist *j;

	lp_assert(prog != NULL);
	lp_assert(stratum != NULL);

	for(j=stratum; j!=NULL; j=j->next) {
		lp_sm_print_rule(of, prog, j->rule);
		nrules++;
	}

	fprintf(sf, "%d\n", nrules);
}


/* Print a smodels 1 header.  The header indicates the number of atoms, the
 * number of rules, and the program size.
 *
 */
void lp_sm_print_header(FILE *f, struct lp *prog) 
{
	lp_assert(prog != NULL);
	
	fprintf(f, "%d\n", prog->natoms);
	fprintf(f, "%d\n", prog->nrules);
	fprintf(f, "%d\n", prog->size);
	
}


/* Print the list of atoms in prog.
 *
 */
void lp_sm_print_atoms(FILE *f, struct lp *prog) 
{
	int i;

	lp_assert(prog != NULL);
	
	for(i=0; i<prog->natoms; i++)
		fprintf(f, "%s\n", prog->atoms[i].name);
}


/* Print the compute statement.
 *
 */
void lp_sm_print_compute(FILE *f, struct lp *prog) 
{
	int i;

	lp_assert(prog != NULL);
	
	fprintf(f, "B+\n%d\n", prog->nposreq);
	for(i=0; i<prog->nposreq; i++) {
		fprintf(f, "%d\n", lp_apos(prog, prog->posreq[i]) + 1);
	}
	fprintf(f, "B-\n%d\n", prog->nnegreq);
	for(i=0; i<prog->nnegreq; i++) {
		fprintf(f, "%d\n", lp_apos(prog, prog->negreq[i]) + 1);
	}

	fprintf(f, "%d\n", prog->nmodels);
}


/* Print a rule in smodels 1 format.
 *
 */
void lp_sm_print_rule(FILE *f, struct lp *prog, struct lp_rule *rule) 
{
	int i;

	lp_assert(prog != NULL);
	lp_assert(rule != NULL);
	lp_assert(rule >= prog->rules && rule < &prog->rules[prog->nrules]);
	lp_assert(rule->head != NULL);
	lp_assert(rule->head >= prog->atoms && rule->head < &prog->atoms[prog->natoms]);

	fprintf(f, "%d ", lp_apos(prog, rule->head) + 1);
	fprintf(f, "%d ", rule->nneg);
	for(i=0; i<rule->nneg; i++)
		fprintf(f, "%d ", lp_apos(prog, rule->neg[i]) + 1);

	fprintf(f, "%d ", rule->npos);
	for(i=0; i<rule->npos; i++)
		fprintf(f, "%d ", lp_apos(prog, rule->pos[i]) + 1);
	
	fprintf(f, "\n");
}
