//! Propagation of binary clauses.
use partial_ref::{partial, PartialRef};

use varisat_formula::Lit;

use crate::context::{parts::*, Context};

use super::{enqueue_assignment, Conflict, Reason};

/// Propagate all literals implied by the given literal via binary clauses.
///
/// On conflict return the binary clause propgating the conflicting assignment.
pub fn propagate_binary(
    mut ctx: partial!(
        Context,
        mut AssignmentP,
        mut ImplGraphP,
        mut TrailP,
        BinaryClausesP,
    ),
    lit: Lit,
) -> Result<(), Conflict> {
    let (binary_clauses, mut ctx) = ctx.split_part(BinaryClausesP);

    for &implied in binary_clauses.implied(lit) {
        let assignment = ctx.part(AssignmentP);

        if assignment.lit_is_false(implied) {
            return Err(Conflict::Binary([implied, !lit]));
        } else if !assignment.lit_is_true(implied) {
            enqueue_assignment(ctx.borrow(), implied, Reason::Binary([!lit]));
        }
    }

    Ok(())
}
