#!/usr/bin/perl
use strict;
use warnings;
use lib "../adv";
use include;

# CONFIGURATION
die "Usage: sim.pl [unit_size] [map] [single|multi] [rndfile|-]\n" unless @ARGV == 4;
my ($unit_size, $area, $mode, $rnds) = @ARGV;
# Rnd Starting Positions
CONFIG->rndload("../sim/$rnds") unless $rnds eq "-";
#my $unit_size = 20;     # [small], [large]
#my $area = "halls";      # beard, halls, squiggle
#my $mode = "single";   # single, multi

# SET UP UI
use HexedUI;
my $ui = create HexedUI {
  Main => {
    Type   => "Map",
    At     => [0, 0],
    Size   => ["100%", "100%"],
    Border => 1,
    Render => sub {
      my $tile = shift;
      my ($char, $color);
      if (ref $tile->{_}) {
        ($char, $color) = $tile->{_}->symbol;
      } elsif ($tile->{color}) {
        $char = $tile->{_};
        $color = $tile->{color};
      } else {
        $char = $tile->{_};
        $color = {
          "#" => "orange",
          "." => "grey"
        }->{$char};
        $color ||= "yellow";
      }
      return ord($char) | HexedUI::paint($color);
    }
  },
};
GAME->{UI} = $ui;

# SET UP MAP
use BDSM::Transform;
my $map = loadmap("../maps/$area");
$ui->{Main}->setup($map);
$map->{OnChange} = sub {
  my ($map, $y, $x, $new) = @_;
  $ui->{Main}->_mod($y, $x, $map->{Map}[$y][$x]);
};
use Highway;
preprock($map);

sub run {
  # <RANDOM> ###################################################################
  # Initialize units
  use Unit;
  my @units;
  GAME->{UnitSize} = $unit_size;  # leader needs to know to make room
  foreach (1 .. $unit_size) {
    my $unit = GAME->{Classes}{Unit}->new(Map => $map, Num => $_);
    if ($_ == 1) {
      $unit->{Magnet}{Last} = "h";
    } else {
      $unit->{Magnet}{Buddy} = $units[$_ - 2];
      # Whilst assembling, just form a line.
      $unit->{Magnet}{Dir} = [0, 1];
    }
    push @units, $unit;
  }

  # Choose a random destination.
  my ($goy, $gox);
  while (1) {
    $goy = CONFIG->random(0, $map->height);
    $gox = CONFIG->random(0, $map->width);
    my $tile = $map->{Map}[$goy][$gox];
    last if $map->{Map}[$goy][$gox]{Hiway};
  }

  # </RANDOM> ##################################################################

  # PART ONE: Assembly

  # Single: Find the highway and then our buddy, then give control to next unit.
  # Multi: Everybody find the highway at once. If our buddy is on too, find
  # them; otherwise wait.

  GAME->{AssCnt} = 0;
  my %found;
  while (1) {
    my $cntr = 0;
    foreach my $unit (@units) {
      if ($mode eq "single") {
        1 until $unit->gethi;
        1 until $unit->assemble == 42 and $unit->{Laster} = [$unit->{Y}, $unit->{X}];
        $cntr++;
      } else {
        $unit->gethi and $found{ $unit->{Num} }++ unless $found{ $unit->{Num} };
        next unless $found{ $unit->{Num} };
        $unit->assemble == 42 and $unit->{Laster} = [$unit->{Y}, $unit->{X}] and $cntr++;
      }
    }
    last if $cntr == @units;
  }

  $units[0]->{Magnet}{Buddy} = {
    Y      => $goy,
    X      => $gox,
    Laster => [-1, -1]
  };
  $units[0]->{Magnet}{Dir} = [0, 0];

  # PART TWO: Movement

  # Single & Multi: Follow our buddy until everybody reaches the destination.

  GAME->{MvCnt} = 0;
  while (1) {
    GAME->{UI}{Main}->draw;
    debug "to $goy, $gox. at $units[0]->{Y}, $units[0]->{X}" if $map->{Map}[$goy][$gox]{_} ne ".";
    foreach my $unit (@units) {
      ($unit->{Num} == 1) ? ctrl($goy, $gox, @units) : $unit->magnet($goy, $gox);
    }
  }
}

sub ctrl {
  my $goy = shift;
  my $gox = shift;
  my $me = shift;
  debug "to $goy, $gox. at $me->{Y}, $me->{X}";
  my @units = @_;

  GAME->{MvCnt}++;
  my $code = $me->assemble(42);
  die "SUCCESS. Ass " . GAME->{AssCnt} . ". Mv " . GAME->{MvCnt} . "." if $me->{Y} == $goy and $me->{X} == $gox;
  return unless $code;
  my $in = {
    1 => "k",
    2 => "j",
    3 => "h",
    4 => "l",
    5 => "y",
    6 => "u",
    7 => "b",
    8 => "n",
  }->{$code};

  # Update the vectors for the troops.
  $_->{Magnet}{Dir} = {
    l => [0, -1],
    h => [0, +1],
    k => [+1, 0],
    j => [-1, 0],
    y => [+1, +1],
    u => [+1, -1],
    b => [-1, +1],
    n => [-1, -1],
  }->{$in} foreach @units;
}

run;
