// part of uber 3
constructor TBaseEntity.Init;
begin
end;

destructor TBaseEntity.Done;
begin
end;

procedure TBaseEntity.Render;
begin
  OnRender;
  RenderSubObjects;
end;

procedure TBaseEntity.RenderSubObjects;
begin
end;

procedure TBaseEntity.OnSpawn;
begin
end;

procedure TBaseEntity.OnDie;
begin
end;

procedure TBaseEntity.OnUpdate;
begin
end;

procedure TBaseEntity.OnRender;
begin
end;

constructor TEntity.Init;
begin
  FParent := nil;
  FNext := nil;
  FPrev := nil;
  FSubFirst := nil;
  FSubLast := nil;
end;

destructor TEntity.Done;
var
  It: PEntity;
begin
  It := FSubFirst;
  while It <> nil do begin
    It^.Done;
    It := It^.Next;
  end;
end;

procedure TEntity.Update;
var
  It: PEntity;
begin
  OnUpdate;
  It := FSubFirst;
  while It <> nil do begin
    It^.Update;
    It := It^.FNext;
  end;
end;

procedure TEntity.Kill;
begin
  // TODO REMOVE
  OnDie;
end;

procedure TEntity.SetParent(NewParent: PEntity);
begin
  if FNext <> nil then
    FNext^.FPrev := FPrev;
  if FPrev <> nil then
    FPrev^.FNext := FNext;
  if FParent <> nil then begin
    if FParent^.FSubFirst = @Self then
      FParent^.FSubFirst := FNext;
    if FParent^.FSubLast = @Self then
      FParent^.FSubLast := FPrev;
    FParent := nil;
  end;
  if NewParent = nil then begin
    FPrev := nil;
    FNext := nil;
    Exit;
  end;
  FParent := NewParent;
  FNext := nil;
  FPrev := FParent^.FSubLast;
  if FPrev <> nil then
    FPrev^.FNext := @Self;
  FParent^.FSubLast := @Self;
  if FParent^.FSubFirst = nil then
    FParent^.FSubFirst := @Self;
end;

procedure TEntity.AddSub(Entity: PEntity);
begin
  Entity^.SetParent(@Self);
end;

procedure TEntity.BringToTop;
begin
  if FParent = nil then
    Exit;
  if FParent.FSubLast = @Self then
    Exit;
  if FParent.FSubFirst = @Self then
    FParent.FSubFirst := FNext;
  if FNext <> nil then
    FNext^.FPrev := FPrev;
  if FPrev <> nil then
    FPrev^.FNext := FNext;
  FPrev := FParent.FSubLast;
  if FPrev <> nil then
    FPrev.FNext := @Self;
  FParent.FSubLast := @Self;
  FNext := nil;
end;

procedure TEntity.SendToBack;
begin
  if FParent = nil then
    Exit;
  if FParent^.FSubFirst = @Self then
    Exit;
  if FParent^.FSubLast = @Self then
    FParent^.FSubLast := FPrev;
  if FPrev <> nil then
    FPrev^.FNext := FNext;
  if FNext <> nil then
    FNext^.FPrev := FPrev;
  FNext := FParent^.FSubFirst;
  if FNext <> nil then
    FNext^.FPrev := @Self;
  FParent^.FSubFirst := @Self;
  FPrev := nil;
end;

//procedure TEntity.MoveBefore(Entity: PEntity);
//begin
//end;

//procedure TEntity.MoveAfter(Entity: PEntity);
//begin
//end;

procedure TEntity.RenderSubObjects;
var
  It: PEntity;
begin
  It := FSubFirst;
  while It <> nil do begin
    It^.Render;
    It := It^.FNext;
  end;
end;

procedure TEntity.ForEach(Action: TForEachProc);
var
  It: PEntity;
begin
  Action(@Self);
  It := FSubFirst;
  while It <> nil do begin
    It^.ForEach(Action);
    It := It^.FNext;
  end;
end;

procedure TEntity.ForEach(Action: TForEachProcObj);
var
  It: PEntity;
begin
  Action(@Self);
  It := FSubFirst;
  while It <> nil do begin
    It^.ForEach(Action);
    It := It^.FNext;
  end;
end;

function TEntity.ForEach(Action: TForEachFunc): Boolean;
var
  It: PEntity;
begin
  if Action(@Self) then
    Exit(True);
  It := FSubFirst;
  while It <> nil do begin
    if It^.ForEach(Action) then
      Exit(True);
    It := It^.FNext;
  end;
  Exit(False);
end;

function TEntity.ForEach(Action: TForEachFuncObj): Boolean;
var
  It: PEntity;
begin
  if Action(@Self) then
    Exit(True);
  It := FSubFirst;
  while It <> nil do begin
    if It^.ForEach(Action) then
      Exit(True);
    It := It^.FNext;
  end;
  Exit(False);
end;

procedure TEntity.ForEachInverted(Action: TForEachProc); overload;
var
  It: PEntity;
begin
  Action(@Self);
  It := FSubLast;
  while It <> nil do begin
    It^.ForEachInverted(Action);
    It := It^.FPrev;
  end;
end;

procedure TEntity.ForEachInverted(Action: TForEachProcObj); overload;
var
  It: PEntity;
begin
  Action(@Self);
  It := FSubLast;
  while It <> nil do begin
    It^.ForEachInverted(Action);
    It := It^.FPrev;
  end;
end;

function TEntity.ForEachInverted(Action: TForEachFunc): Boolean; overload;
var
  It: PEntity;
begin
  It := FSubLast;
  while It <> nil do begin
    if It^.ForEachInverted(Action) then
      Exit(True);
    It := It^.FPrev;
  end;
  Exit(Action(@Self));
end;

function TEntity.ForEachInverted(Action: TForEachFuncObj): Boolean; overload;
var
  It: PEntity;
begin
  It := FSubLast;
  while It <> nil do begin
    if It^.ForEachInverted(Action) then
      Exit(True);
    It := It^.FPrev;
  end;
  Exit(Action(@Self));
end;
