// Fórmulas lógicas como árboles: el ejemplo de la clase.
//
// Ownership: cada nodo es owner de sus hijos. Quien recibe un árbol lo libera con logic_free.
// Un constructor que recibe hijos se queda con ellos, también cuando falla.
#ifndef LOGIC_H
#define LOGIC_H

#include <stdio.h>

typedef enum { LOGIC_CONSTANT, LOGIC_INPUT, LOGIC_NOT, LOGIC_AND, LOGIC_OR } LogicKind;

typedef struct logic Logic;

struct logic {
    LogicKind kind;
    union {
        int constant;                                // LOGIC_CONSTANT: 0 o 1
        char input;                                  // LOGIC_INPUT: una letra de 'a' a 'z'
        Logic *child;                                // LOGIC_NOT
        struct { Logic *left; Logic *right; } pair;  // LOGIC_AND y LOGIC_OR
    } as;
};

// Devuelven NULL si no hay memoria. Si un hijo es NULL, liberan al otro y devuelven NULL.
Logic *logic_constant(int value);
Logic *logic_input(char letter);
Logic *logic_not(Logic *child);
Logic *logic_and(Logic *left, Logic *right);
Logic *logic_or(Logic *left, Logic *right);

// Libera el árbol completo. Acepta NULL.
void logic_free(Logic *e);

// Consultas: no cambian el árbol.
int logic_count(const Logic *e);
int logic_depth(const Logic *e);
void logic_print(const Logic *e, FILE *out);

// inputs tiene 26 valores, uno por letra: inputs[0] es 'a'.
int logic_eval(const Logic *e, const int *inputs);

// Se queda con e y devuelve el árbol simplificado. Lo que ya no se usa, lo libera.
Logic *logic_simplify(Logic *e);

#endif
