##############
# Area::Cave #
##############

package Roguelike::Area::Cave;

use strict;
use warnings;
use Roguelike::Game;
use Roguelike::Utility;

use Roguelike::Tilemap;
use Roguelike::Area;
use Roguelike::Area::Structure::Room;

sub generate {
  shift;  # We aren't really a class, no are we?
  my ($height, $width, $depth) = @_;
  my $map = new Roguelike::Tilemap $height, $width, ".";
  # Since we're an area, not a structure, we get a list of data.
  $map->{Exits} = [];
  $map->border;
  $map->fill([ 1, 1 ], [ $height - 1, $width - 1 ], " ");
  # If they want a blank map, they comply.
  if ($depth == 0) {
    $map->refresh;
    return $map;
  }
  # There *MUST* be an even number of rooms!
  $depth++ if $depth % 2;
  # Place a bunch of rooms.
  foreach (1 .. $depth) {
    while (1) {
      my $exits = { N => [], S => [], E => [], W => [] };
      my $room = new Roguelike::Area::Structure::Room 10, 15;  # Defaults!
      my $y = random(1, $map->height - $room->height - 1);
      my $x = random(1, $map->width - $room->width - 1);
      next unless place($room, on => $map, at => [ $y, $x ], noadj => 1);
      # Get the exit data
      foreach my $dir (qw(N S W E)) {
        foreach (0 .. $#{$room->{Exits}{$dir}}) {
          push @{ $exits->{$dir} }, { ID => $#{ $map->{Data} }, Wall => $_ };
        }
      }
      last;
    }
  }
  # Now, connect the rooms. Ensure every room is connected to one other.
  my $rooms = [0 .. $#{ $map->{Exits} } ];
  while (@$rooms) {
    my $one = $map->{Exits}[delrand($rooms)];
    my $two = $map->{Exits}[delrand($rooms)];
    # Choose random wall for each room.
    my $dir1 = chooserand(qw(n s e w));
    my $dir2 = chooserand(qw(n s e w));
    $one = chooserand(@{ $one->{uc $dir1} });
    $two = chooserand(@{ $two->{uc $dir2} });
    my ($y1, $x1, $y2, $x2, $Y1, $X1, $Y2, $X2);
    if ($dir1 eq "n" or $dir1 eq "s") {
      $Y1 = $one->{Y1};
      $X1 = random($one->{X1} + 1, $one->{X2} - 1);
    } else {
      $Y1 = random($one->{Y1} + 1, $one->{Y2} - 1);
      $X1 = $one->{X1};
    }
    if ($dir2 eq "n" or $dir2 eq "s") {
      $Y2 = $two->{Y1};
      $X2 = random($two->{X1} + 1, $two->{X2} - 1);
    } else {
      $Y2 = random($two->{Y1} + 1, $two->{Y2} - 1);
      $X2 = $two->{X1};
    }
    ($y1, $x1) = dircoords($dir1, $Y1, $X1);
    ($y2, $x2) = dircoords($dir2, $Y2, $X2);
    my @path = $map->pathfind($y1, $x1, $y2, $x2, 1, 1, 1);
    if ($path[0] == -1) {
      say "CRAP! No path between points!";
      next;
    }
    # Yay! So carve out the path.
    $map->{Map}[$Y1][$X1]{_} = ".";
    $map->{Map}[$Y2][$X2]{_} = ".";
    foreach (@path) {
      my ($y, $x) = @$_;
      $map->{Map}[$y][$x]{_} = ".";
      $map->{Map}[$y][$x]{Path} = 1;
      # Put up some walls.
      foreach my $dir (qw(h j k l y u b n)) {
        ($y, $x) = keycoords($dir, @$_);
        if ($map->{Map}[$y][$x]{_} eq " ") {
          $map->{Map}[$y][$x]{_} = "#";
          $map->{Map}[$y][$x]{Path} = 1;
        }
      }
    }
  }
  # Hotspots!
  $_->{Hotspots} = [] foreach @{ $map->{Exits} };
  foreach (1 .. 50) { # Zzz
    while (1) {
      my $y = random(1, $height);
      my $x = random(1, $width);
      next unless $map->{Map}[$y][$x]{_} eq ".";
      next if $map->{Map}[$y][$x]{Hotspot};
      $map->{Map}[$y][$x]{Hotspot} = 1;
      push @{ $map->{Exits}[0]{Hotspots} }, [$y, $x];
      last;
    }
  }
  $map->refresh;
  return $map;
}

42;
