{ File: albersol.pas }

{ Scopo: esercizio di esame }

program Albergo;
{ Esercizio di esame di Fondamenti di Informatica del 15/2/1999.
  Soluzione completa. }

const
  LungCodice = 5;
  LungNome   = 10;

type
  TipoCamera = (singola,doppia);
  TipoCodice = packed array [1..LungCodice] of char;
  TipoNome   = packed array [1..LungNome] of char;
  TipoData   = record
                 giorno : 1..31;
                 mese   : 1..12;
                 anno   : 0..MAXINT
               end;     

  TipoPrenotazione = record
                       codice        : TipoCodice;
                       cognome, nome : TipoNome;
                       camera        : TipoCamera;
                       tariffa       : 0..MAXINT;
                       data_arrivo,
                       data_partenza : TipoData
                     end;

  TipoFilePrenotazioni = file of TipoPrenotazione;

  TipoListaPresenze  = ^TipoRecordPresenza;
  TipoRecordPresenza = record
                         prenotazione : TipoPrenotazione;
                         next         : TipoListaPresenze
                       end;           

  TipoSoggiorno = record
                    cognome, nome    : TipoNome;
                    numero_soggiorni : 0..MAXINT
                  end;
  TipoListaSoggiorni  = ^TipoRecordSoggiorno;
  TipoRecordSoggiorno = record
                          soggiorno : TipoSoggiorno;
                          next      : TipoListaSoggiorni
                        end;

  TipoNomeFile = string;

