Palladion Software
user icon Guest

Created by zope. Last modified 2004-07-15 05:38:33.

File Properties

Filename Bio_Fish.pas
Size 8778
Content-type text/plain

Download File

Download

//==============================================================================
// Unit:       Bio_Fish
//
// Purpose:    Declare TBiolifeFish, a concrete "default" fish which derives its
//			   properties from the BioLife table.
//
// Copyright:  1997, Palladion Software
//==============================================================================
unit Bio_Fish;

interface

uses
	SysUtils,
    Classes,
    Graphics,
    ExtCtrls,
    Fish,
    DBCtrls;

type


  //----------------------------------------------------------------------------
  // Class:     TBiolifeFish
  //
  // Purpose:   Concrete fish class, deriving all properties (except speed) from
  //             the BioLife table entry for the same name.
  //
  // Note:      This class uses the GOF pattern "Flyweight" for sharing
  //			"specific" information (common name, bitmap, etc.).
  //----------------------------------------------------------------------------
  TBiolifeFish = class( TFish )

  private

    FTableIndex  		: integer;
    FHorizontalSpeed	: integer;
    FVerticalSpeed		: integer;

  protected

  	// Implement inherited abstract methods.
  	function GetCommonName : string;						override;
  	function GetScientificName : string;					override;
    function GetWidth : integer;							override;
    function GetHeight : integer;							override;
    function GetBitmap : TBitmap;							override;
    function GetAsString : string;							override;

    // Property implementation methods.
    function GetSpeciesId : integer;

  public

    constructor Create( aSpeciesId : integer );

    procedure Swim( var X : integer; var Y : integer;
    				maxX, maxY : integer );					override;

    property SpeciesId : integer
        read GetSpeciesId;

    function Clone : TFish;									override;

  end;                                                               

  function BiolifeFish_Builder( aPersistentState : string ) : TFish;

implementation

uses
	DB,
    DBTables;

type

  //----------------------------------------------------------------------------
  // Cache entry for shared "specific" data
  //----------------------------------------------------------------------------
  TSpeciesRecord = class

  	SpeciesId 			: integer;
    CommonName			: string;
    ScientificName		: string;
    Height				: integer;
    Width				: integer;
    Image				: TImage;

    destructor Destroy;

  end;

destructor TSpeciesRecord.Destroy;
begin
	Image.Free;
end;

var
  //----------------------------------------------------------------------------
  // Cache for shared "specific" data, indexed by speciesId.
  //----------------------------------------------------------------------------
	TheSpeciesList		: TStringList;

  //----------------------------------------------------------------------------
  // Query for looking up shared "specific" data, parameterized by speciesId.
  //----------------------------------------------------------------------------
    qrySpecies			: TQuery;
    dtsSpecies			: TDataSource;
    imgGraphic			: TDBImage;

//------------------------------------------------------------------------------
// TBiolifeFish implementation.
//------------------------------------------------------------------------------

constructor TBiolifeFish.Create( aSpeciesId : integer );

var
	strSpeciesId	: string;
    specRec			: TSpeciesRecord;
    gf				: TGraphicField;
    ms				: TMemoryStream;

begin

	strSpeciesId := IntToStr( aSpeciesId );

    if not TheSpeciesList.Find( strSpeciesId, FTableIndex ) then
    begin
    	specRec := TSpeciesRecord.Create;

        try
            with specRec, qrySpecies do
            begin
                Close;
                Params[0].AsInteger := aSpeciesId;
                Open;

                if ( RecordCount <> 1 ) then
                	raise EFishError.CreateFmt( 'Invalid species id: %d',
                    								[ aSpeciesid ] );

                SpeciesId 		:= aSpeciesId;
                CommonName 		:= FieldByName( 'Common_Name' ).AsString;
                ScientificName 	:= FieldByName( 'Species Name' ).AsString;
                Width			:= FieldByName( 'Length (cm)' ).AsInteger;

                Image 			:= TImage.Create( Nil );
                Image.Picture.Assign( imgGraphic.Picture );
                
              (*
                gf				:= FieldByName( 'Graphic' ) as TGraphicField;
                ms				:= TMemoryStream.Create;
                gf.SaveToStream( ms );
                Image.Picture.Bitmap.LoadFromStream( ms );
                ms.Free;
               *)

                Height			:= Trunc( Image.Height * Width / Image.Width );
                Image.Height	:= Height;
                Image.Width		:= Width;

                Close;
            end;

        except

            on E : Exception do
            begin
                specRec.Free;
                raise;
            end;

        end;

        FTableIndex := TheSpeciesList.AddObject( strSpeciesId, specRec );
    end;

    //
    // We lack information for setting "real" speeds here.
    //
    FHorizontalSpeed := Random( 11 ) - 5;
    FVerticalSpeed := Random( 11 ) - 5;
