#include "espresso.h"

/** MM: check_equiv je opatchovana len kvoli memory-leakom, nic viac */
/** MM: int kvoli kontrole chyby; -1 pri chybe */
/** MM: pridany fp */
int find_equiv_outputs(pPLA PLA, FILE *fp)
{
    int i, j, ipart, jpart, some_equiv, ret;
    pcover *R, *F;
    
    if ( (PLA==NULL) || (fp==NULL) ) return -1; /** MM: ak chyba parametrov */

    some_equiv = FALSE3;

    makeup_labels(PLA);

    F = ALLOC(pcover, cube->part_size[cube->output]);
    R = ALLOC(pcover, cube->part_size[cube->output]);
    if ( (F==NULL) || (R==NULL) ) { /** MM: ak chyba alokacie */
        FREE(F); FREE(R); return -1;
    }
    /** MM: pridane NULLovanie poloziek -> vyuzite pri dealokacii pri chybe */
    for (int i = 0; i < cube->part_size[cube->output]; i++){
        F[i] = R[i] = NULL;
    }

    for(i = 0; i < cube->part_size[cube->output]; i++) {
    	ipart = cube->first_part[cube->output] + i;
    	R[i] = cof_output(PLA->R, ipart);
    	F[i] = complement(cube1list(R[i]));
    	if ( (R[i]==NULL) || (F[i]==NULL) ) { /** MM: ak chyba alokacie */
            ret = -1; /** nastavenie navratovej hodnoty na chybu */
            goto cleanup; 
        }
    }
	
    for(i = 0; i < cube->part_size[cube->output]-1; i++) {
    	for(j = i+1; j < cube->part_size[cube->output]; j++) {
    	    ipart = cube->first_part[cube->output] + i;
    	    jpart = cube->first_part[cube->output] + j;
    
    	    if (check_equiv(F[i], F[j])) {
        		fprintf(fp, "# Outputs %d and %d (%s and %s) are equivalent\n",
        		    i, j, PLA->label[ipart], PLA->label[jpart]);
        		some_equiv = TRUE3;
    	    } else if (check_equiv(F[i], R[j])) {
        		fprintf(fp, "# Outputs %d and NOT %d (%s and %s) are equivalent\n",
        		    i, j, PLA->label[ipart], PLA->label[jpart]);
        		some_equiv = TRUE3;
    	    } else if (check_equiv(R[i], F[j])) {
        		fprintf(fp, "# Outputs NOT %d and %d (%s and %s) are equivalent\n",
        		    i, j, PLA->label[ipart], PLA->label[jpart]);
        		some_equiv = TRUE3;
    	    } else if (check_equiv(R[i], R[j])) {
        	    fprintf(fp, "# Outputs NOT %d and NOT %d (%s and %s) are equivalent\n",
        		    i, j, PLA->label[ipart], PLA->label[jpart]);
        		some_equiv = TRUE3;
    	    }
    	}
    }

    if (! some_equiv) {
    	fprintf(fp, "# No outputs are equivalent\n");
    }
    ret = 0; /** nastavenie navratovej hodnoty na OK */
    
/** MM: novo pridane navestie, ktore spaja epilog funkcie pre dobry aj zly pripad */
cleanup:
    for(i = 0; i < cube->part_size[cube->output]; i++) {
    	free_cover(F[i]);
    	free_cover(R[i]);
    }
    FREE(F);
    FREE(R);
    return ret;
}

/** MM: boli len pridane funkcie na dealokaciu vnutornych premennych */
int check_equiv(pset_family f1, pset_family f2)
{
    register pcube *f1list, *f2list;
    register pcube p, last;

    f1list = cube1list(f1);
    foreach_set(f2, last, p) {
    	if (! cube_is_covered(f1list, p)) {
            free_cubelist(f1list); /** MM: pridane kvoli memory leakom */
    	    return FALSE3;
    	}
    }
    free_cubelist(f1list);

    f2list = cube1list(f2);
    foreach_set(f1, last, p) {
    	if (! cube_is_covered(f2list, p)) {
            free_cubelist(f2list); /** MM: pridane kvoli memory leakom */
    	    return FALSE3;
    	}
    }
    free_cubelist(f2list);

    return TRUE3;
}
