The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package CSS::SpriteMaker::Layout::FixedDimension;

use strict;
use warnings;

use base 'CSS::SpriteMaker::Layout';

=head1 NAME

CSS::SpriteMaker::Layout::FixedDimension

    my $FixedDimensionLayout = CSS::SpriteMaker::Layout::FixedDimension->new(
        # example $rh_item_info input structure
        {
            "1" => {
                width => 128,
                height => 128,
            },
            ...
        },
        # max 10 items on the same row,
        { 
            dimension => 'horizontal',
            n => 10
        },
    );

Layout maximum I<n> items on a row.

Items are chosen at random.

Input $rh_item_info structure must contain the following keys for this layout
to produce a result:

- width : the width in pixels of the image;

- height : the height in pixels of the image;

The following input parameters B<must> be specified:

- n : number of maximum items to place on the same row

The following input parameters are optional:

- dimension: can be 'horizontal' (default) or 'vertical'.

=head1 VERSION

Version 0.01

=cut

our $VERSION = '0.01';

=head2 new

Instantiates the layout:

    my $FixedDimensionLayout = CSS::SpriteMaker::Layout::FixedDimension->new(
        $rh_item_info,
        {   dimension => 'vertical'  # 'horizontal' is the default
            n => 10                  # compulsory!
        }
    );

=cut

sub new {
    my $class = shift;
    my $rh_items_info = shift;
    my $rh_input_params = shift;

    # defaults
    $rh_input_params->{dimension} //= 'horizontal';

    my $self = bless {}, $class;

    if (!$rh_items_info) {
        die 'no items info hashref was passed in construction to this layout';
    }

    $self->_layout_items($rh_items_info, $rh_input_params);
    $self->finalize();

    return $self;
}

=head2 _layout_items

=cut

sub _layout_items {
    my $self          = shift;
    my $rh_items_info = shift;
    my $rh_input_params = shift;

    if (!exists $rh_input_params->{n} || !defined $rh_input_params->{n}) {
        die "the layout parameter 'n' is required for this layout to produce a result.";
    }

    my $n = $rh_input_params->{n};
    my $dimension = $rh_input_params->{dimension};

    # 1. put items from the same directory in the same row
    my $dimension_id = $dimension eq 'horizontal' ? '0' : '1';

    my @xy = (0, 0);

    my @total_wh = (0, 0);
    my $dimension_size = 0;

    my $i = 0;
    for my $id (keys %$rh_items_info) {
        my @wh = ($rh_items_info->{$id}{width}, $rh_items_info->{$id}{height});

        # condition to switch to the next row
        if ($i == $n) {
            # this item must go on the next row
            $xy[1-$dimension_id] += $dimension_size;
            $xy[$dimension_id] = 0;
            $dimension_size = 0;

            # reset condition
            $i = 0;
        }

        # chain on the current row...
        $self->set_item_coord($id, @xy);

        # prepare next element
        $xy[$dimension_id] += $wh[$dimension_id];
        
        # calculate dimension size (height or width based on dimension)
        $dimension_size = $wh[1-$dimension_id]   if $wh[1-$dimension_id] > $dimension_size;

        # update min/max sizes
        if ($xy[$dimension_id] > $total_wh[$dimension_id]) {
            $total_wh[$dimension_id] = $xy[$dimension_id];
        }
        if ($xy[1-$dimension_id] + $dimension_size > $total_wh[1-$dimension_id]) {
            $total_wh[1-$dimension_id] = $xy[1-$dimension_id] + $dimension_size 
        }

        $i++;
    }

    $self->{width} = $total_wh[0];
    $self->{height} = $total_wh[1];

    return;
}

1;