#include "circuit.h"

#include "assert.h"


int Gate::cal_propagate_len(bool x) {

    int fpl[2];
    fpl[0] = fpl[1] = 0;

    for(Gate* out : outputs) {
        if(!out->is_detected(this)) continue;

        fpl[!value] = std::max(fpl[!value], out->fault_propagate_len[!out->value] + 1);
    }

    return fpl[x];
}

bool Gate::is_detected(Gate* one_of_input) {
    one_of_input->value = !one_of_input->value;
    bool detect = cal_value() != value;
    one_of_input->value = !one_of_input->value;
    return (cal_value() == value) && detect;
}

bool Gate::is_propagated() {
    return sa[0] || sa[1];
}

bool Gate::cal_sa(bool x) {
    if(isPO) {
        if(x == 0) return value;
        else return !value;
    }

    bool sa0 = 0;
    bool sa1 = 0;

    for(Gate* out : outputs) {
        if(!out->is_propagated()) continue;

        if(out->cal_value() != out->value) continue;

        this->value = !this->value;
        bool detect = out->cal_value() != out->value;
        this->value = !this->value;
        if(!detect) continue;

        sa0 |= this->value;
        sa1 |= !this->value;
    }
    if(x == 0) return sa0;
    else return sa1;
}

int Gate::cal_value() {
    int res;

    switch(type) {
        case NOT:
            res = !inputs[0]->value;
            break;
        case BUF:
            res = inputs[0]->value;
            break;
        case AND:
            res = inputs[0]->value;
            for(int i=1; i<inputs.size(); i++) {
                res &= inputs[i]->value;
            }
            break;
        case NAND:
            res = inputs[0]->value;
            for(int i=1; i<inputs.size(); i++) {
                res &= inputs[i]->value;
            }
            res = !res;
            break;
        case OR:
            res = inputs[0]->value;
            for(int i=1; i<inputs.size(); i++) {
                res |= inputs[i]->value;
            }
            break;
        case NOR:
            res = inputs[0]->value;
            for(int i=1; i<inputs.size(); i++) {
                res |= inputs[i]->value;
            }
            res = !res;
            break;
        case XOR:
            res = inputs[0]->value;
            for(int i=1; i<inputs.size(); i++) {
                res ^= inputs[i]->value;
            }
            break;
        case XNOR:
            res = inputs[0]->value;
            for(int i=1; i<inputs.size(); i++) {
                res ^= inputs[i]->value;
            }
            res = !res;
            break;
        case INPUT:
            res = value;
            break;
        default:
            assert(false);
            break;
    }
    return res;
}