Public feed #379000

routeplanner/database

public text v1 · immutable
Raw Edit
·published 2007-03-02 22:35 UTC
rendered paste body
#!/usr/bin/env perl
# Dit is een routeplanner die gebruikt maakt van Geo::Google
#  om een route tussen verschillende adressen te berekenen.
#
# De adressen worden allen steeds opgeslagen in een appart bestand,
#  dit bestand zal automatisch gecreerd worden indien dit
#  nog niet bestaat.
#
# Om dit programma te kunnen gebruiken moet Geo::Google beschikbaar
#  zijn op de computer.
#
# Author:  MADnificent
# Version: 0.0.1

use Geo::Google;

# Globale variabelen
$DB_FILE = '.routeplanner.db';

# Voegt een adres toe aan de database van het programma.
#
# @pre	@_ = (naam, straat, nr, stad, land)
sub voegAdresToe
{
  open (DB, ">>$DB_FILE") || die "could not open database file";
  print DB maakDbRecord(@_);
  close (DB);
}


# Drukt al de adressen af op het scherm.
#
# @pre    file_exists($DB_FILE)
sub drukAdressenAf
{
  my($adressen) = dbGrootte();
  
  print "----------------------------------------------------------\n";
  print " Er zitten $adressen adressen in de database \n";
  print "----------------------------------------------------------\n";
  print "\n";

  drukAdresAf( (0 ... ($adressen-1)) );
}

# Drukt het gevraagde adres af uit de database
#
# @pre	@_[i] < dbGrootte
# @pre  voor onbekende adressen wordt er een lege
#       plaats afgedrukt (even groot dan een geheel
#       record zou innemen).
# @pre  fileExists($DB_FILE)
#
# @post	De gevraagde adressen zijn afgedrukt
sub drukAdresAf
{
  my(@params) = @_;
  my($cur);

  tussenRegel();

  foreach $cur (@params)
  {
    if($cur >=0  && $cur < dbGrootte())
    {
      my(@adres) = geefAdres($cur);
      print "nr:$cur\n";
      print " -- $adres[0] \n";
      print " --- $adres[1] $adres[2] \n";
      print " --- $adres[3], $adres[4] \n";
      tussenRegel();
    }
    else
    {
      print "\n\n\n\n";
    }
  }
}

