program hashfkt;

uses Crt,Strings;

TYPE Hashelement = RECORD
     ISBN        :STRING[10];
     Titel       :STRING[40];
     Autor       :STRING[20];
     Feldtyp     :(besetzt,frei,wiederfrei);
     End;

     Listptr    =^Listelement;

     Listelement =RECORD
     ISBN        :string[10];
     Titel       :string[40];
     Autor       :string[20];
     command     :char;
     next        :Listptr;
     End;

     Hash = object
            HT: array [1..512] of Hashelement;
            Max,Koll,Daten, Gel: Integer;
            HType,Funkt        :char;
            constructor init;
            procedure corHType;
            procedure Insert (ISBN :string;Titel:string;Autor:string);
            procedure Search (ISBN :string);
            procedure Delete (ISBN :string);
            procedure Out;
            function strmodint (str :string;zahl:longint):longint;
            function strtoint(str:string):integer;
            function strtolong(str:string): longint;
            function h1(ISBN:string): integer;
            function h2(str:string): integer;
            function h3(str:string):integer;
            function k(str:string):integer;
            end;

     List = object
           Root:   Listptr;
           constructor     init;
           destructor      clear;
           procedure       insert(ISBN:string;Titel:string;Autor:string;command:char);
           end;

     Datei = object
                  command       :Char;
                  ISBN          :String[10];
                  Titel         :string[40];
                  Autor         :string[20];
                  F             :Text;

                  constructor init;
                  destructor done;
                  function openLog(Filename: string):Boolean;
                  function readcommand: Boolean;
                  function readISBN: Boolean;
                  function readTitel: Boolean;
                  function readAutor: Boolean;
                  function readLog:integer;
             end;

constructor Datei.init;
begin
     command:=' ';
     ISBN:='          ';
     Titel:='                                        ';
     Autor:='                  ';
end;

destructor Datei.done;
begin
  close(F);
end;

function Datei.openLog(Filename:string):Boolean;
begin
  Assign(F, Filename);
  Reset(F);
  openLog := (IOResult = 0) and (Filename <> '');
end;

