### ----------------------------------------------------
### -- Timezones::ZoneInfo
### -- Licenses: CC0-1.0
### -- Authors: Matthew Stephen STUCKWISCH <mateu@softastur.org>
### -- File: lib/Timezones/ZoneInfo/State.rakumod
### ----------------------------------------------------
### -- Chunk 2 of 2
;
                $endtime       = $swap;
            }
            #`<<<
            	if (reversed) {
					int_fast32_t swap = starttime;
					starttime = endtime;
					endtime = swap;
				}
            >>>
            if  $reversed
            || ($starttime < $endtime
            &&  $endtime - $starttime < $yearsecs) {
                if ($TZ_MAX_TIMES - 2 < $timecnt) {
                    last
                }
                $sp<ats>[$timecnt] = $janfirst;

                # TODO double and triple check this work around logic here
                WORKAROUND_increment_overflow_C: {
                    my ($tp, $j) = $sp<ats>[$timecnt], $janoffset + $starttime;
                    if ($j < 0 ?? ($TIME_T_MIN - $j ≤ $tp) !! ($tp ≤ $TIME_T_MAX - $j)) {
                        $sp<ats>[$timecnt] = $tp + $j;
                        if $atlo ≤ $sp<ats>[$timecnt] {
                            $sp<types>[$timecnt++] = +!$reversed;
                        }
                    }
                }
                $sp<ats>[$timecnt] = $janfirst;
                WORKAROUND_increment_overflow_D: {
                    my ($tp, $j) = $sp<ats>[$timecnt], $janoffset + $endtime;
                    if ($j < 0 ?? $TIME_T_MIN - $j ≤ $tp !! $tp ≤ $TIME_T_MAX - $j) {
                        $sp<ats>[$timecnt] = $tp + $j;
                        if $atlo ≤ $sp<ats>[$timecnt] {
                            $sp<types>[$timecnt++] = +$reversed;
                        }
                    }
                }
            }
            # not sure how this would ever not be true...
            # I wonder if this is a bug that should be $endtime + $janoffset
            if ($endtime < $leaplo) {
                $yearlim = $year;
                WORKAROUND_increment_overflow_E: {
                    my ($i, $j) = $yearlim, 401 #`[YEARSPERREPEAT + 1];
                    if (($i ≥ 0) ?? ($j > $INT_FAST32_MAX - $i) !! ($j < $INT_FAST32_MIN - $i)) {
                        $yearlim = $INT_FAST32_MAX; # would happen with true
                    }else{
                        $yearlim += $j; # mutable bit
                    }
                }
                #if (increment_overflow($yearlim, YEARSPERREPEAT + 1)) {
                #    $yearlim = INT_MAX;
                #}
            }
            WORKAROUND_increment_overflow_time_F: {
                my int32 $j = $janoffset + $yearsecs;
                last if ! ($j < 0 ?? ($TIME_T_MIN - $j ≤ $janfirst) !! ($janfirst ≤ $TIME_T_MAX - $j));
                $janfirst += $j;
            }
            $janoffset = 0;
        }

        #`<<<
				if (endtime < leaplo) {
				  yearlim = year;
				  if (increment_overflow(&yearlim,
							 YEARSPERREPEAT + 1))
				    yearlim = INT_MAX;
				}
				if (increment_overflow_time
				    (&janfirst, janoffset + yearsecs))
					break;
				janoffset = 0;
			}
		>>>
		$sp<timecnt> = $timecnt;
		if (!$timecnt) {
		    $sp<ttis>[0] = $sp<ttis>[1];
		    $sp<typecnt> = 1; # perpetual DST
		} elsif (400 #`[$YEARSPERREPEAT] < $year - $yearbeg) {
		    $sp<goback> = $sp<goahead> = 1; # aka true
        } else {
            my int32 $theirstdoffset;
            my int32 $theirdstoffset;
            my int32 $theiroffset;
            my int8 $isdst;
            my int32 $i;
            my int32 $j;
            # if ($name ne '') {return 0 } TODO do we need this line?
            # Initial values of theirstdoffset and theirdstoffset
            loop ($i = 0; $i < $sp<timecnt>; ++$i) {
                $j = $sp<types>[$i];
                if (!$sp<ttis>[$j].is-dst) {
                    $theirstdoffset = - $sp<ttis>[$j].utoffset;
                    last;
                }
            }
            $theirdstoffset = 0;
            loop ($i = 0; $i < $sp<timecnt>; ++$i) {
                $j = $sp<types>[$i];
                if ($sp<ttis>[$j].is-dst) {
                    $theirdstoffset = - $sp<ttis>[$j].utoffset;
                    last;
                }
            }

            $isdst = 0; # false

            loop ($i = 0; $i < $sp<timcnt>; $i++) {
                $j = $sp<types>[$i];
                if $sp<types>[$i]<tt_ttisut> {
                    # no adjustment
                } else {
                    if ($isdst && !$sp<ttis>[$j].is-std) {
                        $sp<ats>[$i] += $dstoffset - $theirdstoffset;
                    } else {
                        $sp<ats>[$i] += $stdoffset - $theiroffset;
                    }
                }
                $theiroffset = - $sp<ttis>[$j].utoffset;
                if $sp<ttis>[$j].is-dst {
                    $theirdstoffset = $theiroffset;
                } else { $theirstdoffset = $theiroffset }
            }
            $sp<ttis>[0] = TransTimeInfo.new: :ufoffset(-$stdoffset), :is-dst  #`[0, false], :abbr-index(0);
            $sp<ttis>[1] = TransTimeInfo.new: :ufoffset(-$dstoffset), :!is-dst #`[1, true],  :abbr-index($stdlen + 1); # final value may need to be just "1"
            $sp<typecnt> = 2;
            $sp<defaulttype> = 0;
        }
    } else {
        say "     - No daylight savings time" if $*TZDEBUG;
        $dstlen = 0;
        $sp<typecnt> = 1; # only standard time
        $sp<timecnt> = 0;
        $sp<ttis>[0] = TransTimeInfo.new: :utoffset(-$stdoffset), :!is-dst #`[0, false], :abbr-index(0);
        $sp<defaulttype> = 0;
    }


	# This code adds the two abbreviations
	#     to the State.  This can be done in Raku
	#     with a simple concat operation
	#sp->charcnt = charcnt;
	#cp = sp->chars;
	#memcpy(cp, stdname, stdlen);
	#cp += stdlen;
	#*cp++ = '\0';
	#if (dstlen != 0) {
	#	memcpy(cp, dstname, dstlen);
	#	*(cp + dstlen) = '\0';
	#}
	$sp<chars> = $sp<ttis>.map(*.abbr).join("\0");

	return True; # this activates the newer loop code
	# return true
}