# Vervangt het record met de gegeven geheugenplaats door het nieuwe
#  gegeven record
#
# @pre	@_[0] = $nr;
# @pre  $nr < dbGrootte;
# @pre  @_[1 .. $#_] = ($naam, $straat, $nummer, $stad, $land)
#
# @post	geefAdres($nr) == ($naam, $straat, $nummer, $stad, $land)
sub vervangAdres
{
  my($nr) = $_[0];
  $nr = dbGrootte() unless adresBestaat($nr);	# Als het id niet bestaat, voegen we het toe op het einde vd database.
  my($dbRegel) = maakDbRecord(@_[1 .. $#_]);
  
  open (DB, $DB_FILE);
  my(@data) = <DB>;
  close (DB);
  
  $data[$nr] = $dbRegel;
  open (DB, ">$DB_FILE");
  print DB @data;
  close (DB);
}
  

# Geeft de data van een bepaald adres-nummer terug.
#
# @pre  @_ = ($nr)
# @pre  $nr < dbGrootte
#
# @ret	($naam, $straat, $nummer, $stad, $land)
sub geefAdres
{
  open (DB, $DB_FILE);
  my(@data) = <DB>;
  close (DB);
  
  parseRecord( $data[$_[0]] );
}

# private
# Verwijdert spaties aan het begin en aan het einde van de gegeven strings
#
# @post	$_[i] =~ /^/S*.*/S*$/
sub trim
{
  my(@return);
  my(@lijst) = @_;
  my($cur);

  foreach $cur (@lijst)
  {
    $cur =~ s/^\s*//;
    $cur =~ s/\s*$//;
    push(@return, $cur);
  }
  return @return;
}

# private
# Haalt de data uit een lijn in de database (of een invoerlijn van de user)
#
# @pre    @_ = ($dbRecord)
# @pre  $dbRecord =~ /\w[\w|\s]*::\w[\w|\s]*::\s*\d+\s*::\w[\w|\s]*::\w[\w|\s]*/
# @pre  $dbRecord =~ /[^:]*::[^:]*::[^:]*::[^:]*::[^:]*/
#       || $dbRecord =~ /\w[\w|\-|\s]*::[a-zA-Z][a-zA-Z|\-|\s]*\s*\d+\s*::\w[\w|\-|\s]*::\w[\w|\-|\s]*/
#
# @ret    ($naam, $straat, $nummer, $stad, $land)
sub parseRecord
{
  if($_[0] =~ /([^:]*)::([^:]*)::([^:]*)::([^:]*)::([^:]*)/)
  {  return trim($1 , $2 , $3 , $4 , $5);  }
  elsif($_[0] =~ /(\w[\w|\-|\s]*)::([a-zA-Z][a-zA-Z|\-|\s]*)(\s*\d+\s*)::(\d+\s+\w[\w|\-|\s]*)::(\w[\w|\-|\s]*)/)
  {  return trim($1 , $2 , $3 , $4 , $5);  }
}

# private
# Geeft weer of de gegeven record-string voldoet aan de syntactische
#   voorwaarden om in de database gestoken te kunnen worden,
#   of niet.
#
# @pre	@_ = $recordString
sub isDbRecord
{
   my($recordString) = $_[0];

   # TODO Users _could_ enter newlines in this data... that would make the layout badd, and wouldn't be a
   #   valid address either...
   if($recordString =~ /\w[\w|\-|\s]*::[a-zA-Z][a-zA-Z|\-|\s]*\s*\d+\s*::\d+\s*\w[\w|\-|\s]*::\w[\w|\-|\s]*/)
   {  return 1; }
   # TODO This is not idiot-proof
   if($recordString =~ /[^:]*::[^:]*::[^:]*::[^:]*::[^:]*/)
   {  return 1; }
   
   return 0;
}

# private
# Maakt een van de gegeven data een string die in de database past.
#
# @pre	@_ = ($naam, $straat, $nr, $stad, $land)
#
# @ret	databse string for the given record
sub maakDbRecord
{
  "$_[0]::$_[1]::$_[2]::$_[3]::$_[4]\n";
}

# Zoekt het aantal elementen in de database van het programma.
#
# @pre    file_exists(DB_FILE) == true;
# 
# @ret    adressen in de database.
sub dbGrootte
{
  my($lijnen) = 0;

  open (DB, $DB_FILE);
  while(<DB>)
  {  $lijnen++; }
  return $lijnen;
}

# Geeft weer of een bepaald adres al dan niet in de database zit
#   indien het dbNummer gegeven is.
#
# @pre	@_ = ($dbNr)
sub adresBestaat
{
  my ($dbNr) = $_[0];
  return 1 if ($dbNr>=0 && $dbNr<dbGrootte);
  return 0;
}

# Verwijdert een regel uit de database van het programma.
#
# De telling van de lijnen begint bij lijn 0.
#   Dit impliceert dat de nummer van de verwijderde regel
#   gelijk is aan de nummer van het verwijderde record.
#   De nummers van de records met een hoger nummer dan dat
#   van het verwijderde record, hun recordnummer daalt met 1.
#
# @pre  file_exists("$DB_FILE");
# @pre  line_exists("$DB_FILE", $lineNr);
# 
# @post Lijnen zijn naar boven verplaatst.
sub verwijderRegel
{
  my(@data);
  my($rem_line) = $_[0];  

  open (DB, $DB_FILE);
  @data = <DB>;
  splice(@data, $rem_line, 1);
  close (DB);

  open (DB, ">$DB_FILE");
  print DB @data;
  close (DB);
}

# Berekent de route tussen twee adressen (die gegeven zijn in een formaat
#   dat Geo::Google begrijpt.
#
# @pre  @_ = ($adresA, $adresB);
# @pre  $_[i] beschrijft routen die Geo::Google begrijpt en die bestaan. 
#       | typeOf($_[i]) == 'String';
#
# @ret  Pad dat de route beschrijft.
#        je kan de data uit dit pad halen door @ret->segments();
#        Uit elk van deze segmenten kan je
#         o -> text     Tekstuele omschrijving
#         o -> html     Langere omschrijving
sub berekenRoute
{
  my ($geo) = Geo::Google->new();
  print "adresstrings: \n $_[0] \n $_[1] \n";

  my ($locA) = $geo->location( address => $_[0] );
  my ($locB) = $geo->location( address => $_[1] );

  my ($path) = $geo->path( $locA , $locA , $locB , $locB );
 
  return $path; 
}


# Berkent de route tussen twee adressen (met het adresnummer gegeven)
#
# @pre  @_ = ($adresA , $adresB);
# @pre  $_[i] < dbGrootte
#
# @ret	Array van strings die de route in menselijke taal beschrijven.
sub geefRouteBeschrijving
{
  my($adresA, $adresB) = ( $_[0] , $_[1] );
  
  # haal de adressen uit de databank
  my(@dataA) = geefAdres( $adresA );
  my(@dataB) = geefAdres( $adresB );

  # bouw adresstrings op uit de data
  my($stringA) = "$dataA[2] $dataA[1], $dataA[3], $dataA[4]";
  my($stringB) = "$dataB[2] $dataB[1], $dataB[3], $dataB[4]";
  
  # geef de data door aan de berekenfunctie
  my(@route) = berekenRoute($stringA, $stringB)->segments(); 

  # haal de tekstStrings uit de berekeningen
  my(@routeBeschrijving);
  my($seg);
  foreach $seg (@route)
  {
    # $seg->html zou een beter beschrijving kunnen opleveren.
    my($text) = $seg->text;
    push(@routeBeschrijving, $text);
  }
 
  return @routeBeschrijving; 
}


# Geeft weer of het mogelijk is een route te berekenen in
#   de huidige databank.
sub kanRouteBerekenen
{
  if(dbGrootte>=2)
  {  return 1; }
  return 0;
}

# Geeft zeer of er records zijn die afgedrukt kunnen worden
sub heeftRecords
{
  if(dbGrootte>0)
  { return 1; }
  return 0;
}

#####  Hier staan de modi waarin de gebruiker data kan invoeren/uitvoeren #####

### Hulpcode om data van de gebruiker te parsen naar acties uit het systeem

# Afhandeling van de routeberekening en afdruk
#
# @pre  @_ = ($adresA , $adresB);
# @pre  0 <= $_[i] < dbGrootte
#
# @post De weg werd berekend en afgedrukt
sub geefRoute
{
  my($adresA, $adresB) = ($_[0], $_[1]);
  die "Gelieve correcte adresnummers in te geven" unless ($adresA<dbGrootte && $adresB<dbGrootte)
							&& ($adresA>=0 && $adresB>=0)
							&& ($adresA != $adresB);
  
  print "De route tussen adres $adresA en $adresB zal berekend worden.\n";
  drukAdresAf($adresA, $adresB);
  
  @beschrijving = geefRouteBeschrijving($adresA, $adresB); 
  
  my($opdracht);
  foreach $opdracht (@beschrijving)
  {
    print "$opdracht\n";
  }
}

# Update het gevraagde record met de gegeven data.
#
# @pre	De eerste meegegeven waarde is de nummer van het record dat aangepas zal worden.
# 	|$_[0] = $nr
# @pre	$nr >= 0 && $nr < dbGrootte
#
# @post	In het record zal de nieuwe data staan (aangegeven door $nNaam, $nStraat, ...)
# 	|geefAdres($nr)==($nNaam,$nStraat,$nNummer,$nStad,$nLand
sub updateRecord
{
  # haal de meegegeven data binnen
  my($nr) = $_[0];
  my(@data) = @_[1 ... $#_];
  return 0 unless dbGrootte > $nr;
  
  # parse de data uit de functie
  my(@record) = geefAdres($nr);
  my(@curTag);
  while($curTag = shift(@data))
  {
    my(@value) = shift(@data);
    if($curTag eq "naam")
    {  $record[0] = @value; }
    elsif($curTag eq "straat")
    {  $record[1] = @value; }
    elsif($curTag eq "nr" || $curTag eq "nummer" || $curTag eq "straatnr" || $curTag eq "straatnummer")
    {  $record[2] = @value; }
    elsif($curTag eq "stad" || $curTag eq "dorp" || $curTag eq "gemeente")
    {  $record[3] = @value; }
    elsif($curTag eq "land")
    {  $record[4] = @value; }
  }
  
  # vervang het oude record bij <nr> door het nieuwe record
  vervangAdres($nr, @record);

  return 1;
}

# Toont een scheidingsregel tussen verschillende items/records/whatever
sub tussenRegel
{
  print "---------------------------------------------------------------\n";
}
  
### Functies voor de interactieve modus

# Toont een record-browser waarmee gebruikers records kunnen opzoeken
#   en eventueel selecteren.
#
# @pre  @_ = ($menustructuur, $selecteerbaar, $beginID)
# @var	$menustructuur
#       Dit is de structuur zonder de toevoeging van
#       " > browser" of van " > selector";
# @var  $selecteerbaar
#       Dit toont aan of de opties ivm selecteren van items
#       aangezet moeten worden.  De browser geeft eenderhoe
#       de laatst geziene waarde van de gebruiker terug.
# @var  $beginID
#       Dit is de ID die in het begin centraal zal staan in de browser.
sub toonBrowser
{
   my($menustructuur , $selecteerbaar, $beginID) = @_;
   # Verzekerd een correcte beginID
   $beginID = $beginID < 0 ? 0 : $beginID;
   $beginID = $beginID >= dbGrootte() ? (dbGrootte()-1) : $beginID;
   # bouw menu op
   my($menu) = $menustructuur . ($selecteerbaar ? " > selector" : " > browser");
   my(@help) = (
      $menu,
      "De recordbrowser is een systeem waarin de verschillende",
      "records kunnen bekeken" . ($selecteerbaar ? " en geselecteerd" : "") . " worden.",
      "[j]",
         "de letter j zal de lijst een letter naar beneden doen gaan.",
         "Indien voor de letter j een getal staat, dan zal er net zoveel",
         "items naar beneden gegaan worden dan dat getal groot is.",
      "[k]",
         "de letter k zal de lijst een letter naar boven doen gaan.",
         "Indien voor de letter een getal staat, dan zal er net zoveel",
         "items naar boven gegaan worden dan dat getal groot is.",
      "[h]",
         "de letter h zal dit help-menu nogmaals te voorschijn toveren.",
      "[niets]",
         "een lege input zal de laatste input heruitvoeren",
         "dit is dus niet het woordje 'niets' ;-)",
      "[x]",
         "stopt de browser.");
   if($selecteerbaar)
   { push(@help, "Het middelste item is dan geselecteerd (u kan het item-nummer",
                  "ook bekijken in de responsbalk."); }
   # Toon help als introductie
   toonMenu (@help);
   
   # Toon de browser
   my($curID) = $beginID;
   my($prevInput);   # this is the input the user gave right before this input.
   my($repeat);
   browserSnap($menu, $selecteerbaar, $curID);
   my($line) = "";
   until($line =~ /x/)
   {
     tussenRegel();
     # catch the repeat-action
     if($repeat)
     {
       $line = $prevInput;
       $repeat = 0;
     }
     else
     {
       print "Uw input:   ";
       $line = <STDIN>;
     }
      
     #scroll down (numbers go up)
     if($line =~ /(\d*)j/)
     {
        if($1)
        {  $curID += $1; }
        else
        {  $curID += 1; }
     }
     #scroll up (numbers go down)
     elsif($line =~ /(\d*)k/)
     {
        if($1)
        {  $curID -= $1; }
        else
        {  $curID -= 1; }
     }
     #toon help
     elsif($line =~ /h/)
     {
        toonMenu (@help); 
     }
     elsif($line eq "\n")
     {
        $repeat = $repeat ? 0 : 1;  # this solves the pressing of <enter> every time
     }
     #vang fouten in $curID op
     $curID = $curID >= dbGrootte() ? (dbGrootte()-1) : $curID;
     $curID = $curID < 0 ? 0 : $curID;

     $prevInput = $line unless $repeat;

     #toon het nieuwe venster
     browserSnap($menu, $selecteerbaar, $curID);
   }
   
   return $curID;
}    

# Toont een bepaald venster van de browser.
#
# @pre  @_ = ($menu, $selecteerbaar, $centraleID);
# @pre  0 <= $centralID < dbGrootte
# @pre  $menu = /[\w+\s>]*\w+/
sub browserSnap
{
  my($menu , $selecteerbaar , $centraleID) = @_;
  printStructuur($menu);  
  
  drukAdresAf(($centraleID-1)...($centraleID+1));
  
  print "huidige ".($selecteerbaar?"geselecteerde ":"")."ID :   $centraleID\n";
}

# Toont een menu op het scherm, en geeft de invoer van de gebruiker
#   terug weer
#
# @pre  @_ = ($menu , @inleiding, @optiesEnOmschrijvingen)
# @pre	$menu = "menu > submenu > subsubmenu ..."
# @pre  @inleiding = ("dit is een leidende", "tekst die ...)
# @pre  @optiesOmschrijving = ("[optie]", "regelBijOptie", "regel bij optie",
#                              "[ander]", "regel bij optie,
#                              "[nog]", "r1", "r2", "r3", ...);
# @pre  exists(@optiesOmschrijving)
#
# @ret  Een optie die bij de optiesOmschrijving stond
sub toonMenu
{
   my(@params) = @_[1 ... $#_];
   
   my($beginOpties)=0;
   while(!($params[$beginOpties] =~ /^\[\w+\]$/))
   {  $beginOpties++; }
   
   my(@inleiding) = @params[0 ... ($beginOpties-1)];
   my(@opties) = @params[$beginOpties ... $#params];

   print "\n\n\n";
   tussenRegel; 
   printStructuur($_[0]);
   printInleiding(@inleiding);
   tussenRegel;
   printOpties(@opties);
   tussenRegel;
   print "Uw keuze: ";
   my($in);
   $in = <STDIN>;
   chop($in);
   return $in;
}

# Print de opties die bij een bepaald menu horen.
#
# @pre  @_ = ($optie1, $introlijn1, $introlijn2, ...,
#             $optie2, $introlijn, ...,
#             ...);
# @pre  $optie =~ /^\[\w+\]$/
sub printOpties
{
   my($cur);
   foreach $cur (@_)
   {
     print "    " unless $cur =~ /^\[\w+\]$/;
     print "$cur\n";
   }
}

# Print de inleidende informatie die bij de menus gegeven wordt.
#   Indentatie wordt automatisch afgehandeld.
#
# @pre  @_ = ("eerste regel", "tweede regel", ...)
sub printInleiding
{
  my(@args) = @_;
  print shift(@args), "\n";
  my($regel);
  while($regel = shift(@args))
  {
    print "   $regel\n";
  }
}
    

# Print de structuur af die de gebruiker toont waar hij zich bevind.
# 
# @pre	@_ = ($structuur, ...);
# @pre  $structuur = "menu > submenu > subsubmenu";
sub printStructuur
{
  tussenRegel;
  print "MENU ::    $_[0]\n";
  tussenRegel;
}

# Vraagt de gebruiker een input die correct is (moet voldoen aan de
#    meegegeven regex
#
# @pre  @_ = ($regex, @vraag);
sub vraagGebruikerRegex
{
   my($regex, @vraag) = @_;

   my($line);
   $line = vraagGebruiker(0, @vraag);
   while( !($line =~ $regex) )
   {  $line = vraagGebruiker(1, @vraag); }
   
   return $line;
}   

# Stelt een vraag een de gebruiker en heeft een interface voor het heralen
#  van vragen aan de gebruiker.
#
# @pre  @_ = ($herhaling, @vraag);
# @pre  @vraag = ($regel1, $regel2, ...);
sub vraagGebruiker
{
  my($herhaling, @vraag) = @_;
  
  if(!$herhaling)
  {
    $aantalKeerDatGebruikerVraagKreeg = 0;
    toonVraagGebruiker(@vraag);
  }
  elsif($aantalKeerDatGebruikerVraagKreeg < 5)
  {
    $aantalKeerDatGebruikerVraagKreeg++;
    print "Uw input was niet correct, probeer nogmaals.\n";
  }
  else
  {
    $aantalKeerDatGebruikerVraagKreeg = 0;
    print "Uw input was niet correct, de vraag was: \n";
    toonVraagGebruiker(@vraag);
  }
  
  print "Uw input:   ";
  my($input);
  $input = <>;
  chop($input);
  print "\n";
  return $input;
}

# Print een gestelde vraag voor de gebruiker af
#
# @pre  @_ = ($regel1, $regel2, ...);
sub toonVraagGebruiker
{
   print "\n";
   tussenRegel;
   my(@regels) = @_;
   my($regel) = shift(@regels);
   print "$regel\n";
   while($regel = shift(@regels))
   {  print "   $regel\n"; } 
}
    
# Vraagt de gebruiker om de naam van een gebruiker
#   in te voeren.
#
# @pre  @_ = ($menu)
# @var	$menu
#       Het menu wordt ingegeven tot aan de parent van
#       dit gedeelte.  Dit wordt automatisch aangevuld
#       tot een bruikbare naam voor deze module.
#       e.g: $menu eq "main > add"
sub enterUser_naam
{
   my($menu) = "$_[0] > naam";
   my($line);
   printStructuur($menu);
   $line = vraagGebruikerRegex(
        '\w[\w|\-|\s]*',
        "Gelieve de naam van de gebruiker in te vullen.");
   return $line;
}
   
# Vraagt de gebruiker om de straat en nummer van een gebruiker
#   in te voeren.
#
# @pre  @_ = ($menu)
# @var	$menu
#       Het menu wordt ingegeven tot aan de parent van
#       dit gedeelte.  Dit wordt automatisch aangevuld
#       tot een bruikbare naam voor deze module.
#       e.g: $menu eq "main > add"
#
# @ret	($street, $digit)
sub enterUser_straat
{
   my($menu) = "$_[0] > straat";
   printStructuur($menu);
   my(@vraag) = ( 
       "Gelieve de straatnaam en de nummer van de straat",
       "(gescheiden door een spatie) in te geven.");
   my($line) = vraagGebruiker(0,@vraag);
   my($correct) = ($line =~ /([a-zA-Z][a-zA-Z|\-|\s]*)\s*(\d+)\s*/);
   my($street) = $1;
   my($digit) = $2;
   while(!$correct)
   {
      $line = vraagGebruiker(1,@vraag);
      $correct = ($line =~ /([a-zA-Z][a-zA-Z|\-|\s]*)\s*(\d+)\s*/);
      $street = $1;
      $digit = $2;
   }
   return ($1, $2);
}
      
# Vraagt de gebruiker om de stad van een gebruiker
#   in te voeren.
#
# @pre  @_ = ($menu)
# @var	$menu
#       Het menu wordt ingegeven tot aan de parent van
#       dit gedeelte.  Dit wordt automatisch aangevuld
#       tot een bruikbare naam voor deze module.
#       e.g: $menu eq "main > add"
sub enterUser_stad
{
   my($menu) = "$_[0] > stad";
   printStructuur($menu);
   my($line) = vraagGebruikerRegex(
       '\d+\s+\w[\w|\-|\s]*',
       "Gelieve de naam van de stad/gemeente van de gebruiker",
       "in te geven, voorafgegaan door de postcode");
   return $line;
}

# Vraagt de gebruiker om het land van een gebruiker
#   in te voeren.
#
# @pre  @_ = ($menu)
# @var	$menu
#       Het menu wordt ingegeven tot aan de parent van
#       dit gedeelte.  Dit wordt automatisch aangevuld
#       tot een bruikbare naam voor deze module.
#       e.g: $menu eq "main > add"
sub enterUser_land
{
   my($menu) = "$_[0] > land";
   printStructuur($menu);
   my($line) = vraagGebruikerRegex(
      '\w[\w|\-|\s]*',
      "Gelieve het land van de gebruiker in te geven");
   return $line;
}

# Vraagt de gebruiker om een naam in te voeren.
#   Deze module handeld het invoegen van een naam af
#   op verscheidene manieren (die hier dus handig
#   gegroepeerd staan).
#
# @pre  @_ = ($menu , @intro)
# @var	@intro is een array met verschillende strings
#       die samen de introductie uitleggen over het waarom
#       van de data-invoer door de gebruiker.
# @var  $menu is de menustructuur die bovenaan de selectie
#       van de data-invoer zal getoond worden.
sub interactiveEnterUser
{
   my($menu, @intro) = @_;
   my(@addMenu) = 
     ("$menu > opties",
      @intro,
      "[lijn]",
      "geeft een gebruiker in op 1 lijn",
      "eg: Steward John::Spring Avenue 67::3476 Springfield::Isle of Man",
      "[individueel]",
      "Het systeem zal hier verscheidene vragen stellen",
      "tot de gebruiker volledig gedefinieerd is.",
      "[leave]",             
      "Toch geen gebruiker definieren?",
      "Kies exit om naar het vorige menu weer te keren.");
   
   # Toon het keuzemenu tot de gebruiker een geldige invoer heeft gegeven.
   my($input);
   while( !($input =~ /[lijn|individueel|leave]/) )
   {  $input = toonMenu(@addMenu); }
   
   return if $input =~ /leave/;

   # Gebruikte veriabelen
   my(@regex, @vraag, $line);
   # Voeg een gebruiker toe in n lijn
   if($input =~ /lijn/)
   {
      $line = vraagGebruikerRegex(
           '\w[\w|\-|\s]*::[a-zA-Z][a-zA-Z|\-|\s]*\s*\d+\s*::\d+\s+\w[\w|\-|\s]*::\w[\w|\-|\s]*',
           "Gelieve de data in te vullen in een string:",
           "eg: Steward John::Spring Avenue 67::3476 Springfield::Isle of Man");
      return parseRecord($line);
   }
   # Voeg een gebruiker toe aan de hand van individuele vragen
   else
   {
      my(@gebruiker);
      #naam van de gebruiker
      $line = enterUser_naam($menu);
      push (@gebruiker, $line);
      #straat van de gebruiker
      push (@gebruiker, enterUser_straat($menu));
      #stad van de gebruiker
      push (@gebruiker, enterUser_stad($menu));
      #land van de gebruiker
      push (@gebruiker, enterUser_land($menu));

      return @gebruiker;
   } 
}

# Afhandling van de add-actie van de gebruiker
sub interactiveAdd
{
   my(@user) = interactiveEnterUser ("main > add",
      "Voeg een gebruiker toe aan de database");
   
   if(@user)
   {  voegAdresToe(@user); }
}

# Afhandling van de update-actie van de gebruiker
sub interactiveUpdate
{
  my($input, $leave);
  my($menu) = "main > wijzig";
  my(@menuInhoud) = (
      $menu,
      "Hier kan u de verschillende methoden kiezen",
      "waarop u een gebruiker kan selecteren uit",
      "de databank, om deze later aan te passen.",
      "[browser]",
         "Deze optie start de browser die u het te",
         "wijzigen element zal laten kiezen uit",
         "de lijst met adressen.",
      "[getal]",
         "Indien u een getal intypt, zal het gevraagde",
         "record verschijnen ter controle, en kan",
         "onmiddelijk overgegaan worden in het wijzigen",
         "van het record (iets sneller als je de ID van",
         "het record reeds kent).",
       "[leave]",
         "Heeft u zich bedacht, en wil u toch geen gebruiker",
         "verwijderen? Of heeft u ondertussen voldoende",
         "gebruikers de records uit gesmeten?",
         "Kies dan <leave> om weer in het vorige",
         "menu terecht te komen"); 
  # het gekozen record 
  my($chosenRecord);
  my($recordGekozen);
  until($leave)
  {
    $recordGekozen = 0;
    until($recordGekozen || $leave)
    {
      $input = toonMenu(@menuInhoud);
      if($input =~ /browser/)
      {
        $chosenRecord = toonBrowser($menu, 1, 0);
        printStructuur("$menu > controle");
        drukAdresAf($chosenRecord);
        print "Bent u zeker dat u dit adres wil wijzigen? (Y/n)";
        my($check);
        $check = <>;
        $recordGekozen = 1 unless $check =~ /[n|N]/;
      }
      elsif($input =~ /(\d+)/)
      {
        print "$input\n";
        $chosenRecord = $1;
        if(adresBestaat($chosenRecord))
        {
          drukAdresAf($chosenRecord);
          print "Bent u zeker dat u dit adres wil wijzigen? (Y/n)";
          my($check);
          $check = <>;
          $recordGekozen = 1 unless $check =~ /[n|N]/;
        }
        else
        { print "Oeps, dat record bestaat niet :-)\n"; }
      }
      elsif($input =~ /leave/)
      {  $leave = 1; }
      else
      { print "Oeps, die optie bestaat niet, probeer nog eens :-)\n"; }
    }
    # We don't want to adjust records if we want to leave
    next if $leave;
    my($doneWithOperations)=0;
    my($menu_mod) = "$menu > ID:$chosenRecord";
    until($doneWithOperations)
    {
      my(@user) = geefAdres($chosenRecord);
      $input = toonMenu(
         $menu_mod,
         "Hier kan u kiezen welke eigenschappen u wil aanpassen",
         "van het door u geselecteerde adres.",
         "[naam]",
            "Pas de naam aan van de persoon.",
         "[straat]",
            "Pas de straat aan van het adres.",
         "[stad]",
            "Pas de stad aan van het adres.",
         "[land]",
            "Pas het land aan van het adres.",
         "[stop]",
            "Stopt met aanpassingen aan het adres,",
            "en gaat weer naar het vorige menu.");
         
      if($input=~/naam/)
      {
         my($naam) = enterUser_naam($menu_mod);
         $user[0] = $naam;
         vervangAdres($chosenRecord, @user);
      } 
      elsif($input=~/straat/)
      {
         my($straat, $nr) = enterUser_straat($menu_mod);
         @user[1,2] = ($straat, $nr);
         vervangAdres($chosenRecord, @user);
      }
      elsif($input=~/stad/)
      {
         my($stad) = enterUser_stad($menu_mod);
         $user[3] = $stad;
         vervangAdres($chosenRecord, @user);
      }
      elsif($input=~/land/)
      {
         my($land) = enterUser_land($menu_mod);
         $user[4] = $land;
         vervangAdres($chosenRecord, @user);
      }
      elsif($input=~/stop/)
      {  $doneWithOperations = 1; }
      else
      {  print "Oeps, u kees een opdracht die niet beschikbaar was.\n"; }
    }
  }
} 

# Afhandeling van de Print actie van de gebruiker
sub interactivePrint
{
  my ($input);
  my ($db_max) = (dbGrootte()-1);
  my ($title) = "main > print";
  my (@menu) =
     ( $title, 
       "Selecteer 1 van de onderstaande opties om",
       "de door u gewenste data af te drukken.",
       "Druk op <ENTER> om de browser te starten!",
       "[alles]",
           "Deze optie drukt al de gekende records af.",
       "[nummers]",
           "U kan ook opteren om verscheide nummers,",
           "gescheiden door een spatie in te typen",
           "de records die hier aan voldoen zullen dan",
           "afgedrukt worden.",
           "net als voor de reeks moeten de getallen zich",
           "bevinden tussen 0 en $db_max.",
       "[browse]",
           "Met deze optie kan u rustig door de lijst",
           "van namen scrollen.",
       "[leave]",
           "Wil u liever toch geen records afdrukken?",
           "kies dan deze optie om naar het vorige menu",
           "weer te keren.");
  my($success) = 0;
  
  until($success)
  {
    $input = toonMenu(@menu);
    # Toon alles
    if($input =~ /alles/)
    {  
       drukAdressenAf; 
       $success++;
       print "druk <enter> om weer naar het vorige menu te keren\n";
       <>;
    }
    # Druk een aantal records af
    elsif($input =~ /[\d+\s+]+/)
    {
       my(@numbers) = split(/\s+/, $input);
       my(@records);
       # zet de correcte adressen in @records
       my($record);
       foreach $record (@numbers)
       {
          if($record >= 0 && $record <= $db_max)
          {  push(@records, $record); }
       }
          
       drukAdresAf(@records); 
       $success++;
       print "druk enter om weer naar het vorige menu te keren\n";
       <>;
    }
    # Browse
    elsif($input =~ /browse/)
    {
       toonBrowser($title, 0, 0);
    }
    # Ga uit de lus
    elsif($input =~ /leave/)
    {  $success++; print "leave";}
    else
    { 
       # Foutieve input gekregen
       print "Oeps, u heeft foutieve input ingegeven, probeer nogmaals\n";
       print "   druk <enter> om weer een keuze te kunnen maken.\n";
       <>;
    }
  }

}

# Afhandeling van de delete-actie van de gebruiker.
sub interactiveDelete
{
  my($input, $leave);
  my($menu) = "main > delete";
  until($leave)
  {
    $input = toonMenu(
        $menu,
        "Hier kan u de verschillende methoden kiezen",
        "waarop u een gebruiker kan verwijderen uit",
        "de databank.",
        "[browser]",
           "Deze optie start de browser die u het te",
           "verwijderen element zal laten kiezen uit",
           "de lijst met adressen.",
        "[getal]",
           "Indien u een getal intypt, zal het gevraagde",
           "record verschijnen ter controle, en kan",
           "onmiddelijk overgegaan worden in het verwijderen",
           "van het record (iets sneller als je de ID van",
           "het record reeds kent).",
         "[leave]",
           "Heeft u zich bedacht, en wil u toch geen gebruiker",
           "verwijderen? Of heeft u ondertussen voldoende",
           "gebruikers de records uit gesmeten?",
           "Kies dan <leave> om weer in het vorige",
           "menu terecht te komen"); 

    my($chosenRecord);
    if($input =~ /browser/)
    {
      $chosenRecord = toonBrowser($menu, 1, 0);
      printStructuur("$menu > controle");
      drukAdresAf($chosenRecord);
      print "Bent u zeker dat u dit adres wil verwijderen? (Y/n)";
      my($check);
      $check = <>;
      verwijderRegel($chosenRecord) unless $check =~ /[n|N]/;
    }
    elsif($input =~ /(\d+)/)
    {
      print "$input\n";
      $chosenRecord = $1;
      if($1>=0 || $1 < dbGrootte())
      {
        drukAdresAf($chosenRecord);
        print "Bent u zeker dat u dit adres wil verwijderen? (Y/n)";
        my($check);
        $check = <>;
        verwijderRegel($chosenRecord) unless $check =~ /[n|N]/;
      }
      else
      { print "Oeps, dat record bestaat niet :-)\n"; }
    }
    elsif($input =~ /leave/)
    {  $leave = 1; }
    else
    { print "Oeps, die optie bestaat niet, probeer nog eens :-)\n"; }
  }
}

# Afhandeling van de route-actie van de gebruiker
sub interactiveRoute
{
  my(@adress, $input, $leave);
  my($menu) = "main > route";
  until($leave)
  { 
    @adress = ();
    my($grootte) = 0;
    until($grootte==2 || $leave)
    {
      print "grootte :: $grootte,   of $adress\n";
      print "adress  :: @adress\n";

      $input = toonMenu(
        $menu,
        "Hier kan u de verschillende methoden kiezen",
        "waarop u een gebruiker kan selecteren als ".($grootte==0?"vertrek":"bestemming"),
        "voor de route.",
        "[browser]",
           "Deze optie start de browser, waarin u",
           "eenvoudig het adres dat u zoekt kan",
           "selecteren",
        "[getal]",
           "Indien u een getal intypt, zal het gevraagde",
           "record verschijnen ter controle, en kan",
           "onmiddelijk overgegaan worden tot het gebruiken",
           "van het adres voor de routebepaling.  Indien u",
           "het adres kent bij nummer, is dit een snellere",
           "methode.",
         "[leave]",
           "Heeft u zich bedacht, en wil u toch geen gebruiker",
           "verwijderen? Of heeft u ondertussen voldoende",
           "gebruikers de records uit gesmeten?",
           "Kies dan <leave> om weer in het vorige",
           "menu terecht te komen"); 
      
       my($gebruiker);
       if($input =~ /browser/)
       {
         $gebruiker = toonBrowser($menu, 1, 0);
         printStructuur("$menu > controle");
         drukAdresAf($gebruiker);
         print "Bent u zeker dat u dit adres wil gebruiken \n";
         print ("als ".($grootte==0?"vertrek":"bestemming")."? (Y/n)  ");
         my($check);
         $check = <>;
         push(@adress, $gebruiker) unless $check =~ /[n|N]/; 
       }
       elsif($input =~ /(\d+)/) 
       {
         $gebruiker = $1;
         if($gebruiker>=0 && $gebruiker<dbGrootte())
         {  
           # nog even controleren of de gebruiker dit adres bedoelde.
           printStructuur("$menu > controle");
           drukAdresAf($gebruiker);
           my($print) = "Bent u zeker dat u dit adres wil gebruiken \n";
           $print .= ("als ".($grootte==0?"vertrek":"bestemming")."? (Y/n)  ");
           print $print;
           my($check);
           $check = <>;
           push(@adress, $gebruiker) unless $check =~ /[n|N]/; 
         }
         else
         {  print "Oeps, dit adres bestaat niet, probeer nogmaals.\n"; }
       }
       elsif($input =~ /leave/)
       {  $leave = 1; }
       else
       {  print "Oeps, u gaf een onbestaande optie, probeer nogmaals.\n"; }
 
       $grootte = @adress;
    }
    

    if(!$leave) 
    {
      printStructuur($menu." > afdruk");
      geefRoute(@adress);
      print "druk op een toets om weer naar het menu te gaan";
      <>;
    }
  }
}

### Afhandeling van de acties van de gebruiker

# Een interactieve modus waarin de gebruiker zijn opties kan bekijken
#  en zo operaties op de data kan uitvoeren.
#
# @post	Gebruiker zal gevraagd worden data in te voeren,
# 	 die overeen stemt met de acties die hij wil ondernemen.
sub interactieveModus
{
  tussenRegel;
  print "Welkom in de interactieve modus\n";
  tussenRegel;
  
  my($input) = "";
  my(@menu);
  while($input ne "quit")
  {
    # We need to calculate the menu every time (after the add, the options may change).
    @menu = ( "main",
	"Gelieve uit de opties (geschreven tussen de [ ]) een keuze te maken,",
	"en deze in te typen (gevolgd door enter)",
	"[add]",
		"voeg een gebruiker toe aan de database" );
    #---------- AVOIDS USERS TO CHOOSE UNAVAILABLE OPTIONS -------------#
    if( heeftRecords() )
    {
    	push(@menu,
		"[update]",
			"geven om uw keuze te maken (volgen door <enter>).",
			"update de gegevens van een gebruiker",
		"[print]",
			"drukt de gegevens van gebruiker(s) af",
		"[delete]",
			"verwijdert de gegevens van een gebruiker");
    }
    if( kanRouteBerekenen() )
    {  push(@menu, "[route]", "geeft de route tussen twee gebruikers"); }
    #---------- AVOIDS USERS TO CHOOSE UNAVAILABLE OPTIONS -------------#
    push(@menu, "[quit]",  "sluit de applicatie af"); 
		
    $input = toonMenu( @menu );

    if($input =~ /add/)
    {  interactiveAdd(); }
    elsif($input =~ /update/)
    {  interactiveUpdate(); }
    elsif($input =~ /print/)
    {  interactivePrint(); }
    elsif($input =~ /delete/)
    {  interactiveDelete(); }
    elsif($input =~ /route/)
    {  interactiveRoute(); }
  }
  exit;
}

# De gebruiker heeft al de data van de uit te voeren bewerkingen
#  reeds op de commandline ingegeven.
#  Deze data zal geparsed worden, en de bewerkingen zullen
#  uitgevoerd worden.
#
# @post	De door de gebruiker ingegeven data zal geparsed worden
sub cliModus
{
  #TODO Finish method stub
  tussenRegel;
  print "Welkom in de cli modus\n";
  print "Uw argumenten waren @ARGV \n";
  tussenRegel;
  # adres(sen) afdrukken
  if($_[0] eq "print" || $_[0] eq "-p")
  {  
    heeftRecords() || die "Er zijn geen records in de database!";
    if(exists($_[1]) && $_[1] < dbGrootte)
    {
      drukAdresAf(@_[1 .. $#_]);
    }
    else
    {  drukAdressenAf; }
  }
  # browser starten
  elsif($_[0] eq "-b" || $_[0] eq "browse" || $_[0] eq "browser")
  {
    heeftRecords() ||  die "U kan geen browser starten in een leeg adressenbestand";
    # start de browser op het gegeven adres
    if(exists($_[1]))
    {
      toonBrowser("cli" , 0 , $_[1]);  
    }
    else
    {
      toonBrowser("cli" , 0 , 0);
    }
  }
  # adres toevoegen
  elsif( exists($_[1]) && ($_[0] eq "-a" || $_[0] eq "add" || $_[0] eq "voeg toe" || $_[0] eq "voegtoe") )
  { 
    isDbRecord($_[1]) || die "Verkeerd geformatteerde of onvolledige input gegeven";
    voegAdresToe( parseRecord($_[1]) );
  }
  # adres update
  elsif($_[0] eq "update" || $_[0] eq "wijzig" || $_[0] eq "-u")
  {
    updateRecord( @_[1 ... $#_] ) || die "Het gegeven adres bestaat niet";
  }
  # adres substitute 
  elsif($_[0] eq "-s" || $_[0] eq "subs" || $_[0] eq "vervang" || $_[0] eq "substitute" || $_[0] eq "verv")
  {
    isDbRecord($_[2]) || die "Verkeerd geformatteerde of onvolledige input gegeven"; 
    vervangAdres( $_[1] , parseRecord($_[2]) );
  }
  # adres verwijderen
  elsif($_[0] eq "-d" || $_[0] eq "del" || $_[0] eq "delete" || $_[0] eq "verwijder")
  {
    adresBestaat($_[1]) || die "Te verwijderen adres bestaat niet.";
    verwijderRegel( $_[1] );
  }
  # bereken route
  elsif($_[0] eq "-r" || $_[0] eq "-w" || $_[0] eq "route" || $_[0] eq "weg")
  {
    #TODO The new Geo::Google should catch this one, test this
    geefRoute( @_[1 ... $#_] );
  }
}

# private
# update een bepaald gegeven uit een record

# De help die bij het commando hoort zal worden weergegeven.
#
# @post De help wordt op het scherm geprint.
sub cliHelp
{
  print "Dit is de help van het 'routes' commando.\n";
  tussenRegel;
  print "Het commando kan opgeroepen worden op verscheidene manieren\n";
  print "- Zonder opties wordt het commando in interactieve modus gestart\n";
  print "   In deze modus kan u steeds help typen om een lijst te krijgen\n";
  print "   van de mogelijke commandos.  Deze help beschrijft echter de \n";
  print "   commandline interface, die slechts 1 verwerking per oproep \n";
  print "   zal verwerken.\n";
  print "- Met de hier beschreven opties zal het programma 1 actie \n";
  print "   ondernemen per oproep, dit systeem is handiger voor integratie\n";
  print "   in andere programmas.\n";
  tussenRegel;
  print "-h\n";
  print "     Toont de help\n";
  print "     \@alias: help\n";
  print "-p\n";
  print "     Drukt al de records in de databse af.\n";
  print "-p <nr> [<nr> [<nr> [..]]]";
  print "     Drukt records met nummers <nr> af (in de gegeven volgorde).\n";
  print "-b [<nr>]\n";
  print "     Start de browser met het gegeven record centraal.\n";
  print "     \@alias: browse\n";
  print "     \@alias: browser\n";
  print "-a <naam>::<straat> <nr>::<stad>::<land>\n";
  print "     Voegt een nieuw record in met de gegeven data als waarden.\n";
  print "     eg: -a Steward\\ John::London\\ Avenue\\ 6::3748\\ Paris::France\n";
  print "     \@alias: add \n";
  print "     \@alias: voeg toe\n";
  print "     \@alias: voegtoe\n";
  print "-u <nr> [naam <nieuwe_naam> ][straat <nieuwe_straat> ][nr <nieuwe_nr> ]\n";
  print "     [stad <nieuwe_stad> ][land <nieuw_land>]\n";
  print "     Vervangt in <nr> de opgegeven data, door de nieuwe gegevens.\n";
  print "     De volgorde van de ingegeven gevens maakt niet uit.\n";
  print "     \@alias: update <nr> [naam ... \n";
  print "     \@alias: wijzig <nr> [naam ... \n";
  print "-s <nr> <naam>::<straat> <nr>::<stad>::<land>\n";
  print "     Vervangt het record in <nr> met het record omschreven door de\n";
  print "     ingegeven data (die na <nr> staat)\n";
  print "     \@alias: subs\n";
  print "     \@alias: substute\n";
  print "     \@alias: verv\n";
  print "     \@alias: vervang\n";
  print "-d <nr> \n";
  print "     Haalt een gebruiker uit de database.\n";
  print "     \@alias: del\n";
  print "     \@alias: delete\n";
  print "     \@alias: verwijder\n";
  print "-r <nrA> <nrB> \n";
  print "     Berekent de weg tussen adres <nrA> en adres <nrB>\n";
  print "     en drukt hier een leesbare beschrijving van af\n";
  print "     \@alias: -w\n";
  print "     \@alias: route \n";
  print "     \@alias: weg\n";
  tussenRegel;
}

#- De door de gebruiker ingevoerde data wordt hier een eerste maal
#-- geparsed zodat hij naar de juiste functies doorgezonden
#-- kan worden.
if(!exists($ARGV[0]))
{ interactieveModus; }
elsif($ARGV[0] eq '-h' || $ARGV[0] eq 'help')
{ cliHelp; }
else
{ cliModus @ARGV; }