(*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * http://www.opensource.org/licenses/cddl1.php.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * http://www.opensource.org/licenses/cddl1.php.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying * information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Portions Copyright 2007 Andreas Schneider
 *)
unit UPacketHandlers;

interface

uses
  SysUtils, dzlib, UEnhancedMemoryStream;

type
  TPacketProcessor = procedure(ABuffer: TEnhancedMemoryStream);
  TPacketProcessorMethod = procedure(ABuffer: TEnhancedMemoryStream) of object;

  { TPacketHandler }

  TPacketHandler = class(TObject)
    constructor Create(ALength: Cardinal; APacketProcessor: TPacketProcessor); overload;
    constructor Create(ALength: Cardinal; APacketProcessorMethod: TPacketProcessorMethod); overload;
    procedure Process(ABuffer: TEnhancedMemoryStream);
  protected
    FLength: Cardinal;
    FPacketProcessor: TPacketProcessor;
    FPacketProcessorMethod: TPacketProcessorMethod;
  published
    property PacketLength: Cardinal read FLength;
  end;

var
  PacketHandlers: array[0..$FF] of TPacketHandler;
  
procedure RegisterPacketHandler(AID: Byte; APacketHandler: TPacketHandler);

implementation

uses
  UAdminHandling;

procedure RegisterPacketHandler(AID: Byte; APacketHandler: TPacketHandler);
begin
  FreeAndNil(PacketHandlers[AID]);
  PacketHandlers[AID] := APacketHandler;
end;

{ TPacketHandler }

constructor TPacketHandler.Create(ALength: Cardinal; APacketProcessor: TPacketProcessor);
begin
  inherited Create;
  FLength := ALength;
  FPacketProcessor := APacketProcessor;
  FPacketProcessorMethod := nil;
end;

constructor TPacketHandler.Create(ALength: Cardinal;
  APacketProcessorMethod: TPacketProcessorMethod);
begin
  inherited Create;
  FLength := ALength;
  FPacketProcessor := nil;
  FPacketProcessorMethod := APacketProcessorMethod;
end;

procedure TPacketHandler.Process(ABuffer: TEnhancedMemoryStream);
begin
  if Assigned(FPacketProcessor) then
    FPacketProcessor(ABuffer)
  else if Assigned(FPacketProcessorMethod) then
    FPacketProcessorMethod(ABuffer);
end;

procedure OnCompressedPacket(ABuffer: TEnhancedMemoryStream);
var
  uncompStream: TEnhancedMemoryStream;
  uncompBuffer: TDecompressionStream;
  targetSize: Cardinal;
  packetID: Byte;
begin
  //writeln('compressed size: ', ABuffer.Size);
  targetSize := ABuffer.ReadCardinal;
  //writeln('uncompressed size: ', targetSize);
  uncompBuffer := TDecompressionStream.Create(ABuffer);
  uncompStream := TEnhancedMemoryStream.Create;
  try
    uncompStream.CopyFrom(uncompBuffer, targetSize);
    uncompStream.Position := 0;
    packetID := uncompStream.ReadByte;
    if PacketHandlers[packetID] <> nil then
    begin
      if PacketHandlers[PacketID].PacketLength = 0 then
        uncompStream.Position := uncompStream.Position + 4;
      uncompStream.Lock(uncompStream.Position, uncompStream.Size - uncompStream.Position);
      PacketHandlers[PacketID].Process(uncompStream);
      uncompStream.Unlock;
    end else
    begin
      {Writeln('Dropping client due to unknown packet: ', ANetState.Socket.PeerAddress);
      ANetState.Socket.Disconnect;
      ANetState.ReceiveQueue.Clear;}
    end;
  finally
    if uncompBuffer <> nil then uncompBuffer.Free;
    if uncompStream <> nil then uncompStream.Free;
  end;
end;


{$WARNINGS OFF}
var
  i: Integer;

initialization
  for i := 0 to $FF do
    PacketHandlers[i] := nil;
  PacketHandlers[$01] := TPacketHandler.Create(0, @OnCompressedPacket);
  //$02 --> ConnectionHandling, done by TdmNetwork
  PacketHandlers[$03] := TPacketHandler.Create(0, @OnAdminHandlerPacket);;
  //$04 --> handled by TLandscape
  //$06-$0B --> handled by TLandscape
  //$0C --> ClientHandling, done by TfrmMain
  //$0D --> RadarMapHandling, done by TfrmRadarMap
finalization
  for i := 0 to $FF do
    if PacketHandlers[i] <> nil then
      PacketHandlers[i].Free;
{$WARNINGS ON}
end.

