package Urb::Misc::Stairs;

use strict;
use warnings;
use 5.010;

use Exporter;
use vars qw /@EXPORT_OK/;

use base qw /Exporter/;

@EXPORT_OK = qw /three_turn two_turn one_turn zero_turn risers_number ideal_going/;

=head1 NAME

Urb::Misc::Stairs - Stair geometry

=head1 SYNOPSIS

  $risers = 17;
  $going_a = 4; # number of riser spaces in base dimension after two widths.
  $going_b = two_turn ($risers, $going_a);

Result is 3

i.e. given seventeen risers, if the base dimension is equal to 2 x width + 4 x going,
the other dimension has to be equal to at least 2 x width + 2 x going.

So, with seventeen risers and two 90deg turns with 30deg winders, given a going
of 240mm and a width of 1200mm, if the base dimension is 3360mm, then the
other dimension has to be at least 3120mm (1200 * 2 + 240 * 3).

=head1 DESCRIPTION

Presuming that all spaces for stairs are at least twice the width required in
both dimensions, the excess length in the base dimension is the number of extra
goings that can be fitted in that dimension.

This is enough information to determine the extra length (in goings) required
in the other dimension, given a number of risers and one of four stair layouts.

Each of these layouts is stackable.

=over

=item three_turn

A three 90deg turn (effectively spiral) stair has one corner where you can
enter and exit at each level.

=cut

sub three_turn
{
    my ($risers, $going_a) = @_;

    my $going_b = int (($risers +1)/2) - 5 - int ($going_a);
    return 0 if $going_b < 0;
    return $going_b;
}

=item two_turn

A two 90deg turn (U-shaped) stair has two corners where you can enter and exit
at each level.

=cut

sub two_turn
{
    my ($risers, $going_a) = @_;
    my $going_b;

    if ($risers %2 == 1)
    {
        $going_b = int ($risers/2) - 3 - int ($going_a/2);
    }
    else
    {
        $going_b = int ($risers/2) - 3 - int (($going_a +1)/2);
    }

    return 0 if $going_b < 0;
    return $going_b;
}

=item one_turn

A one 90deg turn (dog-legged) stair has three corners where you can enter and
exit at each level.

=cut

sub one_turn
{
    my ($risers, $going_a) = @_;

    my $going_b = $risers - 4 - int ($going_a);

    return 0 if $going_b < 0;
    return $going_b;
}

=item zero_turn

A straight flight stair has four corners where you can enter and exit at each
level.

=cut

sub zero_turn
{
    my ($risers, $going_a) = @_;
    my $going_b = 0;

    if ($going_a + 2 > $risers)
    {
        $going_b = 0;
    }
    else
    {
        $going_b = $risers - 1;
    }

    return $going_b;
}

=item risers_number

Given a FTF height and a maximum riser height, return number of risers in a stair

  $total = risers_number (3.0, 0.21);

=cut

sub risers_number
{
    my ($height_ftf, $max_riser) = @_;
    my $num = $height_ftf/$max_riser;
    return $num if int $num == $num;
    return 1 + int $num;
}

=item ideal_going

Given a riser height, return an 'ideal' going distance based on the rule:
minimum going = 220mm, 2xriser + going = 625mm Round up to nearest 5mm:

  $going = ideal_going ($riser);

=cut

sub ideal_going
{
    my $riser = shift;
    my $going = 0.625 - (2*$riser);
    return 0.22 if $going < 0.22;
    return $going if (int ($going*200) == $going*200);
    return 0.005 + (int ($going*200)/200);
}

=back

=cut

1;
