unit Tags;

interface
uses
  SyncObjs,
  SysUtils;

const
  TAG_FLAG_EXTERNAL = 1;

  BOOL_VALUE_FALSE = 'off';
  BOOL_VALUE_TRUE  = 'on';

type
  TTagType = (ttBOOL=1, ttINT=2, ttLONG=3, ttDOUBLE=4, ttSTRING=5);
  TTagStatus = (tsUNINIT, tsGOOD, tsBAD, tsDELETED);

  TTag = class(TObject)
  protected
    FName: string;
    FStatus: TTagStatus;
    FFlags: Integer;
  public
    constructor Create(const name: string; flags: Integer = 0);virtual;

    function getName: string;
    function getType: TTagType; virtual; abstract;
    function getTypeName: string;
    function getStatus: TTagStatus;
    procedure setStatus(status: TTagStatus);

    function getFlags: Integer;
    procedure setFlags(flags: Integer);

    function getBool: boolean; virtual; abstract;
    function getInt: integer; virtual; abstract;
    function getLong: int64; virtual; abstract;
    function getDouble: double; virtual; abstract;
    function getString: string; virtual; abstract;

    procedure setBool(const value: boolean); virtual; abstract;
    procedure setInt(const value: integer); virtual; abstract;
    procedure setLong(const value: int64); virtual; abstract;
    procedure setDouble(const value: double); virtual; abstract;
    procedure setString(const value: string); virtual; abstract;

    function equalsValue(tag: TTag): Boolean; virtual; abstract;
  end;


  TTagRW = class(TTag)
  protected
    FMonitor: TCriticalSection;
    FValueWrChanged: Boolean;

	  procedure copyLastWriteToRead; virtual; abstract;  // ???
	  procedure copyWriteToLastWrite; virtual; abstract;
	  procedure copyWriteToRead; virtual; abstract;
  public
    constructor Create(const name: string; flags: Integer = 0);override;
    destructor Destroy; override;

    function hasWriteValue: boolean;
    function acceptWriteValue: boolean;
    procedure raiseWriteValue;

    function getWriteValBool: boolean; virtual; abstract;
    function getWriteValInt: integer; virtual; abstract;
    function getWriteValLong: int64; virtual; abstract;
    function getWriteValDouble: double; virtual; abstract;
    function getWriteValString: string; virtual; abstract;

    procedure setReadValBool(const value: boolean); virtual; abstract;
    procedure setReadValInt(const value: integer); virtual; abstract;
    procedure setReadValLong(const value: int64); virtual; abstract;
    procedure setReadValDouble(const value: double); virtual; abstract;
    procedure setReadValString(const value: string); virtual; abstract;

  end;

  function createTagRW(ttype: TTagType; const name: string; flags: integer = 0): TTagRW;


implementation
uses
  TagRWBool,
  TagRWInt,
  TagRWLong,
  TagRWDouble,
  TagRWString;

{ TTag }

constructor TTag.Create(const name: string; flags: Integer);
begin
  FName := name;
  FFlags := flags;
  FStatus := tsGOOD;
end;

function TTag.getName: string;
begin
  Result := FName;
end;


function TTag.getStatus: TTagStatus;
begin
  Result := FStatus;
end;

procedure TTag.setStatus(status: TTagStatus);
begin
  FStatus := status;
end;

function TTag.getFlags: Integer;
begin
  Result := FFlags;
end;

procedure TTag.setFlags(flags: Integer);
begin
  FFlags := flags;
end;

function TTag.getTypeName: string;
begin
  case getType of
  ttBOOL:   result := 'BOOL';
  ttINT:    result := 'INT';
  ttLONG:   result := 'LONG';
  ttDOUBLE: result := 'DOUBLE';
  ttSTRING: result := 'STRING';
  end;
end;


{ TTagRW }

constructor TTagRW.Create(const name: string; flags: Integer);
begin
  inherited Create(name, flags);
  FMonitor := TCriticalSection.Create;
  FValueWrChanged := false;
end;

destructor TTagRW.Destroy;
begin
  FMonitor.Free;
  inherited;
end;


function TTagRW.hasWriteValue: boolean;
begin
  result := false;
  if FValueWrChanged then
  begin
    FMonitor.Enter;
    if FValueWrChanged then begin
      copyWriteToLastWrite;
      Result := true;
    end;
    FMonitor.Leave;
	end;
end;

function TTagRW.acceptWriteValue: boolean;
begin
  result := false;
  if FValueWrChanged then
  begin
    FMonitor.Enter;
    if FValueWrChanged then begin
      copyWriteToLastWrite;
      copyWriteToRead;
      Result := true;
    end;
    FMonitor.Leave;
	end;
end;

procedure TTagRW.raiseWriteValue;
begin
  FMonitor.Enter;
	FValueWrChanged := True;
  FMonitor.Leave;
end;

function createTagRW(ttype: TTagType; const name: string; flags: integer = 0): TTagRW;
begin
  Result := nil;
  Case ttype of
    ttBOOL   : Result := TTagRWBool.Create(name, flags);
    ttINT    : Result := TTagRWInt.Create(name, flags);
    ttLONG   : Result := TTagRWLong.Create(name, flags);
    ttDOUBLE : Result := TTagRWDouble.Create(name, flags);
    ttSTRING : Result := TTagRWString.Create(name, flags);
  end;
end;


end.
