#!/bin/bash

filename="${1:-p2_208.txt}"

declare -A mem

parse_line() {
    local line="$1"
    local key=${line% = *}
    local value=${line#* = }
    declare -g cur_mask
    local base_mask
    local mask

    if [ $key == "mask" ]; then
        cur_mask=$value
    else
        # it's a memory instruction, yay
        loc=${key%]}
        loc=${loc#*[}
        base_mask=$(get_base_mask $cur_mask $loc)
        unset masks
        get_masks $base_mask
        for mask in "${masks[@]}"; do
            loc=$(get_value $mask $loc)
            mem[$loc]=$value
        done
    fi
}

get_base_mask() {
    local mask=$1
    local value=$2
    local newmask=""

    # here we literally translate the string to contain X if
    # it's an X, and then check against the value and if either
    # value or mask has a 1 in that position set it to 1 other
    # wise set it to 0
    for (( a=0; a<36; a++ )); do
        if [ ${mask:$a:1} == "X" ]; then
            newmask+="X"
        elif [ ${mask:$a:1} -eq 1 ] || [ $((value & 2**(35-$a))) -gt 0 ]; then
            newmask+="1"
        else
            newmask+="0"
        fi
    done

    echo $newmask
}

get_masks() {
    local string="$1"
    local test="${string/X/b}"
    local mask1
    local mask2
    declare -g -a masks

    if [ "$string" == "$test" ]; then
        masks+=( $string )
        return 0
    fi

    # do the 2 potential replacements and run them through
    mask1=${string/X/1}
    get_masks $mask1
    mask2=${string/X/0}
    get_masks $mask2
}

get_value() {
    local mask="$1"
    local value="$2"
    local mask_part1=${mask//X/0}
    local mask_part2=${mask//1/X}
    mask_part2=${mask_part2//0/1}
    mask_part2=${mask_part2//X/0}
    value=$((value | 2#$mask_part1))
    value=$(( ~ $value & (2**36)-1 ))
    value=$((value | 2#$mask_part2))
    value=$(( ~ $value & (2**36)-1 ))
    echo $value
}

exec 3<"$filename"
while read -u 3 line; do
    parse_line "$line"
done

total=0
for key in ${!mem[@]}; do
    total=$((total+${mem[$key]}))
done

echo "Total: $total"
