#!/bin/bash

set -u

declare -a points=()
declare -a folds=()

filename="${1:-example.txt}"
exec 3<"$filename"

max_x=0
max_y=0

while read -u 3 line; do
    if [ "$line" == "" ]; then
        break
    fi
    x=${line%,*}
    y=${line#*,}
    if [ $x -gt $max_x ]; then
        max_x=$x
    fi
    if [ $y -gt $max_y ]; then
        max_y=$y
    fi
    points+=($line)
done

((max_x+=1))
((max_y+=1))

while read -u 3 line; do
    folds+=(${line#fold along })
done

display_map() {
    for (( y=0; y<$max_y; y++ )); do
        for (( x=0; x<$max_x; x++ )); do
            case "${map[$x,$y]}" in
                0)
                    echo -n "."
                    ;;
                1)
                    echo -n "#"
                    ;;
            esac
        done
        echo
    done
}

declare -A map

# now build a map
for (( y=0; y<$max_y; y++ )); do
    for (( x=0; x<$max_x; x++ )); do
        map["$x,$y"]=0
    done
done

for point in "${points[@]}"; do
    x=${point%,*}
    y=${point#*,}
    map["$x,$y"]=1
done

fold() {
    local line="$1"
    local axis=${line%=*}
    local point=${line#*=}

    declare -A new_map=()

    case $axis in
        x)
            local new_max_x=$(($max_x - $point - 1))
            if [ $point -gt $new_max_x ]; then
                new_max_x=$point
            fi
            for (( y=0; y<$max_y; y++ )); do
                for (( x=0; x<$new_max_x; x++ )); do
                    # be sensible instead of insane, work from the middle out
                    x_1=$(($point-$x-1)) # always one left of the point
                    x_2=$(($point+$x+1)) # always one right of the point
                    if [ $x_1 -lt 0 ]; then
                        x_1=$x_2
                    fi
                    if [ $x_2 -ge $max_x  ]; then
                        x_2=$x_1
                    fi
                    new_x=$(($new_max_x-$x-1)) # work from the right of the new image, left
                    new_map["$new_x,$y"]=$((${map["$x_1,$y"]} | ${map["$x_2,$y"]}))
                done
            done
            max_x=$new_max_x
            ;;
        y)
            local new_max_y=$(($max_y - $point - 1))
            if [ $point -gt $new_max_y ]; then
                new_max_y=$point
            fi
            for (( y=0; y<$new_max_y; y++ )); do
                y_1=$(($point-$y-1)) # always above the fold
                y_2=$(($point+$y+1)) # always below the fold
                if [ $y_1 -lt 0 ]; then
                    y_1=$y_2
                fi
                if [ $y_2 -ge $max_y  ]; then
                    y_2=$y_1
                fi
                new_y=$(($new_max_y-$y-1)) # work from the bottom of the new image, up
                for (( x=0; x<$max_x; x++ )); do
                    new_map["$x,$new_y"]=$((${map["$x,$y_1"]} | ${map["$x,$y_2"]}))
                done
            done
            max_y=$new_max_y
            ;;
    esac

    for k in "${!new_map[@]}"; do
        map[$k]=${new_map[$k]}
    done
}

get_points_count() {
    local count=0
    for (( y=0; y<$max_y; y++ )); do
        for (( x=0; x<$max_x; x++ )); do
            ((count+=${map[$x,$y]}))
        done
    done

    echo $count
}

# do first fold
echo "Doing first fold"
fold "${folds[0]}"
echo "There are $(get_points_count) dots visible after first fold"
for (( f=1; f<${#folds[@]}; f++ )); do
    echo "Doing fold $((f+1)) of ${#folds[@]}"
    fold "${folds[$f]}"
done
echo
echo "After all folds:"
display_map
