The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package SDL::Tutorial::Tetris::Model::Grid;

use strict;
use warnings;

use base 'SDL::Tutorial::Tetris::Base';

use Carp;
use Data::Dumper;

use SDL::Tutorial::Tetris::Model::Pieces;

sub new {
    my ($class, %params) = (@_);

    my $self  = $class->SUPER::new(%params);

    $self->evt_manager->reg_listener($self);
    $self->init(%params);

    return $self;
}

sub init {
    my ($self,%param) = @_;

    #TODO: Get the following from @_ (DONE!)

    $self->{board_line_width} ||= 6;
    $self->{block_size}       ||= 20;
    $self->{board_position}   ||= 300;
    $self->{screen_height}    ||= 480;

    $self->{width}  ||= 10;
    $self->{height} ||= 23;

    # used to test delete_line
    # my $arr_ref = [];
    # for my $x (0..18)
    # {
    #		$arr_ref->[$x][19] = 1;
    #  }

    $self->{grid} ||= [];
}

sub store_piece {
    my $self = shift;
    confess 'Expecting 4 parameters' if ($#_ != 3);
    my ($x, $y, $piece, $rotation) = @_;

    for (my $i1 = $x, my $i2 = 0; $i1 < $x + 5; $i1++, $i2++) {
        for (my $j1 = $y, my $j2 = 0; $j1 < $y + 5; $j1++, $j2++) {
            if (!($i1 < 0 || $j1 < 0)) {
                $self->{grid}->[$i1][$j1] = 1
                  if (
                    SDL::Tutorial::Tetris::Model::Pieces->block_color($piece, $rotation, $j2, $i2) != 0);
            }
        }
    }
}

sub is_game_over {
    my $self = shift;
    for (my $i = 0; $i < $self->{width}; $i++) {
        if (defined $self->{grid}->[$i][0]) {
            return 1 if ($self->{grid}->[$i][0] == 1);
        }
    }
    return 0;
}

#removes a line and moves everything one row down
sub delete_line {
    my $self  = shift;
    my $dline = shift;
    for (my $j = $dline; $j > 0; $j--) {

        for (my $i = 0; $i < $self->{width}; $i++) {
            $self->{grid}->[$i][$j] = $self->{grid}->[$i][$j - 1];
        }
    }
    return 1;
}

sub delete_possible_lines {

    my $self          = shift;
    my $deleted_lines = 0;
    for (my $j = 0; $j < $self->{height}; $j++) {


        my $i = 0;
        while ($i < $self->{width}) {
            last if !(defined($self->{grid}->[$i][$j]));
            $i++;
        }
        $deleted_lines += $self->delete_line($j) if $i == $self->{width};
    }
    return $deleted_lines;
}

sub is_free_loc {
    my $self = shift;
    confess 'Expecting 2 parameters' if $#_ != 1;

    #die 'got '.$_[0].' '.$_[1];
    my $grid = $self->{grid};

    #die Dumper $grid;
    return 1 if !defined($grid->[$_[0]][$_[1]]);
    return 0 if ($grid->[$_[0]][$_[1]] == 1);

}

sub get_x_pos_in_pixels {
    my $self = shift;
    confess 'Expecting 1 parameter got ' . $_[0] if (!defined($_[0]));
    return (
        (   $self->{board_position}
              - ($self->{block_size} * ($self->{width} / 2))
        ) + ($_[0] * $self->{block_size}) + 3
    );
}

sub get_y_pos_in_pixels {
    my $self = shift;
    confess 'Expecting 1 parameter got ' . $_[0] if (!defined($_[0]));
    return (($self->{screen_height} - ($self->{block_size} * $self->{height}))
        + ($_[0] * $self->{block_size}));

}

sub is_possible_movement {
    my $self = shift;
    confess 'Expecting 4 parameters' if $#_ != 3;
    my ($x, $y, $piece, $rotation) = @_;

    for (my $i1 = $x, my $i2 = 0; $i1 < $x + 5; $i1++, $i2++) {
        for (my $j1 = $y, my $j2 = 0; $j1 < $y + 5; $j1++, $j2++) {

            #check if block goes outside limits
            if (   $i1 < 0
                || $i1 > ($self->{width} - 1)
                || $j1 > ($self->{height} - 1))
            {
                return 0
                  if (
                    SDL::Tutorial::Tetris::Model::Pieces->block_color($piece, $rotation, $j2, $i2) != 0);
            }

            #check collision with blocks already on board
            if ($j1 >= 0) {
                return 0
                  if (
                    (SDL::Tutorial::Tetris::Model::Pieces->block_color($piece, $rotation, $j2, $i2) != 0)
                    && !($self->is_free_loc($i1, $j1)));
            }
        }
    }

    #no collision
    return 1;
}

sub notify {
    my ($self, $event) = (@_);

    print "Notify in Grid \n" if $self->{EDEBUG};

    if (defined $event && $event->{name} eq 'Tick') {
        #do checks
    }
}

1;