{ Procedura che risolve il punto 2. }

  procedure StampaDatiClientiNonArrivati (nome_file_pren : TipoNomeFile;
                                          data           : TipoData;
                                          presenze       : TipoListaPresenze);
  { Stampa su schermo i dati relativi ai clienti prenotati per data ma non
    presenti in albergo (cioe` nella lista presenze). }
  var
    f    : TipoFilePrenotazioni;
    pren : TipoPrenotazione;

    function EsisteInLista (lista : TipoListaPresenze;
                            cod   : TipoCodice): boolean;
    { Verifice se la prenotazione di codice cod e` presente in lista. }
    begin
      if lista = NIL then
        EsisteInLista := FALSE
      else if lista^.prenotazione.codice = cod then
        EsisteInLista := TRUE
      else
        EsisteInLista := EsisteInLista(lista^.next, cod)
    end; { EsisteInLista }

    procedure StampaDatiPrenotazione (prenotazione: TipoPrenotazione);
    { Stampa su schermo tutti i dati relativi ad una prenotazione. }
    begin
      with prenotazione do
      begin
        write(codice, '  ', cognome, ' ', nome, ' ');
        if camera = singola then
          write('singola ')
        else
          write('doppia  ');
        write(tariffa:7, ' ');
        with data_arrivo do
          write(giorno:2, '/', mese:2, '/', anno:4, '  ');
        with data_partenza do
          writeln(giorno:2, '/', mese:2, '/', anno:4)
      end
    end; { StampaDatiPrenotazione }

  begin { StampaDatiClientiNonArrivati }
    assign(f, nome_file_pren);
    reset(f);
    writeln('Dati sui clienti prenotati ma non presenti in albergo:');
    writeln('Codice Cognome    Nome       Camera  Tariffa Data arrivo Data partenza');
    writeln('----------------------------------------------------------------------');
    while not eof(f) do
    begin
      read(f, pren);
      if (pren.data_arrivo.giorno = data.giorno) and
         (pren.data_arrivo.mese = data.mese) and
         (pren.data_arrivo.anno = data.anno) then
        if not EsisteInLista(presenze, pren.codice) then
          StampaDatiPrenotazione(pren)
    end;
    close(f)
  end; { StampaDatiClientiNonArrivati }


{ Procedura che risolve il punto 3. }

  procedure CercaClientiAbituali(nome_file_arch : TipoNomeFile;
                                 presenze       : TipoListaPresenze;
                                 var soggiorni  : TipoListaSoggiorni);
  { Restituisce in soggiorni la lista dei clienti attualmente presenti in
    albergo che hanno soggiornato in albergo per tre o piu` volte (incluso
    il soggiorno attuale). }
  var
    saux          : TipoListaSoggiorni;
    num_soggiorni : integer;

    function ContaSoggiorniCliente (nome_file     : TipoNomeFile;
                                    cognome, nome : TipoNome): integer;
    { Calcola quante volte il cliente specificato dal suo cognome e nome ha
      soggiornato in precedenza nell'albergo. }
    var
      f            : TipoFilePrenotazioni;
      conta        : integer;
      prenotazione : TipoPrenotazione;

    begin { ContaSoggiorniCliente }
      assign(f, nome_file);
      reset(f);
      conta := 0;
      while not eof(f) do
      begin
        read(f, prenotazione);
        if (prenotazione.cognome = cognome) and (prenotazione.nome = nome) then
          conta := conta + 1
      end;
      ContaSoggiorniCliente := conta
    end; { ContaSoggiorniCliente }

  begin { CercaClientiAbituali }
    soggiorni := NIL;
    while presenze <> NIL do
    begin
      num_soggiorni := 1 + ContaSoggiorniCliente(nome_file_arch,
                                                 presenze^.prenotazione.cognome,
                                                 presenze^.prenotazione.nome);
      if num_soggiorni >= 3 then
      begin
        new(saux);
        with saux^.soggiorno do
        begin
          cognome := presenze^.prenotazione.cognome;
          nome := presenze^.prenotazione.nome;
          numero_soggiorni := num_soggiorni
        end;
        saux^.next := soggiorni;
        soggiorni := saux
      end;
      presenze := presenze^.next
    end
  end; { CercaClientiAbituali }


{ procedure ausiliarie usate dal programma driver }

  procedure LeggiPresenze (nome_file: TipoNomeFile;
                           var presenze: TipoListaPresenze);
  { Legge dal file di TESTO nome_file i dati relative alle prenotazioni e
    ne costruisce in memoria una lista che restituisce in presenze. }
  var
    f    : text;
    paux : TipoListaPresenze;
    i    : integer;
    ch   : char;
  begin
    assign(f, nome_file);
    reset(f);
    presenze := NIL;
    while not eof(f) do
    begin                         { legge un elemento e lo inserisce in testa }
      new(paux);
      with paux^.prenotazione do
      begin
        for i := 1 to LungCodice do read(f,codice[i]); readln(f);
        for i := 1 to LungNome do read(f,cognome[i]); readln(f);
        for i := 1 to LungNome do read(f,nome[i]); readln(f);
        readln(f,ch);
        if ch = 'S' then
          camera := singola
        else
          camera := doppia;
        readln(f,tariffa);
        with data_arrivo do
          readln(f,giorno, mese, anno);
        with data_partenza do
          readln(f,giorno, mese, anno);
        readln(f)
      end;
      paux^.next := presenze;
      presenze := paux
    end;
    close(f)
  end; { LeggiPresenze }


  procedure ScriviPresenze (nome_file: TipoNomeFile;
                            presenze: TipoListaPresenze);
  { Scrive sul file di RECORD nome_file i dati relative alle prenotazioni
    contenute nella lista presenze. }
  var
    f : TipoFilePrenotazioni;
  begin
    assign(f, nome_file);
    rewrite(f);
    while presenze <> NIL do
    begin
      write(f,presenze^.prenotazione);
      presenze := presenze^.next
    end;
    close(f)
  end; { ScriviPresenze }


  procedure CancellaLista (var l: TipoListaPresenze);
  var
    paux : TipoListaPresenze;
  begin
    while l <> NIL do
    begin
      paux := l;
      l := l^.next;
      dispose(paux)
    end
  end; { CancellaLista }


  procedure StampaSoggiorni (soggiorni: TipoListaSoggiorni);
  begin
    writeln('Cognome   Nome      Soggiorni');
    writeln('-----------------------------');
    while soggiorni <> NIL do
    begin
      with soggiorni^.soggiorno do
        writeln(cognome, nome, numero_soggiorni);
      soggiorni := soggiorni^.next
    end
  end; { StampaSoggiorni }


{ variabili usate nel programma principale }
var
  nome_file_presenze : TipoNomeFile;
  file_prenotazioni  : TipoFilePrenotazioni;
  file_archivio      : TipoFilePrenotazioni;
  data_odierna       : TipoData;
  lista_presenze     : TipoListaPresenze;
  lista_soggiorni    : TipoListaSoggiorni;

begin { Albergo }
  { genera il file di record PRENOT.DAT a partire dal file di testo
    PRENOT.TXT }
  LeggiPresenze('PRENOT.TXT', lista_presenze);
  ScriviPresenze('PRENOT.DAT', lista_presenze);
  CancellaLista(lista_presenze);

  { genera il file di record ARCHIVIO.DAT a partire dal file di testo
    ARCHIVIO.TXT }
  LeggiPresenze('ARCHIVIO.TXT', lista_presenze);
  ScriviPresenze('ARCHIVIO.DAT', lista_presenze);
  CancellaLista(lista_presenze);

  writeln('Immettere il nome del file di testo contenente le presenze! ');
  readln(nome_file_presenze);
  LeggiPresenze(nome_file_presenze, lista_presenze);
  writeln('Immettere la data odierna (gg mm aaaa)!');
  with data_odierna do
   readln(giorno, mese, anno);
  writeln;

  { Attivazione della procedura che risolve il punto 2, a cui vengono passati
    i seguenti parametri attuali:
      - la stringa 'PRENOT.DAT' che rappresenta il nome del file delle
        prenotazioni,
      - la variabile data_odierna, che rappresenta la data odierna,
      - la variabile lista_presenze, che rappresenta la lista delle presenze.
  }

  StampaDatiClientiNonArrivati('PRENOT.DAT', data_odierna, lista_presenze);

  { Attivazione della procedura che risolve il punto 3, a cui vengono passati
    i seguenti parametri attuali:
      - la stringa 'ARCHIVIO.DAT' che rappresenta il nome del file archivio,
      - la variabile lista_presenze, che rappresenta la lista delle presenze,
    e che restituisce
      - nella variabile lista_soggiorni la lista in uscita.
  }

  CercaClientiAbituali('ARCHIVIO.DAT', lista_presenze, lista_soggiorni);

  writeln;
  writeln('Clienti abituali');
  StampaSoggiorni(lista_soggiorni)

end. { Albergo }