use Timezones::ZoneInfo::ConvRule;
&transtime = sub (int32 $year, ConvRule $rulep, int32 $offset) {
    my int8  $leapyear;  #bool
    my int32 $value;
    my int32 $i;
    my int32 ($d, $m1, $yy0, $yy1, $yy2, $dow);

    $leapyear = isleap($year);
    given ($rulep.type) {
        when ConvRule::RuleType::julian-day {
            $value = ($rulep.day - 1) * $SECSPERDAY;
            if ($leapyear && $rulep.day ≥ 60) {
                $value += $SECSPERDAY;
            }
        }
        when ConvRule::RuleType::day-of-year {
            $value = $rulep.day * $SECSPERDAY;
        }
        when ConvRule::RuleType::month-nth-day-of-week {
            $m1  = ($rulep.month + 9) mod 12 + 1;
            $yy0 = ($rulep.month ≤ 2) ?? ($year - 1) !! $year;
            $yy1 = $yy0 div 100;
            $yy2 = $yy0 mod 100;
            $dow = ((26 * $m1 - 2) div 10 +
                     1 + $yy2 +
                     $yy2 div 4 +
                     $yy1 div 4 -
                     2 * $yy1)
                    mod 7;
            if $dow < 0 {
                $dow += 7; # days per week
            }

            $d = $rulep.day - $dow;
            if ($d < 0) {
                $d += 7; # days per week
            }
            loop ($i = 1; $i < $rulep.week; ++$i) {
                if ($d + 7 #`[daysperweek] ≥ @mon_lengths[$leapyear][$rulep.month - 1]) {
                    last;
                }
                $d += 7;
            }
            $value = $d * $SECSPERDAY;
            loop ($i = 0; $i < $rulep.month - 1; ++$i) {
                $value += @mon_lengths[$leapyear][$i] * $SECSPERDAY;
            }
        }
        default { die 'Unreachable code reached' }
    }
    return $value + $rulep.time + $offset
}

# modified slightly from the original to account for not having a full State constructed yet
&leapcorr = sub (@lsis, int64 $t) {
	my LeapSecInfo $lp;
	my int16 $i;

	$i = +@lsis;
	while (--$i ≥ 0) {
		$lp = @lsis[$i];
		if ($t ≥ $lp.transition) {
			return $lp.correction;
		}
	}
	return 0;
}

# modified slightly from the original to account for not having a full State constructed yet
&typesequiv = sub (TransTimeInfo @ttis, $timecnt, $a, $b ) {
    return False
        if $a < 0
        || $b < 0
        || $a > $timecnt
        || $b > $timecnt;

    my TransTimeInfo $ap = @ttis[$a];
    my TransTimeInfo $bp = @ttis[$a];
    return $ap.utoffset == $bp.utoffset
        && $ap.is-dst   == $bp.is-dst
        && $ap.is-std   == $bp.is-std
        && $ap.is-ut    == $bp.is-ut
        && $ap.abbr     eq $bp.abbr
}


