unit types;

interface
uses classes,sysutils,windows;
type
  //Ein Typ für eine Adjazenzmatrix. Wenn dieses Array eine Länge von n^2 hat,
  //geht eine Kante von Knoten i zu Knoten j, genau dann wenn a.mat.[i*n+j] = true.
  TAdjanzenzMatrix=array of boolean;

  //Der Record in den eine Website eingelesen wird
  PSites=^TSites;
  TSites=record
    fileNames:TStringList; //Namen der einzelnen Seite, fileNames[i] wird dabei
                           //in den Arrays nur i genannt
    InDegrees: array of integer; //Anzahl der Kanten die zu den Knoten i führen 
    links: array of array of integer; //Der gesamte Graph als Knotenliste.
                                      //links[i] enthält die Nummern aller
                                      //Knoten, die von i erreicht werden können
    linksAdjazenzMat: tAdjanzenzMatrix; //Der gesamte Graph als Adjazenzmatrix (s.o.)
    AdjazenzMatLen:integer; //Länge einer Spalte/Zeile in der Matrix
  end;

  //Speichert einen Weg der Struktur als verkettete Liste
  //(z.B. für ein Dreieck: A -> B -> C -> A)
  PSiteWay=^TSiteWay;
  TSiteWay=record
    number:integer;    //Nummer der Seite (eine Seite der Struktur, keine benannte)
    notLinked:boolean; //Gibt an, ob ein neuer Weg beginnt
    nextSite:psiteway; //Das nächste Wegstück (nil, beim Ende)
  end;
  //Die eigentliche Struktur
  TStructure        =class
  public
    siteWay: PSiteWay;  //Das erste Stück der Wege
    siteCount: integer; //Anzahl der Seiten
    InDegrees: array of integer; //Anzahl der Kanten, die zu einem Knoten führen
    OutDegrees: array of integer; //Anzahl der Kanten, die von einem Knoten weg führen
    description:string; //Bedeutung der Struktur
    linkedNodes:array of boolean; //true bei allen Knoten, bei denen ein Weg startet,
                                  //und die von einem Knoten aus einem anderen Weg
                                  //erreicht werden können. 
    constructor create(const fileName:string); //Lädt die Struktur aus der angegebenen Datei
    destructor destroy;override; //Freigabe
  end;

implementation

//Lädt die Struktur aus der angegebenen Datei
constructor tstructure.create(const fileName:string);
const SIZEOF_INT=4{sizeof(Integer)};
var fileStream:TFileStream;         //Datei
    descriptionLength,index:integer;//Länge der Beschreibung, Seitenindex
    newWay:boolean;                 //Soll als nächstes ein neuer Weg beginnen
    lastSite:PSiteWay;              //Das letzte Wegstück
    wayStarts:array of boolean;     //Enthält die Nummern aller Knoten an denen
                                    //bisher ein Weg anfing
begin
  //Datei öffnen
  fileStream:=TFileStream.create(fileName,fmOpenRead or fmShareDenyNone);
  try
    fileStream.Read(siteCount,SIZEOF_INT); //Anzahl der Seiten auslesen

    //Anzahl der von einem Knoten ausgehenden Kanten lesen
    SetLength(OutDegrees,siteCount);
    fileStream.Read(OutDegrees[0],SIZEOF_INT*siteCount);

    //Anzahl der in einen Knoten eingehenden Kanten lesen
    SetLength(InDegrees,siteCount);
    fileStream.Read(InDegrees[0],SIZEOF_INT*siteCount);

    //Beschreibung lesen
    fileStream.Read(descriptionLength,SIZEOF_INT);
    SetLength(description,descriptionLength);
    fileStream.Read(description[1],descriptionLength);

    //Weg einlesen
    setlength(wayStarts,siteCount);
    zeromemory(@wayStarts[0],siteCount*sizeof(wayStarts[0]));
    setlength(linkedNodes,siteCount);
    newWay:=true;  //Am Anfang kommt ein neuer Weg
    lastSite:=nil; //Bisher kein letztes Wegstück
    linkedNodes[0]:=true; //Der erste Knoten ist immer erreichbar
    //Lese bis zum Dateiende
    while fileStream.Position<fileStream.size do begin
      //Lese den Index des Knoten zu dem der Weg als nächstes führt
      fileStream.Read(index,SIZEOF_INT);
      if index=-1 then newWay:=true //Wenn ein neuer Weg beginnt, das speichern
      else begin                    //Ansonsten neues Wegstück erzeugen
        if lastSite=nil then begin  //Kein letztes Wegstück?
          //Erstes Wegstück erzeugen, das gleichzeitig das letzte ist
          new(siteWay);
          lastSite:=siteWay;
        end else begin
          //Neues Wegstück hinten anhängen
          new(lastSite.nextSite);
          lastSite:=lastSite.nextSite;
        end;
        lastSite.number:=index;     //Seitennummer übernehmen
        lastSite.notLinked:=newWay; //Und Wegbeginn

        if newWay then wayStarts[index]:=true //Neuer Weg? Das merken
        else if wayStarts[index]=false then //Kein neuer Weg, und am Knoten hat noch kein Weg begonnen
          linkedNodes[index]:=true; //Merken, dass er von einem Weg erreicht werden kann,
                                    //der nicht mit ihm beginnt

        newWay:=false; //Das nächste Wegstück wird keinen neuen Weg anfangen
      end;
    end;
    lastSite.nextSite:=nil; //Endmarkierung


  finally
    filestream.free; //Schließen
  end;
end;

//Freigeben
destructor tstructure.destroy;
var old:PSiteWay;
begin
  //Den gesamten Weg durchlaufen
  while siteWay<>nil do begin
    old:=siteWay; //Zeiger sichern
    siteWay:=siteWay^.nextSite; //Weitergehen
    dispose(old); //Altes löschen
  end;
  inherited;
end;
end.