end;


function TBiolifeFish.GetCommonName : string;
begin
	Result := TSpeciesRecord(
    			TheSpeciesList.Objects[ FTableIndex ] ).CommonName;
end;


function TBiolifeFish.GetScientificName : string;
begin
	Result := TSpeciesRecord(
    			TheSpeciesList.Objects[ FTableIndex ] ).ScientificName;
end;


function TBiolifeFish.GetWidth : integer;
begin
	Result := TSpeciesRecord( TheSpeciesList.Objects[ FTableIndex ] ).Width;
end;


function TBiolifeFish.GetHeight : integer;
begin
	Result := TSpeciesRecord( TheSpeciesList.Objects[ FTableIndex ] ).Height;
end;


function TBiolifeFish.GetBitmap : TBitmap;
begin
	Result := TSpeciesRecord(
    			TheSpeciesList.Objects[ FTableIndex ] ).Image.Picture.Bitmap;
end;


function TBiolifeFish.GetSpeciesId : integer;
begin
	Result := TSpeciesRecord( TheSpeciesList.Objects[ FTableIndex ] ).SpeciesId;
end;


procedure TBiolifeFish.Swim( var X : integer; var Y : integer;
							 maxX, maxY : integer );
begin

	X := X + FHorizontalSpeed;

    if ( X <= 0 ) or ( X + Width >= maxX ) or ( Random( 100 ) < 5 ) then
    	FHorizontalSpeed := - FHorizontalSpeed;

    Y := Y + FVerticalSpeed;

    if ( Y <= 0 ) or ( Y + Height >= maxY ) or ( Random( 100 ) < 5 ) then
    	FVerticalSpeed := - FVerticalSpeed;
end;


function TBiolifeFish.Clone : TFish;
begin
	Result := TBiolifeFish.Create( FTableIndex );
end;


function TBiolifeFish.GetAsString : string;
begin
	Result := IntToStr( SpeciesId ) + ','
            + IntToStr( FHorizontalSpeed ) + ','
            + IntToStr( FVerticalSpeed );
end;



function BiolifeFish_Builder( aPersistentState : string ) : TFish;

var
	comma			: integer;
    aSpeciesId		: integer;
    bioFish			: TBiolifeFish;

begin

	comma := Pos( ',', aPersistentState );

    if ( comma = 0 ) then
    	raise EFishError.Create( 'Invalid BiolifeFish entry.' );

    aSpeciesId := StrToInt( Copy( aPersistentState, 1, comma - 1 ) );

    bioFish := TBiolifeFish.Create( aSpeciesId );

    Delete( aPersistentState, 1, comma );
    comma := Pos( ',', aPersistentState );

    if ( comma = 0 ) then
    begin
    	bioFish.Free;
    	raise EFishError.Create( 'Invalid BiolifeFish entry.' );
    end;

    with bioFish do
    begin
    	FHorizontalSpeed := StrToInt( Copy( aPersistentState, 1, comma-1 ) );
    	FVerticalSpeed := StrToInt( Copy( aPersistentState, comma+1, 999 ) );
    end;

    Result := bioFish;
end;


procedure Setup;
begin
	TheSpeciesList := TStringList.Create;

    qrySpecies := TQuery.Create( nil );
    with qrySpecies do
    begin
    	DatabaseName := 'DBDEMOS';
        SQL.Add( 'SELECT * FROM BioLife b' );
        SQL.Add( ' WHERE b."Species No" = :SpeciesId' );
        Prepare;
    end;

    dtsSpecies := TDataSource.Create( nil );
    dtsSpecies.Dataset := qrySpecies;

    imgGraphic := TDBImage.Create( nil );
    imgGraphic.Datasource := dtsSpecies;
    imgGraphic.DataField := 'Graphic';

end;
//------------------------------------------------------------------------------
// Flush the cache and free it on unload.
//------------------------------------------------------------------------------
procedure Cleanup;

var
	iSpecies : integer;
    specRec  : TSpeciesRecord;

begin

	imgGraphic.Free;
    dtsSpecies.Free;
	qrySpecies.Free;

	for iSpecies := TheSpeciesList.Count - 1 downto 0 do
    begin
    	specRec := TSpeciesRecord( TheSpeciesList.Objects[ iSpecies ] );
        TheSpeciesList.Objects[ iSpecies ] := Nil;
        specRec.Free;
    end;

    TheSpeciesList.Free;
end;

initialization

	Setup;       
    TFish.RegisterBuilder( TBiolifeFish.ClassName, @BiolifeFish_Builder );

finalization

	Cleanup;

end.