function Datei.readcommand:Boolean;
begin
  Read(F,command);
  if ((command='#') or
     (command=#10#13) or
     (command='s') or
     (command='e') or
     (command='l')) then readcommand:=False
  else readcommand:=True;
end;

function Datei.ReadISBN:Boolean;
Var i:integer;
    c:char;
    Error:Boolean;
Begin
 i:=1;
 Error:=False;
 if (command='e')  then
 begin
   Read(F,c);
   if(c<>'/') then Error:=True;
   Read(F,c);
   while not((c='/') or (i>10)) do
        Begin
             ISBN[i]:=c;
             Read(F,c);
             inc(i);
        End;
   if(i>11) then Error:=True;
 end
 else
  begin
   Read(F,c);
   if(c<>'/') then Error:=True;
   readln(F,ISBN);
  end;
ReadISBN:=Error;
End;

function Datei.ReadTitel:Boolean;
Var i:integer;
    c:char;
    Error:Boolean;
Begin
 i:=1;
 Titel:='                                        ';
 Error:=False;
 Read(F,c);
 while not((c='/') or (i>40)) do
       Begin
            Titel[i]:=c;
            Read(F,c);
            inc(i);
       End;
 if(i>41) then Error:=True
 else
   Titel[i]:=#0;
 ReadTitel:=Error;
End;

function Datei.ReadAutor:Boolean;
Var i:integer;
    c:char;
    Error:Boolean;
Begin
 i:=1;
 Error:=False;
 Readln(F,Autor);
 ReadAutor:=Error;
End;

function Datei.readLog:integer;
var Komm:String;
    Ret:integer;
begin
   Ret:=0;
   if Not(readcommand) then
   case command of
   '#': Begin
          Readln(F,Komm);
        end;
   'e': Begin
          if not(readISBN) then
          begin
            if not(readTitel) then
            begin
              if not(readAutor) then
              begin
                write('Einfgen: ',ISBN,'  ',Titel);
                gotoxy(55,wherey);
                writeln('  ',Autor);
                Ret:=1;
              end
            else Ret:=-1
            end else Ret:=-1
          end else Ret:=-1;
        End;
   'l': Begin
        if not(readISBN) then
        begin
         writeln('L”sche ISBN: ',ISBN);
         Ret:=2
        end
         else ret:=-1;
         {readln(F);}
        End;
   's': Begin
        if not(readISBN) then
         Begin
          writeln  ('Suche ISBN: ',ISBN);
          ret:=3
         End
          else ret:=-1;
         { readln(F); }
        End;
   End
   else Readln(F,Komm);
   readLog:=Ret;
end;

constructor List.init;
begin
  root:=Nil;
end;

destructor List.clear;
begin
end;

procedure List.insert(ISBN:string;Titel:string;Autor:string;command:char);
Var
   Hptr,Hptr2 :Listptr;
begin
     Hptr:=Root;
     while Hptr^.next<>Nil do Hptr:=Hptr^.next;
     New(Hptr2);
    Hptr2^.ISBN:=ISBN;
     Hptr2^.Titel:=Titel;
     Hptr2^.Autor:=Autor;
     Hptr2^.command:=command;
     Hptr2^.next:=Nil;
     if Root=Nil then Root:=Hptr2
     else Hptr^.next:=Hptr2;
end;

constructor Hash.init;
var         i:integer;
begin
     HType:='L';
     Max:=25;
     Daten:=0;
     Gel:=0;
     for i:=1 to 512 do
      begin
       HT[i].Feldtyp:=frei;
       HT[i].Titel:='                                      ';
       HT[i].Autor:='                ';
       HT[i].ISBN:='         ';
      end;
end;

procedure Hash.corHType;
begin
  if HType<>'D' then HType:='L';
end;

function Hash.h1(ISBN :string):integer;
begin
  h1:=strmodint(ISBN,Max)+1;
end;

function Hash.k(str:string):integer;
begin
     k:=Koll -(strmodint(str,Koll));
end;

function Hash.h2(str:string):integer;
var ZW :longint;
    i:integer;
    strz:string;
begin
   strz:='000000';
   for i:=1 to 6 do
    begin
      strz[i]:=str[11-i];
    end;
   ZW:=strtolong(strz);
   ZW:=(ZW*Max) div 1000000;
   h2:=ZW+1;
end;

function Hash.h3(str:string):integer;
var i,e,X:integer;
    strz:string;
begin
     strz:='0000000000';
     X:=strmodint(str,10)+1;
     for i:=2 to 10 do
     begin
       for e:=10 downto i do strz[11-e]:=str[11-e];
       strz[12-e]:=#0;
       X:=X*(strmodint(strz,10)+1) mod Max;
     end;
     h3:=X+1;
end;

procedure Hash.Insert(ISBN:string;Titel:string;Autor:string);
var
   index,j,i        :integer;
begin
     i:=1;
     if (HType='L') then j:=1
     else
       j:=k(ISBN);
     if (Funkt='2') then index:=h2(ISBN)
     else
      if (Funkt='3') then index:=h3(ISBN)
       else index:=h1(ISBN);
     writeln('Index: ',index);
     writeln('k:',j);
     while(HT[index].Feldtyp=besetzt) DO
     begin
       index:=(index+j) MOD Max;
       inc(i);
     end;
     HT[index].Feldtyp:=besetzt;
     HT[index].ISBN:=ISBN;
     HT[index].Titel:=Titel;
     HT[index].Autor:=Autor;
     writeln ('ISBN: ',ISBN,' nach ',i,'. Suchschritt eingefgt.');
     readln;
     inc(Daten);
end;

procedure Hash.Search(ISBN:string);
var
   index,j,i        :integer;
begin
     i:=1;
     if (HType='L') then j:=1
     else
       j:=k(ISBN);
     if (Funkt='2') then index:=h2(ISBN)
     else
      if (Funkt='3') then index:=h3(ISBN)
       else index:=h1(ISBN);
       writeln('Index: ',index);
       writeln('k: ',j);

     while ((HT[index].Feldtyp=besetzt) and (HT[index].ISBN<>ISBN)) DO
     begin
      index:=(index+j) MOD Max;
      inc(i);
     end;
     if HT[index].ISBN=ISBN then
        begin
         writeln('ISBN: ',ISBN,' nach',i,'. Suchschritt gefunden.');
         writeln('Autor: ',HT[index].Autor);
         writeln('Titel: ',HT[index].Titel);
         readln;
        end
       else
        begin
         writeln('ISBN: ',ISBN,' nicht gefunden');
         readln;
        end;
end;

procedure Hash.Delete(ISBN:string);
Var
   index,j,i     :integer;
begin
     i:=1;
     if (HType='L') then j:=1
     else
       j:=k(ISBN);
     if (Funkt='2') then index:=h2(ISBN)
     else
      if (Funkt='3') then index:=h3(ISBN)
       else index:=h1(ISBN);
       writeln('Index: ',index);
       writeln('k: ',j);

     while ((HT[index].Feldtyp=besetzt) and (HT[index].ISBN<>ISBN)) DO
     begin
      index:=(index+j) MOD Max;
      inc(i);
     end;
     if HT[index].ISBN=ISBN then
        begin
          HT[index].Feldtyp:=wiederfrei;
          HT[index].ISBN:='          ';
          HT[index].Titel:='                                        ';
          HT[index].Autor:='                     ';
          writeln('ISBN:',ISBN,' wurde nach ',i,'. Suchschritt gel”scht');
          readln;
          inc(Gel);
        end
       else
        begin
          writeln('ISBN: ',ISBN,' nicht gefunden.');
          readln;
        end;

end;

procedure Hash.Out;
var      i:integer;
begin
 clrscr;
 writeln (Daten,' eingegebene Datens„tze');
 writeln (Gel,' gel”schte Datens„tze');
 writeln;
 for i:=1 to Max do writeln('index:',i,' ISBN: ',HT[i].ISBN);
 readln;
end;

function Hash.strtoint(str:string):integer;
var
   len,i,zahl:integer;
begin
    len:=1;
    while ((str[len]>='0')and (str[len]<='9')) do len:=len+1;
    len:=len-1;
    zahl:=0;
    for i:=1 to len-1 do zahl:=(zahl+(ord(str[i])-ord('0')))*10;
    zahl:=zahl+(ord(str[len])-ord('0'));
    strtoint:=zahl;
end;

function Hash.strtolong(str:string):longint;
var
   len,i:integer;
   zahl:longint;
begin
    len:=1;
    while ((str[len]>='0')and (str[len]<='9')) do len:=len+1;
    len:=len-1;
    zahl:=0;
    for i:=1 to len-1 do zahl:=(zahl+(ord(str[i])-ord('0')))*10;
    zahl:=zahl+(ord(str[len])-ord('0'));
    strtolong:=zahl;
end;
function Hash.strmodint (str:string;zahl:longint):longint;
var
   zz,zw1,i,e,l   :integer;
   Code :integer;
   strz :string;
begin
  strz:='0000';
  e:=1;
  for i:=1 to 4 do strz[i]:=str[i];
  strz[5]:=#0;
  e:=i;
  while (e<=10) do
  begin
   zz:=strtoint(strz);
   zw1:=zz mod zahl;
   if (zw1>9) then
    begin
     if (zw1>99) then
      begin
       strz[1]:=chr(ord('0')+zw1 div 100);
       strz[2]:=chr(ord('0')+(zw1-(ord(strz[1])-ord('0')) * 100) div 10);
       strz[3]:=chr(ord('0')+zw1 mod 10);
       l:=4;
      end
     else
     begin
       strz[1]:=chr(ord('0')+zw1 div 10);
       strz[2]:=chr(ord('0')+zw1 mod 10);
       l:=3;
     end;
    end
   else
     begin
     strz[1]:=chr(ord('0')+zw1);
     l:=2;
     end;
   for i:=l to 4 do
     begin
     e:=e+1;
     if (e<=10) then strz[i]:=str[e]
      else
       begin
        strz[i]:=#0;
        i:=4
       end; ;
     end;
   end;
   zz:=strtoint(strz);
   zw1:=zz mod zahl;
  strmodint:=zw1;
end;


Var
   Log          :Datei;
   BHash        :Hash;
   Buffer       :List;
   Ret          :Integer;
   c            :char;
   ISBN         :string[10];
   Autor        :string[20];
   Titel        :string[40];
   Lptr         :Listptr;
begin
 Ret:=0;
 BHash.init;
 Log.init;
 Buffer.Init;
 clrscr;
 write('[L]inear Probing od. [D]oppeltes Hashing:<Default=Linear Probing>');
 readln(BHash.HType);
 BHash.corHType;
 write('Hashtabellengr”áe[1..512]:<Default=25>');
 readln(BHash.Max);
 write('Hashfunktion[1..3]:<Default=1>');
 readln(BHash.Funkt);
 if (BHash.HType='D') then
  begin
    write('Kollisionsparameter:<',BHash.Max);
    readln(BHash.Koll);
    if (BHash.Koll>=BHash.Max) then
    begin
      Writeln('Zu groáer Parameter');
      readln;
      exit;
    end;
  end;
 Log.init;
 if Log.openLog('test.dat')=True then
 begin
  while (not(Eof(Log.F)) and (Ret>-1)) do
   Begin
       Ret:=Log.ReadLog;
       case Ret of
       -1: Begin
           writeln('Fehler in Datei');
           readln;
           end;
       1: Begin   {Einfgen}
           BHash.Insert(Log.ISBN,Log.Titel,Log.Autor);
          End;
       2: Begin   {L”schen}
           BHash.Delete(Log.ISBN);
          End;
       3: Begin   {Suchen}
           BHash.Search(Log.ISBN);
          End;
       End;
   end;
 end;
 Log.Done;
 clrscr;
 c:=' ';
 while (c<>'q') do
 begin
 write ('command:');
 readln (c);
 if c='q' then break;
  write ('ISBN:');
  readln(ISBN);
  if c='e' then
   begin
    write('Titel:');
    readln(Titel);
    write('Autor:');
    readln(Autor);
  end;
    case c of
    'e': Begin   {Einfgen}
           writeln('Einfgen: ',ISBN,'  ',Titel,'  ',Autor);
           BHash.Insert(ISBN,Titel,Autor);
         End;
    'l': Begin   {L”schen}
           BHash.Delete(ISBN);
         End;
    's': Begin   {Suchen}
           BHash.Search(ISBN);
         End;
    'a': Begin
         BHash.Out;
         End;
    End;
   Buffer.insert(ISBN,Titel,Autor,c);
 end;
 Log.init;
 Ret:=0;
 BHash.init;
 clrscr;
 write('[L]inear Probing od. [D]oppeltes Hashing:<Default=Linear Probing>');
 readln(BHash.HType);
 BHash.corHType;
 write('Hashtabellengr”áe[1..512]:<Default=25>');
 readln(BHash.Max);
 write('Hashfunktion[1..3]:<Default=1>');
 readln(BHash.Funkt);
 Log.init;
 if Log.openLog('test.dat')=True then
 begin
  while (not(Eof(Log.F)) and (Ret>-1)) do
   Begin
       Ret:=Log.ReadLog;
       case Ret of
       -1: Begin
           writeln('Fehler in Datei');
           readln;
           end;
       1: Begin   {Einfgen}
           BHash.Insert(Log.ISBN,Log.Titel,Log.Autor);
          End;
       2: Begin   {L”schen}
           BHash.Delete(Log.ISBN);
          End;
       3: Begin   {Suchen}
           BHash.Search(Log.ISBN);
          End;
       End;
   end;
 end;
 Lptr:=Buffer.root;
 while Lptr<>Nil do
 begin
  case Lptr^.command of
  'e': Begin
       writeln('Einfgen: ',Lptr^.ISBN,'  ',Lptr^.Titel,'  ',Lptr^.Autor);
       BHash.Insert(Lptr^.ISBN,Lptr^.Titel,Lptr^.Autor);
       end;
  's': Begin
       BHash.Search(Lptr^.ISBN);
       end;
  'l': Begin
       BHash.Delete(Lptr^.ISBN);
       end;
  'a': Begin
       BHash.Out;
       end;
  end;
  Lptr:=Lptr^.next;
 end;
end.