unit main_stream;

{$mode objfpc}{$H+}

interface

uses
	Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, StdCtrls,
	Spin, Blowfish, demo_stream;

const savedFileName: TFileName = 'stream.dat';

type

	{ TForm1 }

 TForm1 = class(TForm)
		btnDecrypt: TButton;
		btnEncrypt: TButton;
		btnGenerateStream: TButton;
		btnLoadStream: TButton;
		btnSaveStream: TButton;
		edtRecord: TEdit;
		lblAdjustPosition: TLabel;
		lblNumRecords: TLabel;
		lblPositionDesc: TLabel;
		lblOrigin: TLabel;
		lblRecordNo: TLabel;
		lblSavedFileSize: TLabel;
		lblStreamSize: TLabel;
		memoDecrypted: TMemo;
		memoDisplay: TMemo;
		memoEncrypted: TMemo;
		seCurrentRecNo: TSpinEdit;
		seNoOfRecords: TSpinEdit;
		tbPosition: TTrackBar;
		udMover: TUpDown;
		procedure btnDecryptClick(Sender: TObject);
	procedure btnEncryptClick(Sender: TObject);
	procedure btnGenerateStreamClick(Sender: TObject);
	procedure btnLoadStreamClick(Sender: TObject);
	procedure btnSaveStreamClick(Sender: TObject);
	procedure FormDestroy(Sender: TObject);
	procedure seCurrentRecNoChange(Sender: TObject);
	procedure udMoverClick(Sender: TObject; Button: TUDBtnType);
	private
		ds: TdemoStream;
		sOriginal, sEncrypted: TStringStream;
		key: string;
	public
		procedure DisplayStream;
	end;

var
	Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.udMoverClick(Sender: TObject; Button: TUDBtnType);
begin
	if not Assigned(ds) then Exit;

	case Button of
		btPrev: if (ds.Position >= SizeOf(ds.rec)) then
		begin
			ds.Seek(- 2*SizeOf(ds.rec), sofromCurrent);

			if (ds.Position < 0) then ds.Position := 0;

			edtRecord.Text := ds.RecAsString;
			seCurrentRecNo.Value := seCurrentRecNo.Value-1;
		end;

		btNext: if (ds.Position < ds.Size) then
		begin
			edtRecord.Text := ds.RecAsString;
			seCurrentRecNo.Value := seCurrentRecNo.Value+1;
		end;
	end;

	seCurrentRecNoChange(nil);
end;

procedure TForm1.btnEncryptClick(Sender: TObject);
var be: TBlowFishEncryptStream;
begin
	if memoDisplay.Lines.Count = 0 then Exit;

	key := 'example cipher key for Blowfish';
	sOriginal := TStringStream.Create(EmptyStr);
	be := TBlowFishEncryptStream.Create(key, sOriginal);
	be.WriteAnsiString(memoDisplay.Text);
	be.Free;
	memoEncrypted.Text := sOriginal.DataString;
end;

procedure TForm1.btnGenerateStreamClick(Sender: TObject);
begin
	ds.Free;
	ds := TdemoStream.Create(seNoOfRecords.Value);

	seCurrentRecNo.MaxValue := seNoOfRecords.Value -1;

	DisplayStream;
	seCurrentRecNoChange(nil);
	btnSaveStream.Enabled := True;
	lblSavedfileSize.Caption := EmptyStr;

	memoEncrypted.Lines.Clear;
	memoDecrypted.Lines.Clear;
end;

procedure TForm1.btnLoadStreamClick(Sender: TObject);
begin
	FreeAndNil(ds);

	ds := TdemoStream.Create(0);
	ds.LoadFromFile(savedFileName);
	seNoOfRecords.Value := ds.Size div SizeOf(ds.rec);
	seCurrentRecNo.MaxValue := seNoOfRecords.Value -1;

	DisplayStream;
	btnLoadStream.Enabled := False;
	seCurrentRecNoChange(nil);

	memoEncrypted.Lines.Clear;
	memoDecrypted.Lines.Clear;
end;

procedure TForm1.btnSaveStreamClick(Sender: TObject);
begin
	if Assigned(ds) then
	begin
		memoDisplay.Lines.Clear;
		edtRecord.Text := EmptyStr;

		ds.SaveToFile(savedFileName);
		// lblSavedFileSize.Caption := Format('Saved file size is: %d bytes', [FileSize(savedFileName)]);

		btnLoadStream.Enabled := True;
		btnSaveStream.Enabled := False;
		FreeAndNil(ds);
	end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
	ds.Free;
end;

procedure TForm1.seCurrentRecNoChange(Sender: TObject);
var L: integer;
begin
	if not Assigned(ds) then Exit;

	ds.Seek(seCurrentRecNo.Value * SizeOf(ds.rec), soFromBeginning);
	edtRecord.Text := ds.RecAsString;
	L := Length(edtRecord.Text) + Length(LineEnding);
	tbPosition.Position := tbPosition.Max * ds.Position div ds.Size;

	memoDisplay.SelStart := (tbPosition.Position) * L;
	memoDisplay.SelLength := L;
end;

procedure TForm1.btnDecryptClick(Sender: TObject);
var bd: TBlowFishDeCryptStream;
begin
	sEncrypted := TStringStream.Create(sOriginal.DataString);
	bd := TBlowFishDeCryptStream.Create(key, sEncrypted);
	memoDecrypted.Text := bd.ReadAnsiString;
	bd.Free;
	sEncrypted.Free;
	sOriginal.Free;
end;

procedure TForm1.DisplayStream;
begin
	lblStreamSize.Caption := Format('%d ', [ds.Size]);
	tbPosition.Max := ds.Size div SizeOf(ds.rec) -1;

	memoDisplay.Lines.BeginUpdate;
		memoDisplay.Clear;
		ds.Position := 0;
		while (ds.Position < ds.Size) do
		begin
			memoDisplay.Lines.Add(ds.RecAsString);
			tbPosition.Position := (ds.Size * tbPosition.Max) div ds.Position;
		end;
	memoDisplay.Lines.EndUpdate;

	seCurrentRecNo.MaxValue := seNoOfRecords.Value;
	ds.Seek(seCurrentRecNo.Value * SizeOf(ds.rec), soFromBeginning);
	edtRecord.Text := ds.RecAsString;
	tbPosition.Position := (ds.Size * tbPosition.Max) div ds.Position;
end;

end.

