package recursion

import (
	"logik/aussagenlogik/formulae"
)

/* ---------------------------------------------------------------- *
 * METHOD: compute NNF
 * ---------------------------------------------------------------- */

// NOTE: diese bedarf einer Art Doppeltrekursion
func NNF(tree formulae.Formula) formulae.Formula {
	// Definiere Schema:
	var schema = func(tree formulae.Formula, prevValues []formulae.FormulaPair) formulae.FormulaPair {
		// separate out positive and negative parts:
		var pairs = formulae.NewFormulaPairs(prevValues)
		var prevPos = pairs.Pos()
		var prevNeg = pairs.Neg()
		// compute value from previous positive/negative parts:
		if tree.IsPositiveLiteral() {
			return formulae.FormulaPair{
				Pos: tree.Deepcopy(),
				Neg: formulae.Negation(tree),
			}
		} else if tree.IsNegativeLiteral() {
			return formulae.FormulaPair{
				Pos: tree.Deepcopy(),
				Neg: prevPos[0],
			}
		} else if tree.IsTautologySymbol() {
			return formulae.FormulaPair{
				Pos: formulae.Tautology,
				Neg: formulae.Contradiction,
			}
		} else if tree.IsContradictionSymbol() {
			return formulae.FormulaPair{
				Pos: formulae.Contradiction,
				Neg: formulae.Tautology,
			}
		} else if tree.IsNegation() {
			return formulae.FormulaPair{
				Pos: prevNeg[0],
				Neg: prevPos[0],
			}
		} else if tree.IsConjunction2() {
			return formulae.FormulaPair{
				Pos: formulae.Conjunction2(prevPos[0], prevPos[1]),
				Neg: formulae.Disjunction2(prevNeg[0], prevNeg[1]),
			}
		} else if tree.IsConjunction() {
			return formulae.FormulaPair{
				Pos: formulae.Conjunction(prevPos),
				Neg: formulae.Disjunction(prevNeg),
			}
		} else if tree.IsDisjunction2() {
			return formulae.FormulaPair{
				Pos: formulae.Disjunction2(prevPos[0], prevPos[1]),
				Neg: formulae.Conjunction2(prevNeg[0], prevNeg[1]),
			}
		} else if tree.IsDisjunction() {
			return formulae.FormulaPair{
				Pos: formulae.Disjunction(prevPos),
				Neg: formulae.Conjunction(prevNeg),
			}
		} else if tree.IsImplication() {
			return formulae.FormulaPair{
				Pos: formulae.Implies(prevPos[0], prevPos[1]),
				Neg: formulae.Conjunction2(prevPos[0], prevNeg[1]),
			}
		} else {
			panic("Could not evaluate expression!")
		}
	}
	// Erzeuge Funktion aus Schema und berechne Wert:
	fn := formulae.CreateFromSchemeFmlPairValued(schema)
	return fn(tree).Pos
}
