program tehtava9456(input, output);
  const kpl = 500;
  type nimity = packed array [1..15] of char;
       osoite = packed array [1..20] of char;
       pvm = record
               pv : 1..31;
               kk : 1..12;
               vv : 1990..2050
             end;
      tilaaja = record
                  etunimi, sukunimi : nimity;
                  katu, postipaikka : osoite;
                  alkupvm, loppupvm : pvm;
                  maksettu : boolean
               end;
  var Tilaajat : array [1..kpl] of tilaaja;
      ViimKayt : 0..kpl;

{   Taulukon alkuosa on käytössä. Muuttujan ViimKayt arvona on viimeisen 
    käytössä olevan tietueen indeksi. Pvm-tyyppiset kentät on varattu 
    tilauksen alkamis- ja päättymispäivämäärälle. Tilaajatietueet säily-
    tetään nimien mukaisessa (Pascal-toteutuksen antamassa!) aakkos-
    järjestyksessä. Taulukkoa ja viimeisen käytössä olevan tietueen 
    indeksiä voit käyttää globaaleina muuttujina (välittämättä niitä 
    proseduureille parametreina). Proseduurit ovat tässä tehtävässä työ-
    kaluja, joilla tutkitaan ja muutellaan koko ohjelmassa merkityksel-
    listä tietorakenteen sisältöä.}

{   a) Tee proseduuri Hae, joka selvittää, onko annetun niminen henkilö
       tilaajien joukossa. Proseduuri saa etu- ja sukunimen parametrina 
       ja palauttaa kolmannella parametrilla tiedon, onko haettu henkilö 
       tilaaja: kolmas parametri on haetun henkilön tietueen indeksi, 
       jos henkilö löytyi. Jos ei löytynyt, parametri palauttaa negatii-
       visen arvon.}

procedure Hae(etu, suku: nimity; var indeksi: integer);
  var vasen, oikea, keski: integer; {BINÄÄRIHAKU!!}
begin
  if ViimKayt = 0 then
    indeksi := -1
  else
    begin
      vasen := 1; oikea := ViimKayt;
      repeat 

        keski := (vasen + oikea) div 2;
        with Tilaajat[keski] do
          if (suku < sukunimi) or
             (suku = sukunimi) and
             (etu < etunimi) then
            oikea := keski - 1
          else
            vasen := keski + 1

       until (vasen > oikea) or
             (etu  = Tilaajat[keski].etunimi) and
             (suku = Tilaajat[keski].sukunimi);

       if (etu  = Tilaajat[keski].etunimi) and
          (suku = Tilaajat[keski].sukunimi) then
         indeksi := keski
       else
         indeksi := -1
     end;
end;


{   b) Tee proseduuri Lisaa, joka lisää parametrina saamansa tilaajatiedot
       tietorakenteeseen. Proseduuri tarkistaa a)-kohdan proseduurilla, 
       ettei lisättävä jo ole taulukossa. }

procedure Lisaa(tiedot: tilaaja);
  var ind: integer;
begin
  Hae(tiedot.etunimi, tiedot.sukunimi, ind);
  if ind > 0 then 
    writeln('Lisättävä on jo tilaaja!')
  else if ViimKayt >= kpl then
    writeln('Ei enää mahdu!')   
  else
  begin
    ind := ViimKayt;
    while (ind >= 1) and 
          ( (tiedot.sukunimi < Tilaajat[ind].sukunimi) or
            (tiedot.sukunimi = Tilaajat[ind].sukunimi) and
            (tiedot.etunimi < Tilaajat[ind].etunimi) ) do
       begin
         Tilaajat[ind+1] := Tilaajat[ind];
         ind := ind - 1;
       end;
    Tilaajat[ind+1] := tiedot;
    ViimKayt := ViimKayt + 1;
  end;
end;

{   c) Tee proseduuri Poista, joka poistaa parametrina (etu- ja  sukunimi) 
       saamansa tilaajan tietorakenteesta. Käytä a)-kohdan proseduuria. 
       Muista tiivistää taulukko poiston jälkeen. }

procedure Tiivista(indeksi: integer); {pikku apulainen}
  var i: integer;
begin
  ViimKayt := ViimKayt - 1;
  for i := indeksi to ViimKayt do
    Tilaajat[i] := Tilaajat[i+1]
end;

procedure Poista(etu, suku: nimity);
  var ind: integer;
begin
  Hae(etu, suku, ind);
  if ind < 0 then
    writeln('Ei puuttuvaa voi poistaa!')
  else
    Tiivista(ind)
end;

{   d) Tee proseduuri AjanTasalle, joka saa parametrina päiväyksen ja 
       poistaa tietorakenteesta vanhentuneet  (parametria vanhemmat) 
       ja maksamattomat tilaukset. }

procedure Ajantasalle(paivays: pvm);
  var ind: integer;
begin 
  ind := 1;
  while ind <= ViimKayt do 
    with Tilaajat[ind] do
      if not maksettu or
          (loppupvm.vv < paivays.vv) or
          ((loppupvm.vv = paivays.vv) and
              (loppupvm.kk < paivays.kk)) or
          ((loppupvm.vv = paivays.vv) and
              (loppupvm.kk = paivays.kk) and
              (loppupvm.pv < paivays.pv)) then
        Tiivista(ind)
      else
        ind := ind + 1
end;


{   e) Tee parametriton proseduuri Osoitelaput, joka tulostaa osoite-
       lipukkeet kaikille lehden tilaajille.  }

procedure Osoitelaput;
  var ind: integer;
begin
  for ind := 1 to ViimKayt do
    with Tilaajat[ind] do
      begin
        writeln(etunimi, ' ', sukunimi);
        writeln(katu);
        writeln(postipaikka);
        writeln;
      end;
end;

begin {pääohjelman tynkä}
      {aika työlästä olisi rakentaa testiympäristö}
end.

