Componentes.Terceros.jcl/official/1.96/source/common/JclEDI.pas

1642 lines
50 KiB
ObjectPascal

{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) }
{ }
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
{ License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
{ and limitations under the License. }
{ }
{ The Original Code is JclEDI.pas. }
{ }
{ The Initial Developer of the Original Code is Raymond Alexander. }
{ Portions created by Raymond Alexander are Copyright Raymond Alexander. All rights reserved. }
{ }
{ Contributor(s): }
{ Raymond Alexander (rayspostbox3), Robert Marquardt, Robert Rossmair, Petr Vones, }
{ Andreas Hausladen }
{ }
{**************************************************************************************************}
{ }
{ Contains classes to eaisly parse EDI documents and data. Variable delimiter detection allows }
{ parsing of the file without knowledge of the standards at an Interchange level. This enables }
{ parsing and construction of EDI documents with different delimiters. }
{ }
{ Unit owner: Raymond Alexander }
{ Date created: Before February, 1, 2001 }
{ Additional Info: }
{ E-Mail at RaysDelphiBox3 att hotmail dott com }
{ For latest EDI specific demos see http://sourceforge.net/projects/edisdk }
{ See home page for latest news & events and online help. }
{ }
{**************************************************************************************************}
// $Id: JclEDI.pas,v 1.17 2005/08/09 10:30:21 ahuser Exp $
unit JclEDI;
{$I jcl.inc}
{$IFDEF SUPPORTS_WEAKPACKAGEUNIT}
{$WEAKPACKAGEUNIT ON}
{$ENDIF SUPPORTS_WEAKPACKAGEUNIT}
// Add the following directive in project options for debugging memory leaks.
// {$DEFINE ENABLE_EDI_DEBUGGING}
interface
uses
SysUtils, Classes,
JclBase;
const
NA_LoopId = 'N/A'; // Constant used for loop id comparison
ElementSpecId_Reserved = 'Reserved';
EDIDataType_Numeric = 'N';
EDIDataType_Decimal = 'R';
EDIDataType_Identifier = 'ID';
EDIDataType_String = 'AN';
EDIDataType_Date = 'DT';
EDIDataType_Time = 'TM';
EDIDataType_Binary = 'B';
{$IFDEF ENABLE_EDI_DEBUGGING}
var
Debug_EDIDataObjectsCreated: Int64;
Debug_EDIDataObjectsDestroyed: Int64;
Debug_EDIDataObjectListCreated: Int64;
Debug_EDIDataObjectListDestroyed: Int64;
Debug_EDIDataObjectListItemsCreated: Int64;
Debug_EDIDataObjectListItemsDestroyed: Int64;
{$ENDIF ENABLE_EDI_DEBUGGING}
type
TEDIObject = class(TObject); // Base EDI Object
TEDIObjectArray = array of TEDIObject;
EJclEDIError = EJclError;
// EDI Forward Class Declarations
TEDIDataObject = class;
TEDIDataObjectGroup = class;
TEDIObjectListItem = class;
TEDIObjectList = class;
TEDIDataObjectListItem = class;
TEDIDataObjectList = class;
// EDI Delimiters Object
TEDIDelimiters = class(TEDIObject)
private
FSegmentDelimiter: string;
FElementDelimiter: string;
FSubElementSeperator: string; // Also known as: Component Data Seperator
FSegmentDelimiterLength: Integer;
FElementDelimiterLength: Integer;
FSubelementSeperatorLength: Integer;
procedure SetSD(const Delimiter: string);
procedure SetED(const Delimiter: string);
procedure SetSS(const Delimiter: string);
public
constructor Create; overload;
constructor Create(const SD, ED, SS: string); overload;
published
property SD: string read FSegmentDelimiter write SetSD;
property ED: string read FElementDelimiter write SetED;
property SS: string read FSubElementSeperator write SetSS;
property SDLen: Integer read FSegmentDelimiterLength;
property EDLen: Integer read FElementDelimiterLength;
property SSLen: Integer read FSubElementSeperatorLength;
end;
// EDI Data Object
TEDIDataObjectType =
(ediUnknown, ediElement, ediCompositeElement, ediSegment, ediLoop,
ediTransactionSet, ediMessage, ediFunctionalGroup,
ediInterchangeControl, ediFile, ediCustom);
TEDIDataObjectDataState = (ediCreated, ediAssembled, ediDisassembled);
{$IFDEF CLR}
TCustomData = TObject;
{$ELSE}
TCustomData = Pointer; // backward compatibility
{$ENDIF CLR}
TEDIDataObject = class(TEDIObject)
private
procedure SetDelimiters(const Delimiters: TEDIDelimiters);
protected
FEDIDOT: TEDIDataObjectType;
FState: TEDIDataObjectDataState;
FData: string;
FLength: Integer;
FParent: TEDIDataObject;
FDelimiters: TEDIDelimiters;
FErrorLog: TStrings;
FSpecPointer: TEDIObject;
FCustomData1: TCustomData;
FCustomData2: TCustomData;
function GetData: string;
procedure SetData(const Data: string);
public
constructor Create(Parent: TEDIDataObject); reintroduce;
destructor Destroy; override;
function Assemble: string; virtual; abstract;
procedure Disassemble; virtual; abstract;
property SpecPointer: TEDIObject read FSpecPointer write FSpecPointer;
property CustomData1: TCustomData read FCustomData1 write FCustomData1;
property CustomData2: TCustomData read FCustomData2 write FCustomData2;
published
property State: TEDIDataObjectDataState read FState;
property Data: string read GetData write SetData;
property DataLength: Integer read FLength;
property Parent: TEDIDataObject read FParent write FParent;
property Delimiters: TEDIDelimiters read FDelimiters write SetDelimiters;
end;
TEDIDataObjectArray = array of TEDIDataObject;
// EDI Data Object Group
TEDIDataObjectGroup = class(TEDIDataObject)
protected
FGroupIsParent: Boolean;
FEDIDataObjects: TEDIDataObjectList;
FCreateObjectType: TEDIDataObjectType;
function GetCount: Integer;
function GetEDIDataObject(Index: Integer): TEDIDataObject;
procedure SetEDIDataObject(Index: Integer; EDIDataObject: TEDIDataObject);
function InternalAssignDelimiters: TEDIDelimiters; virtual; abstract;
function InternalCreateEDIDataObject: TEDIDataObject; virtual; abstract;
public
constructor Create(Parent: TEDIDataObject; EDIDataObjectCount: Integer = 0); reintroduce;
destructor Destroy; override;
function IndexIsValid(Index: Integer): Boolean;
//
function AddEDIDataObject: Integer;
function AppendEDIDataObject(EDIDataObject: TEDIDataObject): Integer;
function InsertEDIDataObject(InsertIndex: Integer): Integer; overload;
function InsertEDIDataObject(InsertIndex: Integer; EDIDataObject:
TEDIDataObject): Integer; overload;
procedure DeleteEDIDataObject(Index: Integer); overload;
procedure DeleteEDIDataObject(EDIDataObject: TEDIDataObject); overload;
//
function AddEDIDataObjects(Count: Integer): Integer;
function AppendEDIDataObjects(EDIDataObjectArray: TEDIDataObjectArray): Integer;
function InsertEDIDataObjects(InsertIndex, Count: Integer): Integer; overload;
function InsertEDIDataObjects(InsertIndex: Integer;
EDIDataObjectArray: TEDIDataObjectArray): Integer; overload;
procedure DeleteEDIDataObjects; overload;
procedure DeleteEDIDataObjects(Index, Count: Integer); overload;
//
function GetIndexPositionFromParent: Integer; virtual;
//
property EDIDataObject[Index: Integer]: TEDIDataObject read GetEDIDataObject
write SetEDIDataObject; default;
property EDIDataObjects: TEDIDataObjectList read FEDIDataObjects;
published
property CreateObjectType: TEDIDataObjectType read FCreateObjectType;
property EDIDataObjectCount: Integer read GetCount;
end;
TEDIDataObjectGroupArray = array of TEDIDataObjectGroup;
// EDI Data Object Linked List Header and Item classes
TEDIObjectListItem = class(TEDIObject)
protected
FParent: TEDIObjectList;
FPriorItem: TEDIObjectListItem;
FNextItem: TEDIObjectListItem;
FEDIObject: TEDIObject;
FItemIndex: Integer;
FName: string;
public
constructor Create(Parent: TEDIObjectList; PriorItem: TEDIObjectListItem;
EDIObject: TEDIObject = nil);
destructor Destroy; override;
function GetIndexPositionFromParent: Integer;
procedure FreeAndNilEDIDataObject;
published
property ItemIndex: Integer read FItemIndex write FItemIndex;
property PriorItem: TEDIObjectListItem read FPriorItem write FPriorItem;
property NextItem: TEDIObjectListItem read FNextItem write FNextItem;
property EDIObject: TEDIObject read FEDIObject write FEDIObject;
property Name: string read FName write FName;
property Parent: TEDIObjectList read FParent write FParent;
end;
TEDIDataObjectListOptions = set of (loAutoUpdateIndexes);
TEDIObjectList = class(TEDIObject)
private
function GetItem(Index: Integer): TEDIObjectListItem;
protected
FOwnsObjects: Boolean;
FCount: Integer;
FOptions: TEDIDataObjectListOptions;
FFirstItem: TEDIObjectListItem;
FLastItem: TEDIObjectListItem;
FCurrentItem: TEDIObjectListItem;
function GetEDIObject(Index: Integer): TEDIObject;
procedure SetEDIObject(Index: Integer; const Value: TEDIObject);
function CreateListItem(PriorItem: TEDIObjectListItem;
EDIObject: TEDIObject = nil): TEDIObjectListItem; virtual;
public
constructor Create(OwnsObjects: Boolean = True);
destructor Destroy; override;
procedure Add(Item: TEDIObjectListItem; Name: string = ''); overload;
function Add(EDIObject: TEDIObject; Name: string = ''): TEDIObjectListItem; overload;
function Find(Item: TEDIObjectListItem): TEDIObjectListItem; overload;
function Find(EDIObject: TEDIObject): TEDIObjectListItem; overload;
function FindEDIObject(EDIObject: TEDIObject): TEDIObject;
function Extract(Item: TEDIObjectListItem): TEDIObjectListItem; overload; virtual;
function Extract(EDIObject: TEDIObject): TEDIObject; overload; virtual;
procedure Remove(Item: TEDIObjectListItem); overload;
procedure Remove(EDIObject: TEDIObject); overload;
function Insert(Item, BeforeItem: TEDIObjectListItem): TEDIObjectListItem; overload;
function Insert(EDIObject, BeforeEDIObject: TEDIObject): TEDIObjectListItem; overload;
function Insert(BeforeItem: TEDIObjectListItem): TEDIObjectListItem; overload;
function Insert(BeforeEDIObject: TEDIObject): TEDIObjectListItem; overload;
procedure Clear;
function First(Index: Integer = 0): TEDIObjectListItem; virtual;
function Next: TEDIObjectListItem; virtual;
function Prior: TEDIObjectListItem; virtual;
function Last: TEDIObjectListItem; virtual;
procedure UpdateCount;
// ...ByName procedures and functions
function FindItemByName(Name: string;
StartItem: TEDIObjectListItem = nil): TEDIObjectListItem; virtual;
function ReturnListItemsByName(Name: string): TEDIObjectList; virtual;
// Dynamic Array Emulation
function IndexOf(Item: TEDIObjectListItem): Integer; overload;
function IndexOf(EDIObject: TEDIObject): Integer; overload;
function IndexIsValid(Index: Integer): Boolean;
procedure Insert(InsertIndex: Integer; EDIObject: TEDIObject); overload;
procedure Delete(Index: Integer); overload;
procedure Delete(EDIObject: TEDIObject); overload;
procedure UpdateIndexes(StartItem: TEDIObjectListItem = nil);
//
property Item[Index: Integer]: TEDIObjectListItem read GetItem;
property EDIObject[Index: Integer]: TEDIObject read GetEDIObject
write SetEDIObject; default;
published
property Count: Integer read FCount;
property OwnsObjects: Boolean read FOwnsObjects write FOwnsObjects;
property Options: TEDIDataObjectListOptions read FOptions write FOptions;
property CurrentItem: TEDIObjectListItem read FCurrentItem;
end;
TEDIDataObjectListItem = class(TEDIObjectListItem)
private
function GetEDIDataObject: TEDIDataObject;
procedure SetEDIDataObject(const Value: TEDIDataObject);
published
property EDIDataObject: TEDIDataObject read GetEDIDataObject write SetEDIDataObject;
end;
TEDIDataObjectList = class(TEDIObjectList)
private
function GetEDIDataObject(Index: Integer): TEDIDataObject;
procedure SetEDIDataObject(Index: Integer; const Value: TEDIDataObject);
public
function CreateListItem(PriorItem: TEDIObjectListItem;
EDIObject: TEDIObject = nil): TEDIObjectListItem; override;
property EDIDataObject[Index: Integer]: TEDIDataObject read GetEDIDataObject
write SetEDIDataObject; default;
end;
// EDI Loop Stack
TEDILoopStackRecord = record
SegmentId: string;
SpecStartIndex: Integer;
OwnerLoopId: string;
ParentLoopId: string;
EDIObject: TEDIObject;
EDISpecObject: TEDIObject;
end;
TEDILoopStackArray = array of TEDILoopStackRecord;
TEDILoopStackFlags = (ediAltStackPointer, ediStackResized, ediLoopRepeated);
TEDILoopStackFlagSet = set of TEDILoopStackFlags;
TEDILoopStackOnAddLoopEvent = procedure(StackRecord: TEDILoopStackRecord;
SegmentId, OwnerLoopId, ParentLoopId: string; var EDIObject: TEDIObject) of object;
TEDILoopStack = class(TEDIObject)
private
function GetSize: Integer;
protected
FStack: TEDILoopStackArray;
FFlags: TEDILoopStackFlagSet;
FCheckAssignedEDIObject: Boolean;
FOnAddLoop: TEDILoopStackOnAddLoopEvent;
procedure DoAddLoop(StackRecord: TEDILoopStackRecord;
SegmentId, OwnerLoopId, ParentLoopId: string; var EDIObject: TEDIObject);
public
constructor Create;
destructor Destroy; override;
// Basic Stack Routines
function Peek: TEDILoopStackRecord; overload;
function Peek(Index: Integer): TEDILoopStackRecord; overload;
procedure Pop(Index: Integer);
function Push(SegmentId, OwnerLoopId, ParentLoopId: string; StartIndex: Integer;
EDIObject: TEDIObject): Integer;
// Extended Stack Routines
function GetSafeStackIndex(Index: Integer): Integer;
function SetStackPointer(OwnerLoopId, ParentLoopId: string): Integer;
procedure UpdateStackObject(EDIObject: TEDIObject);
procedure UpdateStackData(SegmentId, OwnerLoopId, ParentLoopId: string; StartIndex: Integer;
EDIObject: TEDIObject);
// Extended Stack Routines
function ValidateLoopStack(SegmentId, OwnerLoopId, ParentLoopId: string; StartIndex: Integer;
EDIObject: TEDIObject): TEDILoopStackRecord;
function Debug: string;
//
property Stack: TEDILoopStackArray read FStack;
published
property Size: Integer read GetSize;
property Flags: TEDILoopStackFlagSet read FFlags write FFlags;
property OnAddLoop: TEDILoopStackOnAddLoopEvent read FOnAddLoop write FOnAddLoop;
end;
// Other
// Compatibility functions
function StringRemove(const S, Pattern: string; Flags: TReplaceFlags): string;
function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
implementation
uses
JclResources, JclStrings;
// Other
function StringRemove(const S, Pattern: string; Flags: TReplaceFlags): string;
var
SearchPattern: string;
I, Offset, SearchPatternLength: Integer;
begin
if rfIgnoreCase in Flags then
begin
Result := AnsiUpperCase(S);
SearchPattern := AnsiUpperCase(Pattern);
end
else
begin
Result := S;
SearchPattern := Pattern;
end;
SearchPatternLength := Length(SearchPattern);
Result := S;
I := 1;
Offset := 1;
while I <= Length(Result) do
begin
if SearchPatternLength = 1 then
begin
while Result[I] = SearchPattern[1] do
begin
Offset := Offset + SearchPatternLength;
if not (rfReplaceAll in Flags) then
Break;
Inc(I);
end;
end
else // SearchPatternLength > 1
begin
while Copy(Result, Offset, SearchPatternLength) = SearchPattern do
begin
Offset := Offset + SearchPatternLength;
if not (rfReplaceAll in Flags) then
Break;
end;
end;
if Offset <= Length(Result) then
Result[I] := S[Offset]
else
begin
Result[I] := #0;
SetLength(Result, I-1);
Break;
end;
if not (rfReplaceAll in Flags) then
Break;
Inc(I);
Inc(Offset);
end;
end;
function StringReplace(const S, OldPattern, NewPattern: string; Flags: TReplaceFlags): string;
var
SearchString, SearchPattern: string;
I, SearchIndex, ReplaceIndex: Integer;
SearchPatternLength, ReplacePatternLength: Integer;
SearchResult, ReplaceCount: Integer;
begin
Result := '';
// Handle Case Sensitivity
if rfIgnoreCase in Flags then
begin
SearchString := AnsiUpperCase(S);
SearchPattern := AnsiUpperCase(OldPattern);
end
else
begin
SearchString := S;
SearchPattern := OldPattern;
end;
SearchPatternLength := Length(OldPattern);
ReplacePatternLength := Length(NewPattern);
// Calculate length of result string
ReplaceCount := 0;
SearchResult := StrSearch(SearchPattern, SearchString, 1);
if rfReplaceAll in Flags then
while SearchResult <> 0 do
begin
Inc(SearchResult);
Inc(ReplaceCount);
SearchResult := StrSearch(SearchPattern, SearchString, SearchResult);
end
else
if SearchResult <> 0 then
Inc(ReplaceCount);
SetLength(Result, Length(S) + ((ReplacePatternLength - SearchPatternLength) * ReplaceCount));
// Copy the characters by looping through the result and source at the same time
ReplaceCount := 0;
ReplaceIndex := 1;
SearchIndex := 1;
// Loop while the indexes are still in range
while (ReplaceIndex <= Length(Result)) and (SearchIndex <= Length(SearchString)) do
begin
// Enter algorithm if replacing a pattern or there have been no replacements yet
if (rfReplaceAll in Flags) or ((not (rfReplaceAll in Flags)) and (ReplaceCount = 0)) then
// Replace the pattern (including repeating patterns)
while Copy(SearchString, SearchIndex, SearchPatternLength) = SearchPattern do
begin
// Move forward in the search string
SearchIndex := SearchIndex + Length(SearchPattern);
// Replace an old pattern by writing the new pattern to the result
I := 1;
while (ReplaceIndex <= Length(Result)) and (I <= ReplacePatternLength) do
begin
Result[ReplaceIndex] := NewPattern[I];
Inc(I);
Inc(ReplaceIndex);
end;
//
Inc(ReplaceCount);
// If only making one replacement then break
if not (rfReplaceAll in Flags) then
Break;
end;
// Copy character
if (ReplaceIndex <= Length(Result)) and (SearchIndex <= Length(SearchString)) then
Result[ReplaceIndex] := S[SearchIndex];
// Set indexes for next copy
Inc(SearchIndex);
Inc(ReplaceIndex);
end;
end;
//=== { TEDIDelimiters } =====================================================
constructor TEDIDelimiters.Create;
begin
Create('~', '*', '>');
end;
constructor TEDIDelimiters.Create(const SD, ED, SS: string);
begin
inherited Create;
SetSD(SD);
SetED(ED);
SetSS(SS);
end;
procedure TEDIDelimiters.SetED(const Delimiter: string);
begin
FElementDelimiter := Delimiter;
FElementDelimiterLength := Length(FElementDelimiter);
end;
procedure TEDIDelimiters.SetSD(const Delimiter: string);
begin
FSegmentDelimiter := Delimiter;
FSegmentDelimiterLength := Length(FSegmentDelimiter);
end;
procedure TEDIDelimiters.SetSS(const Delimiter: string);
begin
FSubelementSeperator := Delimiter;
FSubelementSeperatorLength := Length(FSubElementSeperator);
end;
//=== { TEDIDataObject } =====================================================
constructor TEDIDataObject.Create(Parent: TEDIDataObject);
begin
inherited Create;
FState := ediCreated;
FEDIDOT := ediUnknown;
FData := '';
FLength := 0;
FParent := Parent;
FDelimiters := nil;
FSpecPointer := nil;
FCustomData1 := nil;
FCustomData2 := nil;
{$IFDEF ENABLE_EDI_DEBUGGING}
Inc(Debug_EDIDataObjectsCreated);
{$ENDIF ENABLE_EDI_DEBUGGING}
end;
destructor TEDIDataObject.Destroy;
begin
{$IFDEF ENABLE_EDI_DEBUGGING}
Inc(Debug_EDIDataObjectsDestroyed);
{$ENDIF ENABLE_EDI_DEBUGGING}
if not Assigned(FParent) then
FDelimiters.Free;
FDelimiters := nil;
FSpecPointer := nil;
FCustomData1 := nil;
FCustomData2 := nil;
inherited Destroy;
end;
function TEDIDataObject.GetData: string;
begin
Result := FData;
end;
procedure TEDIDataObject.SetData(const Data: string);
begin
FData := Data;
FLength := Length(FData);
end;
procedure TEDIDataObject.SetDelimiters(const Delimiters: TEDIDelimiters);
begin
if not Assigned(FParent) then
FreeAndNil(FDelimiters);
FDelimiters := Delimiters;
end;
//=== { TEDIDataObjectGroup } ================================================
constructor TEDIDataObjectGroup.Create(Parent: TEDIDataObject; EDIDataObjectCount: Integer);
begin
inherited Create(Parent);
FCreateObjectType := ediUnknown;
FGroupIsParent := True;
FEDIDataObjects := TEDIDataObjectList.Create;
if EDIDataObjectCount > 0 then
AddEDIDataObjects(EDIDataObjectCount);
end;
function TEDIDataObjectGroup.AddEDIDataObjects(Count: Integer): Integer;
var
I: Integer;
begin
Result := FEDIDataObjects.Count; // Return position of 1st
for I := 1 to Count do
FEDIDataObjects.Add(InternalCreateEDIDataObject);
end;
function TEDIDataObjectGroup.AddEDIDataObject: Integer;
begin
Result := FEDIDataObjects.Count; // Return position
FEDIDataObjects.Add(InternalCreateEDIDataObject);
end;
function TEDIDataObjectGroup.AppendEDIDataObject(EDIDataObject: TEDIDataObject): Integer;
begin
Result := FEDIDataObjects.Count; // Return position
FEDIDataObjects.Add(EDIDataObject);
if FGroupIsParent then
EDIDataObject.Parent := Self;
end;
function TEDIDataObjectGroup.AppendEDIDataObjects(EDIDataObjectArray: TEDIDataObjectArray): Integer;
var
I: Integer;
begin
Result := FEDIDataObjects.Count; // Return position of 1st
for I := Low(EDIDataObjectArray) to High(EDIDataObjectArray) do
begin
FEDIDataObjects.Add(EDIDataObjectArray[I]);
if FGroupIsParent then
EDIDataObjectArray[I].Parent := Self;
end;
end;
procedure TEDIDataObjectGroup.DeleteEDIDataObject(EDIDataObject: TEDIDataObject);
begin
if loAutoUpdateIndexes in FEDIDataObjects.Options then
FEDIDataObjects.Delete(EDIDataObject)
else
FEDIDataObjects.Remove(EDIDataObject);
end;
procedure TEDIDataObjectGroup.DeleteEDIDataObject(Index: Integer);
begin
if IndexIsValid(Index) then
FEDIDataObjects.Delete(Index)
else
{$IFNDEF CLR}
raise EJclEDIError.CreateResFmt(@RsEDIError010, [Self.ClassName, IntToStr(Index)]);
{$ELSE}
raise EJclEDIError.CreateFmt(RsEDIError010, [Self.ClassName, IntToStr(Index)]);
{$ENDIF ~CLR}
end;
procedure TEDIDataObjectGroup.DeleteEDIDataObjects;
begin
FEDIDataObjects.Clear;
end;
procedure TEDIDataObjectGroup.DeleteEDIDataObjects(Index, Count: Integer);
var
I: Integer;
begin
if IndexIsValid(Index) then
begin
FEDIDataObjects.Options := FEDIDataObjects.Options - [loAutoUpdateIndexes];
try
for I := 1 to Count do
DeleteEDIDataObject(Index);
finally
FEDIDataObjects.Options := FEDIDataObjects.Options + [loAutoUpdateIndexes];
end;
end
else
{$IFNDEF CLR}
raise EJclEDIError.CreateResFmt(@RsEDIError011, [IntToStr(Index)]);
{$ELSE}
raise EJclEDIError.CreateFmt(RsEDIError011, [IntToStr(Index)]);
{$ENDIF ~CLR}
end;
destructor TEDIDataObjectGroup.Destroy;
begin
DeleteEDIDataObjects;
FreeAndNil(FEDIDataObjects);
inherited Destroy;
end;
function TEDIDataObjectGroup.GetEDIDataObject(Index: Integer): TEDIDataObject;
begin
if FEDIDataObjects.Count > 0 then
if Index >= 0 then
if Index <= FEDIDataObjects.Count - 1 then
begin
if not Assigned(FEDIDataObjects[Index]) then
raise EJclEDIError.CreateFmt(RsEDIError006, [Self.ClassName, IntToStr(Index)]);
Result := FEDIDataObjects[Index];
end
else
raise EJclEDIError.CreateFmt(RsEDIError005, [Self.ClassName, IntToStr(Index)])
else
raise EJclEDIError.CreateFmt(RsEDIError004, [Self.ClassName, IntToStr(Index)])
else
raise EJclEDIError.CreateFmt(RsEDIError003, [Self.ClassName, IntToStr(Index)]);
end;
function TEDIDataObjectGroup.IndexIsValid(Index: Integer): Boolean;
begin
Result := FEDIDataObjects.IndexIsValid(Index);
end;
function TEDIDataObjectGroup.InsertEDIDataObject(InsertIndex: Integer): Integer;
begin
Result := InsertIndex; // Return position
if IndexIsValid(InsertIndex) then
FEDIDataObjects.Insert(InsertIndex, InternalCreateEDIDataObject)
else
Result := AddEDIDataObject;
end;
function TEDIDataObjectGroup.InsertEDIDataObject(InsertIndex: Integer;
EDIDataObject: TEDIDataObject): Integer;
begin
Result := InsertIndex; // Return position
if IndexIsValid(InsertIndex) then
begin
FEDIDataObjects.Insert(InsertIndex, EDIDataObject);
if FGroupIsParent then
EDIDataObject.Parent := Self;
end
else
Result := AppendEDIDataObject(EDIDataObject);
end;
function TEDIDataObjectGroup.InsertEDIDataObjects(InsertIndex: Integer;
EDIDataObjectArray: TEDIDataObjectArray): Integer;
var
I: Integer;
begin
Result := InsertIndex; // Return position of 1st
if IndexIsValid(InsertIndex) then
begin
for I := High(EDIDataObjectArray) downto Low(EDIDataObjectArray) do
begin
FEDIDataObjects.Insert(InsertIndex, EDIDataObjectArray[I]);
if FGroupIsParent then
EDIDataObjectArray[I].Parent := Self;
end;
end
else
Result := AppendEDIDataObjects(EDIDataObjectArray);
end;
function TEDIDataObjectGroup.InsertEDIDataObjects(InsertIndex, Count: Integer): Integer;
var
I: Integer;
begin
Result := InsertIndex; // Return position of 1st
if IndexIsValid(InsertIndex) then
begin
for I := 1 to Count do
FEDIDataObjects.Insert(InsertIndex, InternalCreateEDIDataObject);
end
else
Result := AddEDIDataObjects(Count);
end;
procedure TEDIDataObjectGroup.SetEDIDataObject(Index: Integer; EDIDataObject: TEDIDataObject);
begin
if FEDIDataObjects.Count > 0 then
if Index >= 0 then
if Index <= FEDIDataObjects.Count - 1 then
begin
FEDIDataObjects.Item[Index].FreeAndNilEDIDataObject;
FEDIDataObjects[Index] := EDIDataObject;
if FGroupIsParent then
FEDIDataObjects[Index].Parent := Self;
end
else
raise EJclEDIError.CreateFmt(RsEDIError009, [Self.ClassName, IntToStr(Index)])
else
raise EJclEDIError.CreateFmt(RsEDIError008, [Self.ClassName, IntToStr(Index)])
else
raise EJclEDIError.CreateFmt(RsEDIError007, [Self.ClassName, IntToStr(Index)]);
end;
function TEDIDataObjectGroup.GetIndexPositionFromParent: Integer;
var
I: Integer;
ParentGroup: TEDIDataObjectGroup;
begin
Result := -1;
if Assigned(Parent) and (Parent is TEDIDataObjectGroup) then
begin
ParentGroup := TEDIDataObjectGroup(Parent);
for I := 0 to ParentGroup.EDIDataObjectCount - 1 do
if ParentGroup.EDIDataObject[I] = Self then
begin
Result := I;
Break;
end;
end; // if
end;
function TEDIDataObjectGroup.GetCount: Integer;
begin
Result := FEDIDataObjects.Count;
end;
//=== { TEDIObjectListItem } =================================================
constructor TEDIObjectListItem.Create(Parent: TEDIObjectList;
PriorItem: TEDIObjectListItem; EDIObject: TEDIObject = nil);
begin
inherited Create;
FName := '';
FParent := Parent;
FItemIndex := 0;
FEDIObject := EDIObject;
FPriorItem := PriorItem;
FNextItem := nil;
if FPriorItem <> nil then
FItemIndex := FPriorItem.ItemIndex + 1;
{$IFDEF ENABLE_EDI_DEBUGGING}
Inc(Debug_EDIDataObjectListItemsCreated);
{$ENDIF ENABLE_EDI_DEBUGGING}
end;
destructor TEDIObjectListItem.Destroy;
begin
{$IFDEF ENABLE_EDI_DEBUGGING}
Inc(Debug_EDIDataObjectListItemsDestroyed);
{$ENDIF ENABLE_EDI_DEBUGGING}
FPriorItem := nil;
FNextItem := nil;
if FParent.OwnsObjects then
FreeAndNilEDIDataObject;
FEDIObject := nil;
FParent := nil;
inherited Destroy;
end;
procedure TEDIObjectListItem.FreeAndNilEDIDataObject;
begin
FreeAndNil(FEDIObject);
end;
function TEDIObjectListItem.GetIndexPositionFromParent: Integer;
begin
Result := FParent.IndexOf(Self);
end;
//=== { TEDIObjectList } =====================================================
constructor TEDIObjectList.Create(OwnsObjects: Boolean = True);
begin
inherited Create;
FOwnsObjects := OwnsObjects;
FFirstItem := nil;
FLastItem := nil;
FCurrentItem := nil;
FCount := 0;
FOptions := [loAutoUpdateIndexes];
{$IFDEF ENABLE_EDI_DEBUGGING}
Inc(Debug_EDIDataObjectListCreated);
{$ENDIF ENABLE_EDI_DEBUGGING}
end;
destructor TEDIObjectList.Destroy;
begin
{$IFDEF ENABLE_EDI_DEBUGGING}
Inc(Debug_EDIDataObjectListDestroyed);
{$ENDIF ENABLE_EDI_DEBUGGING}
Clear;
inherited Destroy;
end;
procedure TEDIObjectList.Clear;
var
ListItem: TEDIObjectListItem;
TempItem: TEDIObjectListItem;
begin
ListItem := FFirstItem;
while ListItem <> nil do
begin
TempItem := ListItem;
ListItem := ListItem.NextItem;
TempItem.Free;
end;
FFirstItem := nil;
FLastItem := nil;
FCurrentItem := nil;
FCount := 0;
end;
function TEDIObjectList.First(Index: Integer): TEDIObjectListItem;
begin
if Index = 0 then
Result := FFirstItem
else
Result := GetItem(Index);
FCurrentItem := Result;
end;
function TEDIObjectList.Last: TEDIObjectListItem;
begin
FCurrentItem := FLastItem;
Result := FCurrentItem;
end;
function TEDIObjectList.Next: TEDIObjectListItem;
begin
FCurrentItem := FCurrentItem.NextItem;
Result := FCurrentItem;
end;
function TEDIObjectList.Prior: TEDIObjectListItem;
begin
FCurrentItem := FCurrentItem.PriorItem;
Result := FCurrentItem;
end;
function TEDIObjectList.Add(EDIObject: TEDIObject; Name: string): TEDIObjectListItem;
begin
Result := CreateListItem(FLastItem, EDIObject);
Result.Name := Name;
if FLastItem <> nil then
FLastItem.NextItem := Result;
if FFirstItem = nil then
FFirstItem := Result;
FLastItem := Result;
FCurrentItem := Result;
Inc(FCount);
end;
function TEDIObjectList.FindItemByName(Name: string;
StartItem: TEDIObjectListItem): TEDIObjectListItem;
var
ListItem: TEDIObjectListItem;
begin
Result := nil;
if StartItem <> nil then
ListItem := StartItem
else
ListItem := First;
while ListItem <> nil do
begin
if ListItem.Name = Name then
begin
Result := ListItem;
Break;
end;
ListItem := Next;
end;
end;
procedure TEDIObjectList.Insert(InsertIndex: Integer; EDIObject: TEDIObject);
var
ListItem: TEDIObjectListItem;
begin
FCurrentItem := GetItem(InsertIndex);
if FCurrentItem <> nil then
begin
//Link new item
ListItem := CreateListItem(FCurrentItem.PriorItem);
ListItem.NextItem := FCurrentItem;
ListItem.EDIObject := EDIObject;
//Relink current item
if FCurrentItem.PriorItem <> nil then
FCurrentItem.PriorItem.NextItem := ListItem
else
FFirstItem := ListItem;
FCurrentItem.PriorItem := ListItem;
//
FCurrentItem := ListItem;
Inc(FCount);
// Update the indexes starting at the current item.
if loAutoUpdateIndexes in FOptions then
UpdateIndexes(FCurrentItem); //Pass nil to force update of all items
end
else
Add(EDIObject);
end;
function TEDIObjectList.GetItem(Index: Integer): TEDIObjectListItem;
var
I: Integer;
ListItem: TEDIObjectListItem;
begin
Result := nil;
if FCurrentItem <> nil then // Attempt to search from the current item.
begin
if Index = FCurrentItem.ItemIndex then // The index already points to the current item.
Result := FCurrentItem
else
if Index > FCurrentItem.ItemIndex then // Search forward in the list.
begin
I := FCurrentItem.ItemIndex - 1;
ListItem := FCurrentItem;
while ListItem <> nil do
begin
Inc(I);
if I = Index then
begin
Result := ListItem;
Break;
end;
ListItem := ListItem.NextItem;
end;
FCurrentItem := Result;
end
else // if Index < FCurrentItem.ItemIndex then // Search backward in the list.
begin
I := FCurrentItem.ItemIndex + 1;
ListItem := FCurrentItem;
while ListItem <> nil do
begin
Dec(I);
if I = Index then
begin
Result := ListItem;
Break;
end;
ListItem := ListItem.PriorItem;
end;
FCurrentItem := Result;
end;
end
else // No current item was assigned so search from the beginning of the structure.
begin
I := -1;
FCurrentItem := FFirstItem;
ListItem := FFirstItem;
while ListItem <> nil do
begin
Inc(I);
if I = Index then
begin
Result := ListItem;
Break;
end;
ListItem := ListItem.NextItem;
end;
FCurrentItem := Result;
end;
end;
procedure TEDIObjectList.Delete(Index: Integer);
var
ListItem: TEDIObjectListItem;
begin
ListItem := GetItem(Index);
if ListItem <> nil then
begin
Remove(ListItem);
// Update the indexes starting at the current item.
if loAutoUpdateIndexes in FOptions then
UpdateIndexes(FCurrentItem.PriorItem); //Pass nil to force update of all items
end;
end;
procedure TEDIObjectList.Delete(EDIObject: TEDIObject);
begin
Remove(EDIObject);
// Update the indexes starting at the current item.
if loAutoUpdateIndexes in FOptions then
UpdateIndexes(nil); //Pass nil to force update of all items
end;
procedure TEDIObjectList.UpdateIndexes(StartItem: TEDIObjectListItem = nil);
var
I: Integer;
ListItem: TEDIObjectListItem;
begin
if StartItem <> nil then
begin
ListItem := StartItem;
I := StartItem.ItemIndex - 1;
end
else
begin
ListItem := FFirstItem;
I := -1;
end;
while ListItem <> nil do
begin
Inc(I);
ListItem.ItemIndex := I;
ListItem := ListItem.NextItem;
end;
end;
procedure TEDIObjectList.UpdateCount;
var
ListItem: TEDIObjectListItem;
begin
FCount := 0;
ListItem := FFirstItem;
while ListItem <> nil do
begin
ListItem := ListItem.NextItem;
Inc(FCount);
end;
end;
procedure TEDIObjectList.Remove(EDIObject: TEDIObject);
var
ListItem: TEDIObjectListItem;
begin
ListItem := Find(EDIObject);
if ListItem <> nil then
begin
// Remove the item from the list
ListItem := Extract(ListItem);
// Free the list item
FreeAndNil(ListItem);
end;
end;
function TEDIObjectList.Extract(EDIObject: TEDIObject): TEDIObject;
var
ListItem: TEDIObjectListItem;
begin
Result := nil;
ListItem := Find(EDIObject);
if ListItem <> nil then
begin
// Extract the EDI Data Object
Result := ListItem.EDIObject;
ListItem.EDIObject := nil;
// Remove the item from the list
ListItem := Extract(ListItem);
// Free the list item
FreeAndNil(ListItem);
end;
end;
function TEDIObjectList.IndexOf(EDIObject: TEDIObject): Integer;
var
I: Integer;
ListItem: TEDIObjectListItem;
begin
Result := -1;
I := 0;
ListItem := FFirstItem;
while ListItem <> nil do
begin
if ListItem.EDIObject = EDIObject then
begin
FCurrentItem := ListItem;
FCurrentItem.ItemIndex := I;
Result := I;
Break;
end;
ListItem := ListItem.NextItem;
Inc(I);
end;
end;
function TEDIObjectList.GetEDIObject(Index: Integer): TEDIObject;
var
ListItem: TEDIObjectListItem;
begin
Result := nil;
ListItem := GetItem(Index);
if ListItem <> nil then
Result := ListItem.EDIObject;
end;
procedure TEDIObjectList.SetEDIObject(Index: Integer; const Value: TEDIObject);
var
ListItem: TEDIObjectListItem;
begin
ListItem := GetItem(Index);
if ListItem <> nil then
ListItem.EDIObject := Value;
end;
function TEDIObjectList.ReturnListItemsByName(Name: string): TEDIObjectList;
var
ListItem: TEDIObjectListItem;
begin
Result := TEDIObjectList.Create(False);
ListItem := First;
while ListItem <> nil do
begin
if ListItem.Name = Name then
Result.Add(ListItem.EDIObject, ListItem.Name);
ListItem := Next;
end; //while
end;
function TEDIObjectList.IndexOf(Item: TEDIObjectListItem): Integer;
var
I: Integer;
ListItem: TEDIObjectListItem;
begin
Result := -1;
I := 0;
ListItem := FFirstItem;
while ListItem <> nil do
begin
if ListItem = Item then
begin
FCurrentItem := ListItem;
FCurrentItem.ItemIndex := I;
Result := I;
Break;
end;
ListItem := ListItem.NextItem;
Inc(I);
end;
end;
procedure TEDIObjectList.Remove(Item: TEDIObjectListItem);
begin
// Remove the item from the list
Item := Extract(Item);
// Free the list item
FreeAndNil(Item);
end;
function TEDIObjectList.Extract(Item: TEDIObjectListItem): TEDIObjectListItem;
begin
Result := Item;
// Set current item
if Item.NextItem <> nil then
FCurrentItem := Item.NextItem
else
FCurrentItem := Item.PriorItem;
// Extract the item and relink existing items.
if Item.NextItem <> nil then
Item.NextItem.PriorItem := Item.PriorItem;
if Item.PriorItem <> nil then
Item.PriorItem.NextItem := Item.NextItem;
if Item = FFirstItem then
FFirstItem := Item.NextItem;
if Item = FLastItem then
FLastItem := Item.PriorItem;
// Update the count
Dec(FCount);
end;
procedure TEDIObjectList.Add(Item: TEDIObjectListItem; Name: string);
begin
Item.Parent := Self;
Item.Name := Name;
Item.NextItem := nil;
Item.PriorItem := nil;
if FLastItem <> nil then
begin
Item.PriorItem := FLastItem;
FLastItem.NextItem := Item;
end;
if FFirstItem = nil then
FFirstItem := Item;
FLastItem := Item;
FCurrentItem := Item;
Inc(FCount);
end;
function TEDIObjectList.FindEDIObject(EDIObject: TEDIObject): TEDIObject;
var
ListItem: TEDIObjectListItem;
begin
Result := nil;
ListItem := FFirstItem;
while ListItem <> nil do
begin
if ListItem.EDIObject = EDIObject then
begin
FCurrentItem := ListItem;
Result := ListItem.EDIObject;
Break;
end;
ListItem := ListItem.NextItem;
end;
end;
function TEDIObjectList.Find(Item: TEDIObjectListItem): TEDIObjectListItem;
var
ListItem: TEDIObjectListItem;
begin
Result := nil;
ListItem := FFirstItem;
while ListItem <> nil do
begin
if ListItem = Item then
begin
FCurrentItem := ListItem;
Result := ListItem;
Break;
end;
ListItem := ListItem.NextItem;
end;
end;
function TEDIObjectList.Find(EDIObject: TEDIObject): TEDIObjectListItem;
var
ListItem: TEDIObjectListItem;
begin
Result := nil;
ListItem := FFirstItem;
while ListItem <> nil do
begin
if ListItem.EDIObject = EDIObject then
begin
FCurrentItem := ListItem;
Result := ListItem;
Break;
end;
ListItem := ListItem.NextItem;
end;
end;
function TEDIObjectList.IndexIsValid(Index: Integer): Boolean;
begin
Result := False;
if (FCount > 0) and (Index >= 0) and (Index <= FCount - 1) then
Result := True;
end;
function TEDIObjectList.Insert(Item, BeforeItem: TEDIObjectListItem): TEDIObjectListItem;
begin
Result := Item;
if Result = nil then
Result := CreateListItem(BeforeItem, nil);
Result.Parent := Self;
Result.PriorItem := nil;
Result.NextItem := nil;
if BeforeItem <> nil then // Insert item
begin
Result.PriorItem := BeforeItem.PriorItem;
BeforeItem.PriorItem := Result;
if Result.PriorItem <> nil then
Result.PriorItem.NextItem := Result;
Result.NextItem := BeforeItem;
end
else
if FFirstItem <> nil then // Insert as first item
begin
FFirstItem.PriorItem := Result;
Result.NextItem := FFirstItem;
FFirstItem := Result;
end
else
Add(Result); // Add as first item
FCurrentItem := Result;
Inc(FCount);
end;
function TEDIObjectList.Insert(EDIObject, BeforeEDIObject: TEDIObject): TEDIObjectListItem;
var
BeforeItem: TEDIObjectListItem;
begin
BeforeItem := Find(BeforeEDIObject);
Result := CreateListItem(BeforeItem, EDIObject);
Insert(Result, BeforeItem);
end;
function TEDIObjectList.Insert(BeforeItem: TEDIObjectListItem): TEDIObjectListItem;
begin
Result := CreateListItem(BeforeItem, nil);
Insert(Result, BeforeItem);
end;
function TEDIObjectList.Insert(BeforeEDIObject: TEDIObject): TEDIObjectListItem;
begin
Result := Insert(nil, BeforeEDIObject);
end;
//=== { TEDIDataObjectListItem } =============================================
function TEDIDataObjectListItem.GetEDIDataObject: TEDIDataObject;
begin
Result := TEDIDataObject(FEDIObject);
end;
procedure TEDIDataObjectListItem.SetEDIDataObject(const Value: TEDIDataObject);
begin
FEDIObject := Value;
end;
//=== { TEDIDataObjectList } =================================================
function TEDIDataObjectList.CreateListItem(PriorItem: TEDIObjectListItem;
EDIObject: TEDIObject): TEDIObjectListItem;
begin
Result := TEDIDataObjectListItem.Create(Self, PriorItem, EDIObject);
end;
function TEDIDataObjectList.GetEDIDataObject(Index: Integer): TEDIDataObject;
begin
Result := TEDIDataObject(GetEDIObject(Index));
end;
procedure TEDIDataObjectList.SetEDIDataObject(Index: Integer; const Value: TEDIDataObject);
begin
SetEDIObject(Index, Value);
end;
function TEDIObjectList.CreateListItem(PriorItem: TEDIObjectListItem;
EDIObject: TEDIObject = nil): TEDIObjectListItem;
begin
Result := TEDIObjectListItem.Create(Self, PriorItem, EDIObject);
end;
//=== { TEDILoopStack } ======================================================
constructor TEDILoopStack.Create;
begin
inherited Create;
SetLength(FStack, 0);
FFlags := [];
end;
destructor TEDILoopStack.Destroy;
var
I: Integer;
begin
for I := Low(FStack) to High(FStack) do
FStack[I].EDIObject := nil;
SetLength(FStack, 0);
inherited Destroy;
end;
function TEDILoopStack.Debug: string;
var
I: Integer;
begin
Result := 'Loop Stack' + AnsiLineBreak;
for I := 0 to High(FStack) do
Result := Result + FStack[I].SegmentId + ', ' +
FStack[I].OwnerLoopId + ', ' +
FStack[I].ParentLoopId + ', ' +
IntToStr(FStack[I].SpecStartIndex) + AnsiLineBreak;
end;
procedure TEDILoopStack.DoAddLoop(StackRecord: TEDILoopStackRecord;
SegmentId, OwnerLoopId, ParentLoopId: string; var EDIObject: TEDIObject);
begin
if Assigned(FOnAddLoop) then
FOnAddLoop(StackRecord, SegmentId, OwnerLoopId, ParentLoopId, EDIObject);
end;
function TEDILoopStack.GetSafeStackIndex(Index: Integer): Integer;
begin
if Length(FStack) > 0 then
begin
if Index >= Low(FStack) then
begin
if Index <= High(FStack) then
Result := Index
else
Result := High(FStack);
end
else
Result := Low(FStack);
end
else
{$IFNDEF CLR}
raise EJclEDIError.CreateResFmt(@RsEDIError057, [IntToStr(Index)]);
{$ELSE}
raise EJclEDIError.CreateFmt(RsEDIError057, [IntToStr(Index)]);
{$ENDIF ~CLR}
end;
function TEDILoopStack.GetSize: Integer;
begin
Result := Length(FStack);
end;
function TEDILoopStack.Peek: TEDILoopStackRecord;
begin
Result := FStack[High(FStack)];
end;
function TEDILoopStack.Peek(Index: Integer): TEDILoopStackRecord;
begin
if Length(FStack) > 0 then
if Index >= Low(FStack) then
if Index <= High(FStack) then
Result := FStack[Index]
else
raise EJclEDIError.CreateFmt(RsEDIError054, [IntToStr(Index)])
else
raise EJclEDIError.CreateFmt(RsEDIError055, [IntToStr(Index)])
else
raise EJclEDIError.CreateFmt(RsEDIError056, [IntToStr(Index)]);
end;
procedure TEDILoopStack.Pop(Index: Integer);
begin
// Resize loop stack if the index is less than the length
if (Index >= 0) and (Index < Length(FStack)) then
begin
SetLength(FStack, Index);
FFlags := FFlags + [ediStackResized];
end;
end;
function TEDILoopStack.Push(SegmentId, OwnerLoopId, ParentLoopId: string; StartIndex: Integer;
EDIObject: TEDIObject): Integer;
begin
// Add to loop stack
SetLength(FStack, Length(FStack) + 1);
UpdateStackData(SegmentId, OwnerLoopId, ParentLoopId, StartIndex, EDIObject);
Result := High(FStack);
end;
function TEDILoopStack.SetStackPointer(OwnerLoopId,
ParentLoopId: string): Integer;
var
I: Integer;
begin
FFlags := FFlags - [ediStackResized];
FFlags := FFlags - [ediAltStackPointer];
Result := -1; // Entry not found
// Find the loop in the stack
for I := High(FStack) downto 0 do
begin
if (OwnerLoopId = FStack[I].OwnerLoopId) and
(ParentLoopId = FStack[I].ParentLoopId) then
begin
Result := I;
// Pop entries from the stack starting at the index after the found loop
Pop(I + 1);
Break;
end;
end;
// Check if an exact entry was found
if Result = -1 then
begin
// Find the parent loop in the stack
for I := High(FStack) downto 0 do
begin
if (ParentLoopId = FStack[I].ParentLoopId) and
(FStack[I].OwnerLoopId <> NA_LoopId) then
begin
FFlags := FFlags + [ediAltStackPointer];
Result := GetSafeStackIndex(I);
// Pop entries from the stack starting at the index after the found loop
Pop(I + 1);
Break;
end;
end;
end;
end;
procedure TEDILoopStack.UpdateStackData(SegmentId, OwnerLoopId, ParentLoopId: string;
StartIndex: Integer; EDIObject: TEDIObject);
begin
FStack[High(FStack)].SegmentId := SegmentId;
FStack[High(FStack)].OwnerLoopId := OwnerLoopId;
FStack[High(FStack)].ParentLoopId := ParentLoopId;
FStack[High(FStack)].SpecStartIndex := StartIndex;
FStack[High(FStack)].EDIObject := EDIObject;
end;
procedure TEDILoopStack.UpdateStackObject(EDIObject: TEDIObject);
begin
FStack[High(FStack)].EDIObject := EDIObject;
end;
function TEDILoopStack.ValidateLoopStack(SegmentId, OwnerLoopId, ParentLoopId: string;
StartIndex: Integer; EDIObject: TEDIObject): TEDILoopStackRecord;
var
I: Integer;
StackRecord: TEDILoopStackRecord;
begin
if Length(FStack) <= 0 then
// Add entry to stack
Push(SegmentId, OwnerLoopId, ParentLoopId, StartIndex, EDIObject)
else
begin
I := SetStackPointer(OwnerLoopId, ParentLoopId);
if I >= 0 then // Entry found
begin
if ediLoopRepeated in FFlags then
begin
// Get the previous stack record so the repeated loop will not be nested
StackRecord := Peek(I-1);
// In event handler add loop to external data structure since it repeated
// See JclEDI_ANSIX12.TEDITransactionSetDocument class for implementation example.
DoAddLoop(StackRecord, SegmentId, OwnerLoopId, ParentLoopId, EDIObject);
// Update stack object only
UpdateStackObject(EDIObject);
// Debug
// ShowMessage('LoopRepeated');
end
else
if ediAltStackPointer in FFlags then
begin
// Get the previous stack record because the loop
// is not to be nested at the current stack pointer
StackRecord := Peek(I-1);
// In event handler add loop to external data structure since it is new
// See JclEDI_ANSIX12.TEDITransactionSetDocument class for implementation example.
DoAddLoop(StackRecord, SegmentId, OwnerLoopId, ParentLoopId, EDIObject);
// Update stack entry
UpdateStackData(SegmentId, OwnerLoopId, ParentLoopId, StartIndex, EDIObject);
// Debug
// ShowMessage('AltStackPointer');
end
else
if ediStackResized in FFlags then
begin
// Debug
// ShowMessage('Stack Size Decreased');
end
else
begin
// Segment is part of loop
end;
end
else
if I = -1 then // Entry not found.
begin
// In event handler add loop since it is new
StackRecord := Peek;
// In event handler add loop to external data structure since it is new
DoAddLoop(StackRecord, SegmentId, OwnerLoopId, ParentLoopId, EDIObject);
// Add entry to stack
Push(SegmentId, OwnerLoopId, ParentLoopId, StartIndex, EDIObject);
// Debug
// ShowMessage('Stack Size Increased');
end;
end;
Result := Peek;
end;
end.