// Experiment 20: Compute the CHECKSUM for a given binary data frame
//                and verify correctness at the receiver end.
// (Also serves as the "parity bit checking" exercise from the index.)
// Compile: gcc 20_checksum_parity.c -o checksum
// Run    : ./checksum

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* ---------- 1's-complement checksum on m blocks of n bits each ---------- */

// Add two n-bit binary strings (assumed equal length) with end-around carry
void addBinary(char *a, char *b, char *out, int n) {
    int carry = 0;
    for (int i = n - 1; i >= 0; i--) {
        int sum = (a[i]-'0') + (b[i]-'0') + carry;
        out[i] = (sum % 2) + '0';
        carry  =  sum / 2;
    }
    // End-around carry
    for (int i = n - 1; carry && i >= 0; i--) {
        int sum = (out[i]-'0') + carry;
        out[i] = (sum % 2) + '0';
        carry  =  sum / 2;
    }
    out[n] = '\0';
}

// 1's complement of an n-bit binary string
void onesComplement(char *s, char *out, int n) {
    for (int i = 0; i < n; i++)
        out[i] = (s[i] == '0') ? '1' : '0';
    out[n] = '\0';
}

/* ---------- main ---------- */

int main() {
    int m, n;
    printf("Enter number of data blocks  (m): ");
    if (scanf("%d", &m) != 1 || m < 1) return 1;
    printf("Enter bits per block        (n): ");
    if (scanf("%d", &n) != 1 || n < 1) return 1;

    char blocks[20][33];
    for (int i = 0; i < m; i++) {
        printf("Block %d (%d bits): ", i+1, n);
        scanf("%32s", blocks[i]);
        if ((int)strlen(blocks[i]) != n) {
            printf("Bad length, expected %d bits.\n", n);
            return 2;
        }
    }

    /* ---- SENDER: compute checksum ---- */
    char sum[33], next[33];
    strcpy(sum, blocks[0]);
    for (int i = 1; i < m; i++) {
        addBinary(sum, blocks[i], next, n);
        strcpy(sum, next);
    }
    char checksum[33];
    onesComplement(sum, checksum, n);

    printf("\n--- SENDER ---\n");
    printf("Sum of data blocks : %s\n", sum);
    printf("Checksum (1's comp): %s\n", checksum);
    printf("Sent to receiver   : data + checksum\n");

    /* ---- RECEIVER: add everything (incl. checksum), check for all-1s ---- */
    char rsum[33];
    strcpy(rsum, blocks[0]);
    for (int i = 1; i < m; i++) {
        addBinary(rsum, blocks[i], next, n);
        strcpy(rsum, next);
    }
    addBinary(rsum, checksum, next, n);
    strcpy(rsum, next);

    char verify[33];
    onesComplement(rsum, verify, n);

    printf("\n--- RECEIVER ---\n");
    printf("Receiver sum            : %s\n", rsum);
    printf("Complement of sum       : %s\n", verify);

    // If complement is all zeros -> data accepted
    int accept = 1;
    for (int i = 0; i < n; i++)
        if (verify[i] != '0') { accept = 0; break; }

    printf("\nResult: %s\n",
           accept ? "Data ACCEPTED (no error detected)"
                  : "Data REJECTED (error detected)");
    return 0;
}
