unit Sequenceu;{ ULObjUsr descendant for holding sequence related data }
{
  (C) 2000 - 2001 Jindrich Jindrich, Pavel Pisa, PiKRON Ltd.

  Originators of the CHROMuLAN project:

  Jindrich Jindrich - http://www.jindrich.com
                      http://orgchem.natur.cuni.cz/Chromulan/
                      software developer, project coordinator
  Pavel Pisa        - http://cmp.felk.cvut.cz/~pisa
                      embeded software developer
  PiKRON Ltd.       - http://www.pikron.com
                      project initiator, sponsor, instrument developer

  The CHROMuLAN project is distributed under the GNU General Public Licence.
  See file COPYING for details.

  Originators reserve the right to use and publish sources
  under different conditions too. If third party contributors
  do not accept this condition, they can delete this statement
  and only GNU license will apply.
}


interface
uses
  SysUtils, Messages, Classes, {v0.30} Controls, Forms, XStringGrid,{/v0.30}
  ULRecTyp, ULRecUtl, ULObju, ULFObju, ULObjUsru, {v0.49}ULObjDes,{/v0.49}
  Fileu,
  ULIType, ULIObju, Instrumentu,
  ULMType, ULMObju, Methodu,
  AAPGType, AAPGObju, AAPLType, AAPLObju, AAPrgu,
  ULSQType, ULSQObju,
  ULSRType, ULSRObju,
  {v0.30}
  ULPRType, ULPRObju,
  {/v0.30}

  UlanType, Spectrum, AcqInfou
  {v0.30}, ActnList, Menus, Msgu, ShowMsg, Language, XGridFrm,
    SpecForm{/v0.30}
  {v0.36}
  , ULStringGrid, WinUtl
  {/v0.36}
  {v0.38}
  , Stru
  {/v0.38}
  {v0.41}, Timer, Timersu, UlanGlob, ExeLogu, FileCtrl, Modulu,
    ULADType, ULADObju, SModulu
  {/v0.41}
  {v0.47}
  , ModuUtl, Compareu {winutl}
  {/v0.47}
  {v0.49}
  ,USPType, USPObju
  ,Prgu, SeqPrgu
  {/v0.49}
  {v0.50}
  ,ULAType
{  ULBType, ULBRType,
  ULBObju, ULBRObju, BaseLineu}
   , AnalSetupFrm, ULEdutl
  {/v0.50}
  ;

{urXXXX}
{urSeqXXXX}
const
  urSeq = 9000;
  urSeqMethodExists = urSeq + 1;
  urSeqInstrumentExists = urSeq + 2;
  urSeqPrgExists = urSeq + 3;
  {v0.41}
  urSetSequenceStateInvalid = urSeq + 4;

  urInvalidProgramNoEquil = urSeq + 5;
  urNoSamples = urSeq + 6;
  {/v0.41}
  {v0.51}
  urInvalidProgramFormat = urSeq + 7;
  {/v0.51}
{/urSeqXXXX}
type
  TSequenceResult = integer;

type
  {v0.30}
  TScanReason = (srResultTable, srCalibrationFile, srOpen{v0.38}, srOpenOverlay{/v0.38});
  {/v0.30}

  TSeqSample = class;

  TSequence = class(TULObjUsr) {ulobju ulobjusru}
  private
    FLastSample: TSeqSample;
    FCurSample: TSeqSample;

    FDefMethod: TUlanMethod;
      { default method for new sample }
    FDefInstrument: TInstrument;
      { default instrument for new sample }
    FDefPrg: {v0.49}TPrg{/v0.49 TAAPrg};
      { default program for new sample }
      { ulsqtype }
    {v0.30}
    FMakeTable: TAction;
    FCalibrationFileAssign: TAction;
    FDataFilesOpen: TAction;
    {v0.38}
    FDataFilesOpenOverlay: TAction;
    {/v0.38}
    {v0.50}
    FProcessorActivate: TAction;
    {/v0.50}

    FCurGrid: TXStringGrid;
    FGridValueCaption: string;
    FCurScanULSR: TULSRObj;
    FCurScanAcqData: TAcqData;
    FCurCalibFN: string;
    {/v0.30}
    {v0.38}{ulobju}
    {FDeleteFiles: boolean;}
      { delete files corresponding to deleting ulsr? }
    FCurSpecForm: TSpectrumForm;
    {/v0.38}
    {v0.44}
    FClearSampleErrorAction: TAction;
    {/v0.44}
    {v0.50}
    {FDefBaseLine: TBaseLine;}
    {/v0.50}
    {v0.51}
    FProcessor: TObject;
    {/v0.51}
    {v0.49}
    FDataTemplate: TAcqData;
    function GetSequenceKind: TSequenceKind;
    {/v0.49}
    {v0.50}
    procedure SetSequenceKind(AKind: TSequenceKind);
    function GetDefPrgDir: string;
    function GetDefPrgExt: string;
    function GetDefMethodDir: string;
    function GetDefTemplateDir: string;
    function GetSequencesDir: string;
    {/v0.50}
  protected
    function GetRecID: TULRecID; override;
    function ChildCreate(AChildObj: TULObj): TULObjUsr; override;
    procedure ChildDestroyed(AChild: TULObjUsr); override;
    procedure ClassFieldsCreate; override;

    function GetULSQ: TULSQObj;
    function GetDefMethod: TUlanMethod;
    function GetDefInstrument: TInstrument;
    function GetDefPrg: {v0.49}TPrg{/v0.49 TAAPrg}; {v0.41}virtual;{/v0.41}
    function GetLastSample: TSeqSample;
    function GetCurSample: TSeqSample;
    function GetNextSample: TSeqSample;
    procedure SeqSampleCreated(ss: TSeqSample);
      { update new SeqSample default values }
    function GetDirName: string;{v0.41}virtual;{/v0.41}
    {v0.30}
    procedure MenuActionNeeded;override;
    procedure MakeResultTable(Sender: TObject);
    procedure CalibrationFileAssign(Sender: TObject);
    procedure DataFilesOpen(Sender: TObject);
    {v0.38}
    procedure DataFilesOpenOverlay(Sender: TObject);
    {/v0.38}
    {v0.50}
    procedure ProcessorActivate(Sender: TObject);
    {/v0.50}

    procedure ChildsScan(sr: TScanReason);
      procedure ResultTableAddRow;
      procedure CalibFNAssign;
      procedure DataFileOpen{v0.38}(Aditive:boolean){/v0.38};
    {/v0.30}
    {v0.32}
    procedure FileNameChanged;override;
    {/v0.32}
    {v0.36}{ulobjusru}
    procedure ULGridCreated(AGrid: TULStringGrid); override;
    procedure DoOnDblClick(AGrid: TObject);
    procedure SetCurSample(ASample: TSeqSample);
    {/v0.36}
    {v0.44}
    procedure FirstMenuActionNeeded; override;
    procedure ClearSampleError(Sender: TObject);
    {/v0.44}
    {v0.49}
    function GetPrgRecID: TULRecID; virtual;
    function GetPrgExt: string;
    {procedure DoAfterLoad; override;}{ulobjusru}

    function GetDataTemplateFileName: TFileName;
    procedure SetDataTemplateFileName(const AFileName: TFileName);
    function GetDataTemplate: TAcqData;
    {/v0.49}
    {v0.50}
    procedure FieldDefDirNeeded(AField: TULObjField); override;
    procedure ObjDefDirNeeded;override;
    function GetChannelName: string;
    function GetFixedSequenceName: string;
    {/v0.50}
  public
    destructor Destroy;override;
    procedure UpdateDefDirs; override;
    function First: boolean;
      { select first sample as current }
    function Next: boolean;
      { select next sample as current }
    {v0.36}
    procedure NoSample;
    {/v0.36}
    {v0.50}
    function GetNewSequenceName: string;
    procedure UpdateFileNameFromSequenceName;
    procedure CheckDir;

    {procedure Run;{called by usr to start the sequence}
    {procedure Stop;{called by usr to stop the sequence}
    {/v0.50}
    property ULSQ: TULSQObj read GetULSQ;
    property CurSample: TSeqSample read GetCurSample{v0.36} write SetCurSample{/v0.36};
    property LastSample: TSeqSample read GetLastSample;
    property NextSample: TSeqSample read GetNextSample;
    property DefMethod: TUlanMethod read GetDefMethod;
    property DefInstrument: TInstrument read GetDefInstrument;
    property DefPrg: {v0.49}TPrg{/v0.49 TAAPrg} read GetDefPrg;
    property DirName: string read GetDirName;
      { Default (full) dir for files of samples = dir of .ULS file + SequenceName }
    {v0.49}
    property SequenceKind: TSequenceKind read GetSequenceKind write SetSequenceKind;
    property PrgRecID: TULRecID read GetPrgRecID;
    property PrgExt: string read GetPrgExt;
    property DataTemplateFileName: TFileName read GetDataTemplateFileName write SetDataTemplateFileName;
    property DataTemplate: TAcqData read GetDataTemplate;
    {/v0.49}
    {v0.50}
    property ChannelName: string read GetChannelName;
    property FixedSequenceName: string read GetFixedSequenceName;
    {/v0.50}
    {v0.51}
    property Processor: TObject read FProcessor write FProcessor;
    {/v0.51}
  end;
  {v0.41}
  TSequenceClass = class of TSequence;
  {/v0.41}

  TSeqSample = class(TULObjUsr)
  private
    FInstrument: TInstrument;
    FMethod: TUlanMethod;
    FPrg: {v0.49}TPrg{/v0.49 TAAPrg};
    {v0.50} {ulobjusru}
    function GetSequence: TSequence;
    {/v0.50}
  protected
    function GetULSR: TULSRObj;
    procedure ClassFieldsCreate; override;
    function ChildCreate(AChildObj: TULObj): TULObjUsr; override;
    procedure ChildDestroyed(AChild: TULObjUsr); override;
    function GetRecID: TULRecID; override;
    {v0.50}
    procedure FieldDefDirNeeded(AField: TULObjField); override;
    {/v0.50}
  public
    constructor Create(AOwner: TULObjUsr; AObj: TULObj; ARecID: TULRecID); reintroduce;
    destructor Destroy;override;
    {ulobjusru}
    property ULSR: TULSRObj read GetULSR;
    property Method: TUlanMethod read FMethod;
    property Instrument: TInstrument read FInstrument;
    property Prg: {v0.49}TPrg{/v0.49 TAAPrg} read FPrg;
    {v0.50}
    property Sequence: TSequence read GetSequence;
    {/v0.50}
  end;

(*v0.49*)(*v0.49
{v0.41}
  TSeqFormState = (
    sfsIdle, { nothing to do - does not change the last sample name when set }
    sfsLoadSample, { user should load sample }
    sfsLoaded, { uses is informed that the sample was loaded }
    sfsInjectSample, { user should inject sample }
    sfsInjected,     { uses is informed that the sample was injected }
    sfsLoadAndInjectSample, { user should load and inject sample }
    sfsFinished, { user is informed about sequence finished=completed OK }
    sfsAborted   { user is informed about sequence abortion=failure }
  );

{  TSampleState = (
  );}
  TSequenceState = (
    sesDisconnected, { devices disconnected }
    sesAborted,      { sequence run aborted, devices off }
    sesFinished,     { sequence run finished by processing last sample, devices off }
    sesStandby,      { sequence run not started yet or stopped upon user request, devices off
                       (not finished) }
    sesOff,          { .. not real state, just for comparing, all below = OFF }
    sesStarting,     { sequence run requested, devices preparing for run }
    sesStopping,     { sequence run stopping upon user request, devices stopping }
    sesFinishing,    { sequence run finishing after last sample processed, devices stopping }
    sesAborting,     { sequence run aborting because of error, devices aborting }
    sesReady,        { sequence is ready to run (devices ready), devices ready to run }
    sesStopRunning,  { running, but after processing current sample Stopping will start
                       (user requested stop after current sample) }
    sesRunning       { sequence is running }
    ); { ... same as AAAType.TAAAState }

  TSSequence = class(TSequence) {standalone sequence}
  private
    FLogHead: string;
    {v0.47}{/v0.47
    FAutomatic: boolean;}
      { working with autosampler if true }
    {FDataTemplateFileName: TFileName;}
    FIsInTimer: boolean;

    FSequenceState: TSequenceState;
    FStateStartTime: integer;
    FUsrStateTimeOffset: integer;
    FStateTime: integer;

    FSubState: integer;
    {FSubStateStartTime: integer;
    FUsrSubStateTimeOffset: integer;
    FSubStateTime: integer;}

    FTimerAdded: boolean;

    {FIsFirstSample: boolean;}

    {actions}
    FSequenceRunAction: TAction;
    {FSequenceStopAction: TAction;
    FNulAction: TAction;}
    FPrgEditAction: TAction;
    FMethodEditAction: TAction;
    FDoAcqShowAction: TAction;
    FShowActPrgAction: TAction;
    {/actions}

    FSeqForm: TForm;
      { comunicates with usr }
    FCurPrg: {v0.49}TPrg{/v0.49 TAAPrg};
    FBrowsingCurPrg: {v0.49}TPrg{/v0.49 TAAPrg};{ non nil, if for FCurPrg was called ShowRunning }

    FAcqInfo: TAcqInfo;
    FAcqData: TAcqData;

    FDataTemplate: TAcqData;
    FPump: TPumpModule;
    FPumpTimerLogged: boolean;
    {v0.47}
    FAutoSampler: TAutoSamplerModule;
    FAutoSamplerChecked: boolean;
      { already tried to find autosampler }
    {/v0.47}

    {action handlers}
    procedure SequenceRun(Sender: TObject);
    {procedure SequenceStop(Sender: TObject);}
    procedure PrgEdit(Sender: TObject);
    procedure MethodEdit(Sender: TObject);
    procedure DoAcqShow(Sender: TObject);
    procedure ShowActPrgAction(Sender: TObject);
    {/action handlers}

    procedure SetSequenceState(ASequenceState: TSequenceState);
    procedure TimerAdd;
    procedure TimerDel;

    procedure DoCurSampleSelected;
    procedure CurSampleStateChanged;
    procedure SeqFormFree;
    procedure SeqFormDoTimer;
    procedure SeqFormCheck(sfs: TSeqFormState; const ASampleName: string);
    procedure SetCurPrg(APrg: {v0.49}TPrg{/v0.49 TAAPrg});
    procedure StateStart(ASequenceState: TSequenceState; AUsrTimeOffset: integer);
    function GetDataTemplateFileName: TFileName;
    procedure SetDataTemplateFileName(const AFileName: TFileName);

    procedure DefMethodSetDefaults;
    procedure DefPrgCreateDefault;

    function GetNewSequenceName: string;
    procedure CheckDir;
    procedure OnGetWindowCaption(var ACaption: string);
    procedure ShowRunningPrg;
    function GetDataTemplate: TAcqData;
    function GetSampleToLoad: TSeqSample;
    function GetPump: TPumpModule;
    {v0.47}
    function GetAutoSampler: TAutoSamplerModule;
    function AutoSamplerLoad(AVialNr: integer): boolean;
    function AutoSamplerInject: boolean;
    function GetAutomatic: boolean;
    {/v0.47}
    procedure OnMark(Sender: TObject);
    procedure PumpPrgRun(const msg: string);
    procedure PumpPrgEnd(const msg: string);
    procedure PumpPrgActNrSelect(i:integer);
    procedure PumpStartOrRun(const msg: string);

  protected
    procedure DoAfterCreate; override;
    {v0.49}
    {procedure UpdateDefDirs; override;}
    procedure CheckDefPrg;
    {/v0.49}

    procedure ClassFieldsCreate; override;
    procedure DoTimer(Sender: TObject);{register in timersu}
      procedure DoTimerRunningStopRunning;


    procedure FirstMenuActionNeeded; override;{ulobjusru}
    procedure Log(const msg: string);
    procedure LogState(const msg: string);
    procedure ObjUpdated; override;
    function CheckCurSample: boolean;
    function FirstSampleRun: TSequenceResult;{ulantype}


    function AcqEquilStart: boolean;
    procedure AcqEquilStop;

    function AcqGetReady: boolean;
    function AcqInfoCreate: boolean;
    function AcqStart: boolean;
    procedure AcqDoTimer;
    procedure AutoSaveAll;
    procedure AcqShow;
    procedure AcqDataUpdateViewLimit;
    procedure AcqStop;

    procedure DoLoadSample;
    procedure DoInjectSample;

    function GetDirName: string;override;
    function GetDefPrg: {v0.49}TPrg{/v0.49 TAAPrg}; override;

    function GetSequenceStateStr(ASequenceState:TSequenceState): string;
    function SequenceStateStr: string;
    {v0.49}
    {function GetPrgRecID: TULRecID; override;}
    procedure DoAfterLoad; override;
    {/v0.49}
  public
    constructor Load(const AFileName: string); override;
    destructor Destroy; override;
    procedure FileNew; override;

    procedure DoOK;
      { called from SeqForm when it's OK button pressed }
      procedure DoConfirm;
        { called either from DoOK or from OnMark }
    procedure DoCancel;
      { called from SeqForm when it's Cancel button pressed }


    property SequenceState: TSequenceState read FSequenceState write SetSequenceState;
    property CurPrg: {v0.49}TPrg{/v0.49 TAAPrg} read FCurPrg write SetCurPrg;
    property DataTemplateFileName: TFileName read GetDataTemplateFileName write SetDataTemplateFileName;
    property LogHead: string read FLogHead write FLogHead;
    property Automatic: boolean read {v0.47}GetAutomatic{/v0.47 FAutomatic write FAutomatic};
    property DataTemplate: TAcqData read GetDataTemplate;{set just through DataTemplateFileName}
    property Pump: TPumpModule read GetPump;
    {v0.47}
    property AutoSampler: TAutoSamplerModule read GetAutoSampler;
    {/v0.47}
  end;
  TSSequenceClass = class of TSSequence;

{const
  IsAAASequence: boolean = false;}
{/v0.41}
*)

{v0.32}
function SequenceBrowserOpen(const AFileName: shortstring; AMode: TOpenMode): boolean;
{/v0.32}

implementation
{v0.50}
uses AAAu{v0.50}, Processoru{/v0.50};
{/v0.50}
{v0.41}
{v0.49}{/v0.49
uses SeqFrm;}
{/v0.41}

{TSequence}
function TSequence.GetRecID: TULRecID;
begin
  Result := ULSQID;
end;

procedure TSequence.UpdateDefDirs;
var
  c: TULObjUsr;
  i: integer;
begin
  {v0.49}
  if SequenceKind = skStandalone then begin
{    DefPrg.Obj.ObjDesc.DefDir := ulanglob.PrgsDir;}
  end;
  {/v0.49}

  Obj.FindField('PrgFileName').FldDesc.DefDir := DefPrg.Obj.ObjDesc.DefDir;{AO.PrgsDir;}
  Obj.FindField('MethodFileName').FldDesc.DefDir := DefMethod.Obj.ObjDesc.DefDir;{AO.MethodsDir;}
  {v0.41}
  Obj.FindField('DataTemplateFileName').FldDesc.DefDir := ulanglob.TemplateDir;
  {/v0.41}{ulsqtype}
  for i := 0 to ChildCount - 1 do begin
    c := Childs[i];
    if c is TSeqSample then with c as TSeqSample do begin
      ULSR.FindField('PrgFileName').FldDesc.DefDir := DefPrg.Obj.ObjDesc.DefDir;
      ULSR.FindField('MethodFileName').FldDesc.DefDir := DefMethod.Obj.ObjDesc.DefDir;
      break;
    end;
  end;
end;


{v0.50}
function TSequence.GetDefPrgDir: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAA.AO.PrgsDir;{aaatype}
  end else begin
    Result := ulanglob.PrgDir;
  end;
end;
function TSequence.GetDefPrgExt: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAPGExt;{aapgtype}
  end else begin
    Result := USPExt;{usptype}
  end;
end;

function TSequence.GetDefMethodDir: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAA.AO.MethodsDir;{aaatype}
  end else begin
    Result := ulanglob.MethodDir;
  end;
end;


function TSequence.GetDefTemplateDir: string;
begin
  Result := ulanglob .TemplateDir;
end;

function TSequence.GetSequencesDir: string;
begin
  if (SequenceKind = skAAA) then begin
    Result := AAA.AO.SeqsDir;{aaatype}
  end else begin
    Result := ulanglob.SequenceDir;
  end;
end;

procedure TSequence.FieldDefDirNeeded(AField: TULObjField);
var
  fn: string;
  fd: TULObjFldDesc;
begin
  fd := AFIeld.FldDesc;
  fn := fd.Name;
  if fn = 'PrgFileName' then begin
    fd.DefDir := GetDefPrgDir;
    fd.DefExt := GetDefPrgExt;
  end else if fn = 'MethodFileName' then begin
    fd.DefDir := GetDefMethodDir;
  end else if fn = 'DataTemplateFileName' then begin
    fd.DefDir := GetDefTemplateDir;
  end;
end;

procedure TSequence.ObjDefDirNeeded;
begin
  Obj.ObjDesc.DefDir := GetSequencesDir;{ulanglob}
end;
{/v0.50}

procedure TSequence.ClassFieldsCreate;
begin
  inherited;
  {v0.25}
  {v0.36}
  CurSample := nil;
  {/v0.36 FCurSample := nil;}
  FLastSample := nil;
  {/v0.25
  FLastSampleIndex := -1;
  FCurSampleIndex := -1;}
  {FDefMethod := TUlanMethod}
  (ChildFindOrAdd(ULMID, ''));
  {FDefInstrument := TInstrument}
  (ChildFindOrAdd(ULIID, ''));
  {FDefPrg := TAAPrg}
  (ChildFindOrAdd({v0.49}GetPrgRecID{/v0.49 AAPGID}, ''));
  UpdateDefDirs;
end;

function TSequence.GetDefMethod: TUlanMethod;
begin
  if FDefMethod = nil then
    FDefMethod := TUlanMethod(ChildFindOrAdd(ULMID, ''));
  Result := FDefMethod;
end;

function TSequence.GetDefInstrument: TInstrument;
begin
  if FDefInstrument = nil then
    FDefInstrument := TInstrument(ChildFindOrAdd(ULIID, ''));
  Result := FDefInstrument;
end;

function TSequence.GetDefPrg: {v0.49}TPrg{/v0.49 TAAPrg};
begin
  if FDefPrg = nil then begin
    {v0.49}
    FDefPrg := TPrg(ChildFindOrAdd(GetPrgRecID, ''));
    {/v0.49
    FDefPrg := TAAPrg(ChildFindOrAdd(AAPGID, ''));}
    {v0.41}
    FDefPrg.Obj.SetFlag(rfAskForSave, true);
    {/v0.41}
  end;
  Result := FDefPrg;
end;

procedure TSequence.ChildDestroyed(AChild: TULObjUsr);
begin
  if AChild = FDefMethod then
    FDefMethod := nil
  else if AChild = FDefInstrument then
    FDefInstrument := nil
  else if AChild = FDefPrg then
    FDefPrg := nil;
  {v0.25}
  if AChild = FCurSample then begin
    {v0.36}
    CurSample := nil;
    {/v0.36 FCurSample := nil;}
  end else if AChild = FLastSample then
    FLastSample := nil;
  {/v0.25}
  {v0.50}
{  if AChild = FDefBaseLine then
    FDefBaseLine := nil;}
  {/v0.50}
end;

procedure TSequence.SeqSampleCreated(ss: TSeqSample);
var
  sn, vn: integer;
  i: integer;
{  fn: string;}
{  seqn: string;}
  ou: TULObjUsr;
begin
  if ss.ULSR.PrgFileName = '' then begin
    ss.ULSR.PrgFileName := ULSQ.PrgFileName;
    ss.Prg.Obj.Assign(DefPrg.Obj);
  end;

  if ss.ULSR.MethodFileName = '' then begin
    ss.ULSR.MethodFileName := ULSQ.MethodFileName;
    ss.Method.Obj.Assign(DefMethod.Obj);
  end;

  if ss.ULSR.SampleState = sasWaiting then
    ss.Instrument.Obj.Assign(DefInstrument.Obj);{methodu instrumentu}

  if ss.ULSR.VialNr = 0 then begin
    sn := 0;
    vn := 0;
    for i := 0 to ChildCount - 1  do begin
      ou := Childs[i];
      if ou is TSeqSample then with ou as TSeqSample do begin
        if ou <> ss then begin
          sn := ULSR.SampleNr;
          vn := ULSR.VialNr; {ulsrtype}
        end;
      end;
    end;
    inc(sn);
    inc(vn);
                                                                            
    ss.ULSR.FileName := 'Sample' + {v0.38} LZero(IntToStr(sn), 3){/v0.38 IntToStr(sn)};
    {v0.52}
    if ss.ULSR.SampleName = '' then
      ss.ULSR.SampleName := ss.ULSR.FileName;
    {/v0.52}
    ss.ULSR.VialNr := vn;
    ss.ULSR.SampleNr := sn;
  end;

  ss.ULSR.FindField('MethodFileName').FldDesc.DefDir := DefMethod.Obj.ObjDesc.DefDir;
  ss.ULSR.FindField('PrgFileName').FldDesc.DefDir := DefPrg.Obj.ObjDesc.DefDir;
end;{ulsrobju}


function TSequence.GetDirName: string;
{v0.50}
begin
{/v0.50
var
  n: string;
  i: integer;
begin
  n := ULSQ.SequenceName;
  for i := 1 to length(n) do begin
    if n[i] in [':',',','/','\','?'] then
      n[i] := '_';
  end; }
  Result := AddBackSlash(ULSQ.RootFileDir) + {v0.50}FixedSequenceName{/v0.50 n} + '\';
end;

{v0.50}
function TSequence.GetFixedSequenceName: string;
var
  i: integer;
begin
  Result := ULSQ.SequenceName;
  for i := 1 to length(Result) do begin
    if Result[i] in [':',',','/','\','?'] then
      Result[i] := '_';
  end;
end;

procedure TSequence.UpdateFileNameFromSequenceName;
begin
  FileName := AbsoluteFileName(Obj.ObjDesc.DefDir, FixedSequenceName, ULSExt);
{  FileName := ReplaceExt(DelBackSlash(DirName), ULSExt);}
end;

{v0.49}
{function TSequence.PrgCreate: TPrg;
begin

end;}
{/v0.49}

function TSequence.ChildCreate(AChildObj: TULObj): TULObjUsr;
var
  id:TULRecID;
  ss: TSeqSample;
begin
  Result := nil;
  if AChildObj = nil then begin
    id := ULSRID
  end else begin
    id := AChildObj.RecID;
  end;

  case id of
    ULSRID: begin
      ss := TSeqSample.Create(Self, AChildObj, id);
      Result := ss;
      SeqSampleCreated(ss);
    end;
    ULMID: begin
      Result := TUlanMethod.Create(Self, AChildObj, id);
      if (FDefMethod = nil) then begin
        {SetResult(urSeqMethodExists, '');}
        FDefMethod := TUlanMethod(Result);
      end;
    end;
    ULIID: begin
      Result := TInstrument.Create(Self, AChildObj, id);
      if FDefInstrument = nil then begin
        {SetResult(urSeqInstrumentExists, '');}
        FDefInstrument := TInstrument(Result);
      end;
    end;
    AAPGID: begin
      Result := TAAPrg.Create(Self, AChildObj, id);
      if FDefPrg = nil then begin
        {SetResult(urSeqPrgExists, '');}
        FDefPrg := {v0.49}TPrg{/v0.49 TAAPrg}(Result);
      end;
    end;
    {v0.49}
    USPID: begin
      Result := TSeqPrg.Create(Self, AChildObj, id);
      if FDefPrg =  nil then begin
        FDefPrg := TPrg(Result);
      end;
    end;
    {/v0.49}
    {v0.50}
    {ULBID: begin
      Result := TBaseLine.Create(Self, AChildObj, id);
      if FDefBaseLine = nil then begin
        FDefBaseLine := TBaseLine(Result);
      end;
    end;}
    {/v0.50}
  else
    SetResult(urUnknownChildRecID, ULRecIDToStrStrip(id));{ulrecutl}
  end;
end;

function TSequence.GetULSQ;
begin
  Result := TULSQObj(Obj);
end;

destructor TSequence.Destroy;
begin
  {v0.49}
  FDataTemplate.Free;
  {/v0.49}
  {v0.51}
  if FProcessor <> nil then begin
    TProcessor(FProcessor).Sequence := nil;
    FProcessor := nil;
  end;
  {/v0.51}
  inherited Destroy;
end;

function TSequence.GetCurSample: TSeqSample;
{var c: TULObjUsr;}
begin
  {v0.25}
  Result := FCurSample;
  {/v0.25
  Result := nil;
  if (FCurSampleIndex >= 0) and (FCurSampleIndex < ChildCount) then begin
    c := Childs[FCurSampleIndex];
    if c is TSeqSample then
      Result := TSeqSample(c);
  end;}
end;

function TSequence.GetLastSample: TSeqSample;
{v0.25}{/v0.25 var c: TULObjUsr;}
begin
  {v0.25}
  Result := FLastSample;
  {/v0.25
  Result := nil;
  if (FLastSampleIndex >= 0) and (FLastSampleIndex < ChildCount) then begin
    c := Childs[FLastSampleIndex];
    if c is TSeqSample then
      Result := TSeqSample(c);
  end;}
end;

function TSequence.GetNextSample: TSeqSample;
var
  i: integer;
  s: TSeqSample;
begin
  Result := nil;
  {v0.25}
  i := ChildList.IndexOf(FCurSample) + 1;
  {/v0.25
  i := FCurSampleIndex + 1;}
  if i < 0 then
    exit;
  while i < ChildCount do begin
    if Childs[i] is TSeqSample then begin
      s := TSeqSample(Childs[i]);{ulsrtype}
      if (s.ULSR.SampleState = sasWaiting) or (s.ULSR.SampleState = sasInLoop) then begin
        Result := s;
        exit;
      end;
    end;
    inc(i);
  end;
end;

function TSequence.First: boolean;
  { select first sample as current }
begin
  {v0.25}
  {v0.36}
  CurSample := nil;
  {/v0.36 FCurSample := nil;}
  FLastSample := nil;
  {/v0.25
  FCurSampleIndex := -1;
  FLastSampleIndex := -1;}
  Result := Next;
end;

function TSequence.Next: boolean;
      { select next sample as current }
var s: TSeqSample;
begin
  s := NextSample;
  {v0.25}
  {v0.36}{/v0.36
  if FCurSample <> nil then begin
    FCurSample.Obj.SetFlag(rfCantDelete, false);
  end;}
  FLastSample := FCurSample;
  {/v0.25
  FLastSampleIndex := FCurSampleIndex;}
  if s <> nil then begin
    {v0.25}
    FCurSample := s;
    {v0.36}{/v0.36
    FCurSample.Obj.SetFlag(rfCantDelete, true);}
    {/v0.25
    FCurSampleIndex := ChildList.IndexOf(s);}
    Result := true;
  end else begin
    Result := false;
    {v0.36}
    CurSample := nil;
    {/v0.36}
  end;
end;

{v0.30}
procedure TSequence.MenuActionNeeded;
var
  s: string;
  o: TULObj;
begin
  s := GetTxt({#}'all');
  if Obj.ChildWithFlagCount(rfSelected) > 0 then begin
    s := GetTxt({#}'selected')
  end else begin
    if not Obj.FindObj(ULSRID, foChilds, '', o) then
      exit;
  end;

  if FMakeTable = nil then begin
    FMakeTable := TAction.Create(Self);
    FMakeTable.OnExecute := MakeResultTable;
  end;
  FMakeTable.Caption := GetTxt({#}'Show results for') + ' ' + s;
  Obj.MenuActionAdd(FMakeTable);

  if FCalibrationFileAssign = nil then begin
    FCalibrationFileAssign := TAction.Create(Self);
    FCalibrationFileAssign.OnExecute := CalibrationFileAssign;
  end;
  FCalibrationFileAssign.Caption := GetTxt({#}'Assign calib.file to') + ' ' + s;
  Obj.MenuActionAdd(FCalibrationFileAssign);

  if FDataFilesOpen = nil then begin
    FDataFilesOpen := TAction.Create(Self);
    FDataFilesOpen.OnExecute := DataFilesOpen;
  end;
  FDataFilesOpen.Caption := GetTxt({#}'Open window for') + ' ' + s;
  Obj.MenuActionAdd(FDataFilesOpen);

  {v0.38}
  if FDataFilesOpenOverlay = nil then begin
    FDataFilesOpenOverlay := TAction.Create(Self);
    FDataFilesOpenOverlay.OnExecute := DataFilesOpenOverlay;
  end;
  FDataFilesOpenOverlay.Caption := GetTxt({#}'Open') + ' ' + s + ' ' +
    GetTxt('in one window');
  Obj.MenuActionAdd(FDataFilesOpenOverlay);
  {/v0.38}
end;

procedure TSequence.DataFileOpen{v0.38}(Aditive:boolean);{/v0.38}
begin
  if FileExists(FCurScanAcqData.ULF.FileName) then begin
    {v0.38}
    if Aditive then begin
      if FCurSpecForm = nil then
        FCurSpecForm := CreateSpectrumForm(FCurScanAcqData.ULF.FileName, omRead)
      else
        FCurSpecForm.AddDataFile(FCurScanAcqData.ULF.FileName);
    end else
    {/v0.38}
    begin
      {v0.38} FCurSpecForm := {/v0.38} CreateSpectrumForm(FCurScanAcqData.ULF.FileName, omRead);
    end;
  end;
  {specform}
end;

procedure TSequence.CalibFNAssign;
var ad: TAcqData;
begin
  ad := FCurScanAcqData;
  ad.CalibrationFileSelect(FCurCalibFN);{spectrum}
end;

procedure TSequence.ResultTableAddRow;
var
  r, c, pc, pi: integer;
{  pn: string;}

  ppn: string;
  pv: string;

  p: TULPRObj;

  ad: TAcqData;
  ulsr: TULSRObj;
  xg: TXStringGrid;
  sp: TSpectrum;

  procedure ColFind(const n: string; var col: integer);
  var
    i: integer;
    s: string;
  begin
    for i := 1 to xg.ColCount - 1 do begin
      s := xg.Cells[i, 0];
      if s = '' then begin
        xg.Cells[i, 0] := n;
        col := i;
        exit;
      end else if s = n then begin
        col := i;
        exit;
      end;
    end;
    xg.ColCount := xg.ColCount + 1;
    col := xg.ColCount - 1;
    xg.Cells[col, 0] := n;
  end;

  procedure RowFind(var row: integer);
  var i: integer;
  begin
    row := -1;
    for i := 0 to xg.RowCount - 1 do begin
      if i > 0 then begin
        if xg.Cells[0, i] = '' then begin
          row := i;
          break;
        end;
      end;
    end;
    if row = -1 then begin
      xg.RowCount := xg.RowCount + 1;
      row := xg.RowCount - 1;
    end;
    xg.Cells[0, row] := ChangeFileExt(ulsr.FileName,'');
  end;

begin
  ad := FCurScanAcqData;
  ulsr := FCurScanULSR;
  xg := FCurGrid;

 {ResultTableValueName[ord(ULSQ.ResultTableValue)]}

  if ad.ULA.AutodetectLater then begin
    try
      sp := TSpectrum.Create(ad);
      try
        try
          sp.AutoDetect;
        except
        end;
      finally
        sp.Free;
      end;
    except;
    end;
  end;

  RowFind(r);
  pc := ad.ULP.ChildCount;
  if pc > (xg.ColCount - 1) then
    xg.ColCount := pc + 1;

  ppn := ResultTableValueName[ULSQ.ResultTableValue];
  for pi := 0 to pc - 1 do begin
    p := TULPRObj(ad.ULP.Childs[pi]);
    if p.RecID = ULPRID then begin
      ColFind(p.PeakName, c);            {ulsqobju uledfrm aapltype}
      if FGridValueCaption = '' then begin
        FGridValueCaption := p.FindField(ppn).FldDesc.Caption;
      end;
      pv := p.FindField(ppn).AsUsrString;
      xg.Cells[c, r] := pv;{FloatToStrF(pv, ffGeneral, 7, 4);}
    end;
  end;
end;

procedure TSequence.ChildsScan(sr: TScanReason);
var
  i: integer;
  fl: TULRecFlags;
  o: TULObj;
  ad: TAcqData;
  releaseData: boolean;
  fn: string;
  frm: TForm;
begin
  i := -1;
  {v0.38}
  FCurSpecForm := nil;
  {/v0.38}
  if Obj.ChildWithFlagCount(rfSelected) > 0 then
    fl := rfSelected
  else
    fl := 0;
  while Obj.ChildWithFlagNext(fl, i) do begin
    o := Obj.Childs[i];
    if o.RecID = ULSRID then begin
      FCurScanULSR := TULSRObj(o);
      try
        releaseData:= true;
        fn := ChangeFileExt(DirName + FCurScanULSR.FileName, ULFExt);
        {v0.31}
        case sr of
          srResultTable, srOpen {v0.38},srOpenOverlay{/v0.38}: begin
            if not FileExists(fn) then
              continue;
          end;
        end;
        {/v0.31}

        {v0.33}
        case sr of
          srOpen{v0.38}, srOpenOverlay{/v0.38}: begin
            ad := TAcqData.Create(fn, omRead);
          end;
        else
          if not FindOpenedData(fn, ad {v0.36}, frm{/v0.36}) then begin
            ad := TAcqData.Create(fn, omRead);
          end else begin
            releaseData := false;
          end;
        end;
        {/v0.33
        ad := TAcqData.Create(fn, omRead);}
        try
          FCurScanAcqData := ad;
          case sr of
            srResultTable: ResultTableAddRow;
            srCalibrationFile: CalibFNAssign;
            srOpen: DataFileOpen{v0.38}(false){/v0.38};
            {v0.38}
            srOpenOverlay: DataFileOpen(true);
            {/v0.38}
          end;
        except
          { ignore adddata failure }
        end;
        FCurScanAcqData := nil;
        if releaseData then begin
          ad.Free;
        end;
      except
        { ignore one datafile read failure }
        {if releaseData then begin
          ad.Free;
          ad := nil;
        end;}
      end;
    end;
  end;
end;

procedure TSequence.DataFilesOpen(Sender: TObject);
begin
  ChildsScan(srOpen);
end;

{v0.38}
procedure TSequence.DataFilesOpenOverlay(Sender: TObject);
begin
  ChildsScan(srOpenOverlay);
end;
{/v0.38}

procedure TSequence.CalibrationFileAssign(Sender: TObject);
var fn: string;
begin
  {ulobju}
  fn := '';
  if FileNameOpenSelect(fn, GetTxt({#}'Select calibration file'),
    CalibrationFileFilter, DirName) then
  begin
    FCurCalibFN := fn;
    try
      ChildsScan(srCalibrationFile);
    finally
      FCurCalibFN := '';
    end;
    {specform}
  end;
end;

procedure TSequence.MakeResultTable(Sender: TObject);
var
  f: TXGridForm;
{  i: integer;}
  ok: boolean;
begin
  ok := false;
  FGridValueCaption := '';
  f := TXGridForm.Create(Application);
  try
    f.Caption := ChangeFileExt(FileName, '') + ' ' + GetTxt({#}'Results Table');
    FCurGrid := f.Grid;
    try
      ChildsScan(srResultTable);
    finally
      FCurGrid := nil;
    end;
    ok := true;
    if f.Grid.RowCount > 1 then begin
      f.Grid.FixedRows := 1;
    end else begin
      ok := false;
    end;
    if f.Grid.ColCount > 1 then begin
      f.Grid.FixedCols := 1;
    end else begin
      ok := false;
    end;
    f.Grid.RemoveEmptyColsRows;
  finally
    if ok then begin
      f.Grid.Cells[0,0] := FGridValueCaption;
      f.Show
    end else begin
      f.Free;
      (*ShowMessage(GetTxt({#}'No data found'), smError, 0);*)
    end;
  end
end;
{/v0.30}

{v0.32}
procedure TSequence.FileNameChanged;
begin
  if ULSQ <> nil then
    ULSQ.SequenceName := ChangeFileExt(ExtractFileName(FileName), '');
end;
{/v0.32}

{v0.36}{ulobjusru}
procedure TSequence.ULGridCreated(AGrid: TULStringGrid);
begin
  inherited;
  AGrid.OnDblClick := DoOnDblClick;
end;

procedure TSequence.DoOnDblClick(AGrid: TObject);
var
  o: TULObj;
  fn: string;
  d: TAcqData;
  f: TForm;
begin
  if not (AGrid is TULStringGrid) then
    exit;
  {ulstringgrid}
  o := TULStringGrid(AGrid).CurChild;
  if o is TULSRObj then with o as TULSRObj do begin
    fn := AbsoluteFileName(DirName, FileName, ULFExt);
    if FindOpenedData(fn, d, f) then begin
      f.BringToFront;
    end else begin
      if FileExists(fn) then
        CreateSpectrumForm(fn, omRead);
    end;
  end;
end;

procedure TSequence.NoSample;
begin
  CurSample := nil;
  FLastSample := nil;
end;

procedure TSequence.SetCurSample(ASample: TSeqSample);
begin
  if FCurSample = ASample then
    exit;
  if FCurSample <> nil then begin
    FCurSample.Obj.SetFlag(rfWriteLocked, false);
    FCurSample.Obj.SetFlag(rfCantDelete, false);
  end;
  FCurSample := ASample;
  if FCurSample <> nil then begin
    FCurSample.Obj.SetFlag(rfWriteLocked, true);{disable for usr}
    FCurSample.Obj.SetFlag(rfCantDelete, true);
  end;
end;
{/v0.36}

{v0.44}
procedure TSequence.FirstMenuActionNeeded;

  {procedure ActionUpdate(var AAction: TAction; ANotifyEvent: TNotifyEvent; const ACaption: string);
  begin
    if AAction = nil then begin
      AAction := TAction.Create(Self);
      AAction.OnExecute := ANotifyEvent;
    end;
    AAction.Caption := ACaption;
    Obj.MenuActionAdd(AAction);
  end;}

  procedure AddClearError;
  {var sr: TULSRObj;}
  begin
    {sr := TULSRObj(Obj.ActiveChild);}
    ActionUpdate(FClearSampleErrorAction, ClearSampleError, GetTxt({#}'Clear Sample Error'));
  end;

begin
{ulstringgrid  s := GetTxt('all');
  if Obj.ChildWithFlagCount(rfSelected) > 0 then begin
    s := GetTxt('selected')
  end else begin
    if not Obj.FindObj(ULSRID, foChilds, '', o) then
      exit;
  end; }
  if SequenceKind = skStandalone then
    ActionUpdate(FProcessorActivate, ProcessorActivate, GetTxt({#}'Activate processing'));
  AddClearError;
end;

procedure TSequence.ClearSampleError(Sender: TObject);
begin
  if Obj.ActiveChild is TULSRObj then with Obj.ActiveChild as TULSRObj do begin
    if SampleState = sasError then
      SampleState := sasWaiting;
  end;
    {ulsrtype}
end;
{/v0.44}

{v0.49}
function TSequence.GetPrgRecID: TULRecID;
begin
  case SequenceKind of
     skAAA: Result := AAPGID;
  else
    Result := USPID;
  end;
end;

function TSequence.GetPrgExt: string;
begin
  Result := ULRecDefFileExt(GetPrgRecID);
  {ulrecutl}
end;

{v0.49}
procedure TSequence.SetSequenceKind(AKind: TSequenceKind);
var
  ss: TSeqSample;
  i: integer;
begin
  {v0.50}
  if ULSQ.SequenceKind = AKind then
    exit;
  ULSQ.SequenceKind := AKind;

  DefPrg.Obj.Free;
  ClassFieldsCreate;

  for i := 0 to ChildCount - 1 do begin
    if Childs[i] is TSeqSample then begin
       ss := TSeqSample(Childs[i]);
       ss.FPrg.Obj.Free;
       ss.ClassFieldsCreate;{ulobjusru}
    end;
  end;
  {/v0.50
  ULSQ.SequenceKind := AKind;}
end;

function TSequence.GetSequenceKind: TSequenceKind;
begin
  Result := ULSQ.SequenceKind;
end;
{/v0.49}


{v0.50}
function TSequence.GetNewSequenceName: string;
var
  d: string;
  n: string;
  i: integer;
begin
  Obj.DefDirNeeded;
  n := FormatDateTime('yymmdd', Now);
  i := 1;
  repeat {ulsqtype}
    d := n + '-' + IntToStr(i);
    if not DirectoryExists(AddBackSlash(Obj.ObjDesc.DefDir) + d) then begin
      break;
    end;
    inc(i);
  until false;
  Result := d;
end;

function TSequence.GetChannelName: string;
begin
  Result := DataTemplate.ULI.ChannelName;{spectrum}
end;

procedure TSequence.ProcessorActivate(Sender: TObject);
var p: TProcessor;
begin
  p := Processors.ProcessorGet(ChannelName);
  p.Sequence := Self;
  if Processor = p then
    p.FormShow;
end;
{/v0.50}

{/TSequence.}


{TSeqSample}
constructor TSeqSample.Create(AOwner: TULObjUsr; AObj: TULObj; ARecID: TULRecID);
begin
  inherited Create(AOwner, AObj, ARecID);
end;

procedure TSeqSample.ClassFieldsCreate;
{v0.49}
var fd: TULObjFldDesc;
{/v0.49}
begin
  inherited; {ulfobju}
  ChildFindOrAdd(ULMID, '');
  ChildFindOrAdd(ULIID, '');{ulobjusru}
  {v0.49}
  ChildFindOrAdd(Sequence.GetPrgRecID, '');
  fd := Obj.FindField('PrgFileName').FldDesc;{ulsrtype}
  if TSequence(ULObjOwner).GetPrgRecID = USPID then begin
    fd.Filter := USPFilter;
    fd.DefDir := ulanglob.PrgDir;
  end;
  {/v0.49
  ChildFindOrAdd(AAPGID, '');}
end;

function TSeqSample.GetRecID: TULRecID;
begin
  Result := ULSRID;
end;

function TSeqSample.ChildCreate(AChildObj: TULObj): TULObjUsr;
var
  id:TULRecID;
begin
  Result := nil;
  id := 0;
  if AChildObj = nil then begin
    SetResult(urUnknownChildRecID, '');
  end else begin
    id := AChildObj.RecID;
  end;

  case id of
    ULMID: begin
      Result := TUlanMethod.Create(Self, AChildObj, id);
      if (FMethod = nil) then begin
        FMethod := TUlanMethod(Result);
      end;
      Result := FMethod;
    end;
    ULIID: begin
      Result := TInstrument.Create(Self, AChildObj, id);
      if FInstrument = nil then begin
        FInstrument := TInstrument(Result);
      end;
    end;
    AAPGID: begin
      Result := TAAPrg.Create(Self, AChildObj, id);{aaprgu}
      if FPrg = nil then begin
        FPrg := {v0.49}TPrg{/v0.49 TAAPrg}(Result);
      end;
    end;
    {v0.49}
    USPID: begin
      Result := TSeqPrg.Create(Self, AChildObj, id);
      if FPrg = nil then begin
        FPrg := TPrg(Result);
      end;
    end;
    {/v0.49}
  else
    SetResult(urUnknownChildRecID, ULRecIDToStrStrip(id));{ulrecutl}
  end;
end;

procedure TSeqSample.ChildDestroyed(AChild: TULObjUsr);
begin
  if AChild = FMethod then
    FMethod := nil
  else if AChild = FInstrument then
    FInstrument := nil
  else if AChild = FPrg then
    FPrg := nil;
end;

function TSeqSample.GetULSR: TULSRObj;
begin
  Result := TULSRObj(Obj);
end;

destructor TSeqSample.Destroy;
begin
  inherited Destroy;
end;

{v0.49}
function TSequence.GetDataTemplate: TAcqData;
var
  d: TAcqData;
  ul: TUserViewLimit;
begin
  if FDataTemplate = nil then begin
    d := TAcqData.Create(DataTemplateFileName, omRead);
    try
      if d.ULI.Duration <> 0 then begin
        ul := NewUserViewLimit;
        d.ULVL.MinX := ul.Min.X;
        d.ULVL.MinY := ul.Min.Y;
        d.ULVL.MaxX := d.ULI.Duration / 60; //min
        d.ULVL.MaxY := ul.Max.Y;
      end;
      d.ULF.SaveToFile(d.ULF.FileName);
    except
      d.Free;
    end;
    FDataTemplate := d;
  end;
  Result := FDataTemplate;
end;

procedure TSequence.SetDataTemplateFileName(const AFileName: TFileName);
begin
  if (AFileName = ULSQ.DataTemplateFileName) then
    exit;
  FDataTemplate.Free;
  FDataTemplate := nil;
  ULSQ.DataTemplateFileName := AFileName;
end;

function TSequence.GetDataTemplateFileName: TFileName;
begin
  if ULSQ.DataTemplateFileName = '' then begin
    ULSQ.DataTemplateFileName := AddBackSlash(TemplateDir) + {v0.50} pvUlanDefaultTemplate{/v0.50 pvUlanDefaultSeq};
  end;
  Result := ULSQ.DataTemplateFileName;
end;
{/v0.49}

{v0.50}
procedure TSeqSample.FieldDefDirNeeded(AField: TULObjField);
var
  fd: TULObjFldDesc;
  fn: string;
begin
  fd := AField.FldDesc;
  fn := fd.Name;
  if fn = 'PrgFileName' then
    fd.DefDir := Sequence.GetDefPrgDir
  else if fn = 'MethodFileName' then
    fd.DefDir := Sequence.GetDefMethodDir
  {v0.52}
  else if fn = 'DataTemplateFileName' then
    fd.DefDir := Sequence.GetDefTemplateDir
  {/v0.52};
end;

function TSeqSample.GetSequence: TSequence;
begin
  Result := TSequence(ULObjOwner);{ulobjusru}
end;
{/v0.50}

{/TSeqSample.}

(*v0.49*)(*/v0.49
{v0.41}
{TSSequence}
procedure TSSequence.FirstMenuActionNeeded;

  procedure ActionUpdate(var AAction: TAction; ANotifyEvent: TNotifyEvent; const ACaption: string);
  begin
    if AAction = nil then begin
      AAction := TAction.Create(Self);
      AAction.OnExecute := ANotifyEvent;
    end;
    AAction.Caption := ACaption;
    Obj.MenuActionAdd(AAction);
  end;

  procedure AddClearError;
  {var sr: TULSRObj;}
  begin
    {sr := TULSRObj(Obj.ActiveChild);}
    ActionUpdate(FClearSampleErrorAction, ClearSampleError, GetTxt({#}'Clear Sample Error'));
  end;

begin
  {v0.44}
  inherited;
  {/v0.44}
{  s := GetTxt('all');
  if Obj.ChildWithFlagCount(rfSelected) > 0 then begin
    s := GetTxt('selected')
  end else begin
    if not Obj.FindObj(ULSRID, foChilds, '', o) then
      exit;
  end; }
  ActionUpdate(FSequenceRunAction, SequenceRun, GetTxt({#}'Run'));
  ActionUpdate(FPrgEditAction, PrgEdit, GetTxt({#}'Program Edit'));
  ActionUpdate(FMethodEditAction, MethodEdit, GetTxt({#}'Method Edit'));
  if FAcqInfo <> nil then
    ActionUpdate(FDoAcqShowAction, DoAcqShow, GetTxt({#}'Show Acquisition'));
  if CurPrg <> nil then
    ActionUpdate(FShowActPrgAction, ShowActPrgAction, GetTxt({#}'Show Running Program'));
//  ActionUpdate(FSequenceStopAction, SequenceStop, GetTxt({#}'Stop'));
  {v0.44}
  AddClearError;
  {/v0.44
  ActionUpdate(FNulAction, nil, '-');}
end;

procedure TSSequence.ShowActPrgAction(Sender: TObject);
begin
  ShowRunningPrg;
end;

procedure TSSequence.DefMethodSetDefaults;
begin
  FDefMethod.ULM.NoUnknownPeaks := true;
  FDefMethod.Save;
end;

procedure TSSequence.DefPrgCreateDefault;

  procedure AddLine0(l: TAAPLObj);
  begin
    l.PrgTime := 0;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acInject;
    l.Note := 'Start by injecting the sample on the column (acqusition starts)';
  end;

  procedure AddLine1(l: TAAPLObj);
  begin
    l.PrgTime := 30;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acNHD;
    l.Note := 'Ninhydrin should be switched on for poscolumn detection';
  end;

  procedure AddLine2(l: TAAPLObj);
  begin
    l.PrgTime := 60;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acZero;
    l.Note := 'Eventually zero the detector';
  end;

  procedure AddLine3(l: TAAPLObj);
  begin
    l.PrgTime := 90;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acAcqStop;
    l.Note := 'Acquisition can be stopped before program ends';
  end;

  procedure AddLine4(l: TAAPLObj);
  begin
    l.PrgTime := 120;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acStartEquil;
    l.Note := 'Start equilibrating the columnn for next sample';
  end;

  procedure AddLine5(l: TAAPLObj);
  begin
    l.PrgTime := 150;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acLoad;
    l.Note := 'Load next sample to injector loop';
  end;

  procedure AddLine6(l: TAAPLObj);
  begin
    l.PrgTime := 180;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acNone;
    l.Note := 'Just waiting for the end (of equilibration)';
  end;

var
  pl: TAAPrgLine;
  i: integer;

begin
  DefPrg.Obj.Clear;
  for i := 0 to 6 do begin
    pl := TAAPrgLine(DefPrg.ChildAdd(nil, AAPLID, ''));
    case i of
      0: AddLine0(pl.AAPL);
      1: AddLine1(pl.AAPL);
      2: AddLine2(pl.AAPL);
      3: AddLine3(pl.AAPL);
      4: AddLine4(pl.AAPL);
      5: AddLine5(pl.AAPL);
      6: AddLine6(pl.AAPL);
    end;
  end;
  DefPrg.Save;
end;

constructor TSSequence.Load(const AFileName: string);
begin
  inherited;{ulsqtype}
  SequenceState := sesStarting;
  Obj.OnGetWindowCaption := OnGetWindowCaption;
end;

function TSSequence.GetPump: TPumpModule;
begin
  if FPump = nil then begin
    if CurDeviceMode = dmUlan then
      FPump := TPumpModule.Create(Self, DataTemplate.Channel);
  end;
  Result := FPump;
end;

{v0.47}
function TSSequence.GetAutoSampler: TAutoSamplerModule;
var
  m: TModule;
begin
  if FAutoSampler = nil then begin
    if not FAutoSamplerChecked then begin
      if CurDeviceMode = dmUlan then begin
        FAutoSamplerChecked := true;
        try
          FAutoSampler := TAutoSamplerModule.Create(Self, DataTemplate.Channel);
        except
          { fails if autosampler not found }
        end;
      end;
    end;
  end;
  Result := FAutoSampler;
end;

function TSSequence.AutoSamplerLoad(AVialNr: integer): boolean;
begin
  if AutoSampler <> nil then begin
    AutoSampler.PREPSAMP.AsInteger := AVialNr;
    Log('AutoSampler PREPSAMP=' + IntToStr(AVialNr));
    Result := true;
    {
    if SimulationOn then begin
      AS_SAMPNUM.AsInteger := vnr;
    end;
    }
  end else begin
    Result := false;
    LogState('AutoSamplerLoad - no autosampler');
    SequenceState := sesAborting;
  end;
end;

function TSSequence.AutoSamplerInject: boolean;
begin
  if AutoSampler = nil then begin
    LogState('AutoSamplerInject - no autosampler');
    Result := false;
  end else begin
    AutoSampler.INJECT.AsInteger := 1;
    Result := true;
  end;
end;

function TSSequence.GetAutomatic: boolean;
begin
  Result := AutoSampler <> nil;
end;
{/v0.47}

procedure TSSequence.OnGetWindowCaption(var ACaption: string);
begin
  ACaption := ULSQ.ObjDesc.Caption + ' ' + ULSQ.SequenceName + ' ' + SequenceStateStr;
  if (FAcqInfo <> nil) then begin
    ACaption := ACaption + ' ' + ExtractFileName(FAcqInfo.Data.ULF.FileName) + ' ' +
    FloatToStrF(FAcqInfo.CurTime / 60, ffFixed, 7, 2);
  end;
end;

function TSSequence.SequenceStateStr: string;
begin
  Result := GetSequenceStateStr(SequenceState);
end;

function TSSequence.GetSequenceStateStr(ASequenceState:TSequenceState): string;
var s: string;
begin
  case ASequenceState of
    sesDisconnected: s := 'Disconnected'; { devices disconnected }
    sesAborted: s := 'Aborted';      { sequence run aborted, devices off }
    sesFinished: s := 'Finished';    { sequence run finished by processing last sample, devices off }
    sesStandby: s := 'Standby';      { sequence run not started yet or stopped upon user request, devices off
                       (not finished) }
    sesOff: s := 'Off';              { .. not real state, just for comparing, all below = OFF }
    sesStarting: s := 'Starting';    { sequence run requested, devices preparing for run }
    sesStopping: s := 'Stopping';    { sequence run stopping upon user request, devices stopping }
    sesFinishing: s := 'Finishing';  { sequence run finishing after last sample processed, devices stopping }
    sesAborting: s := 'Aborting';     { sequence run aborting because of error, devices aborting }
    sesReady: s:= 'Ready';        { sequence is ready to run (devices ready), devices ready to run }
    sesStopRunning: s := 'StopRunnig';  { running, but after processing current sample Stopping will start
                       (user requested stop after current sample) }
    sesRunning: s := 'Running';       { sequence is running }
  else
    s := 'Unknown';
  end;
  Result := s;
end;

procedure TSSequence.ClassFieldsCreate;
begin
  inherited;
  DefMethod.FullFileName := ULSQ.MethodFileName;

  if (DefMethod.FileName = '') or (pos('NONAME', Uppercase(DefMethod.FileName)) <> 0) then begin
    DefMethod.FullFileName := ULRecDefFileName(ULMID);
    ULSQ.MethodFileName := DefMethod.RelFileName;
  end;
  if (not FileExists(DefMethod.FullFileName)) and
    (DefMethod.RelFileName = ULRecDefFileName(ULMID))
  then begin
    DefMethodSetDefaults;
  end;
  DefMethod.LoadFromFile('');

  {v0.49}
  CheckDefPrg;
  {/v0.49
  DefPrg.FullFileName := ULSQ.PrgFileName;
  if (DefPrg.FileName = '') or (pos('NONAME', Uppercase(DefPrg.FileName)) <> 0) then begin
    DefPrg.FullFileName := ULRecDefFileName(AAPGID);
    ULSQ.PrgFileName := DefPrg.RelFileName;
  end;
  if (DefPrg.RelFileName = ULRecDefFileName(AAPGID))
  then begin
    if (not FileExists(DefPrg.FullFileName))then begin
      DefPrgCreateDefault;
    end;
  end;
  DefPrg.LoadFromFile('');
  }
end;

{v0.49}
procedure TSSequence.CheckDefPrg;
begin
  DefPrg.FullFileName := ULSQ.PrgFileName;
  if (DefPrg.FileName = '') or (pos('NONAME', Uppercase(DefPrg.FileName)) <> 0) then begin
    DefPrg.FullFileName := ULRecDefFileName(GetPrgRecID);
    ULSQ.PrgFileName := DefPrg.RelFileName;
  end;
  if (DefPrg.RelFileName = ULRecDefFileName(AAPGID))
    or (DefPrg.RelFileName = ULRecDefFileName(USPID))
  then begin
    if (not FileExists(DefPrg.FullFileName))then begin
      DefPrgCreateDefault;
    end;
  end;
  DefPrg.LoadFromFile('');
  if DefPrg.Obj.ObjDesc.DefDir = '' then
    DefPrg.Obj.ObjDesc.DefDir := ulanglob.PrgDir;
end;
{/v0.49}


procedure TSSequence.DoAfterCreate;
begin
  {update def dirs}
  {v0.49}
  {/v0.49
  Obj.ObjDesc.DefDir := ulanglob.SequenceDir;

  Obj.FindField('PrgFileName').FldDesc.DefDir := ulanglob.PrgDir;
  Obj.FindField('MethodFileName').FldDesc.DefDir := ulanglob.MethodDir;

  DefMethod.Obj.ObjDesc.DefDir := ulanglob.MethodDir;
  DefMethod.UpdateDefDirs;

  DefPrg.Obj.ObjDesc.DefDir := ulanglob.PrgDir;}
  UpdateDefDirs;
  {/update def dirs}
end;

{v0.49}
{procedure TSSequence.UpdateDefDirs;
var fd: TULObjFldDesc;
begin
  Obj.ObjDesc.DefDir := ulanglob.SequenceDir;

  fd := Obj.FindField('PrgFileName').FldDesc;
  fd.DefDir := ulanglob.PrgDir;
  fd.Filter := USPFilter;

  Obj.FindField('MethodFileName').FldDesc.DefDir := ulanglob.MethodDir;
  DefMethod.Obj.ObjDesc.DefDir := ulanglob.MethodDir;
  DefMethod.UpdateDefDirs;

  DefPrg.Obj.ObjDesc.DefDir := ulanglob.PrgDir;
  DefPrg.Obj.ObjDesc.OpenFilter := USPFilter;
end;}

procedure TSSequence.DoAfterLoad;
var bn: string;
begin
  inherited;
  bn := ChangeFileExt(ExtractFileName(ULSQ.PrgFileName), '');
  if (bn = 'NONAME') or (bn = 'AAPG') then begin
    Obj.FindField('PrgFileName').FldDesc.Filter := USPFilter;
    Obj.FindField('PrgFileName').FldDesc.DefDir := ulanglob.PrgDir;
    ULSQ.PrgFileName := '';
    CheckDefPrg;
  end;
end;
{/v0.49}


function TSSequence.GetNewSequenceName: string;
var
  d: string;
  n: string;
  i: integer;
begin
  n := FormatDateTime('yymmdd', Now);
  i := 1;
  repeat {ulsqtype}
    d := n + '-' + IntToStr(i);
    if not DirectoryExists(AddBackSlash(Obj.ObjDesc.DefDir) + d) then begin
      break;
    end;
    inc(i);
  until false;
  Result := d;
end;

procedure TSSequence.FileNew;
begin
{ if ULSQ.PrgFileName = '' then begin
    ULSQ.PrgFileName := AO.PrgFileName;
  end;

  if ULSQ.MethodFileName = '' then begin
    ULSQ.MethodFileName := AO.MethodFileName;
  end; }
  ClassFieldsUpdate;

  if ULSQ.SequenceName = '' then begin
    ULSQ.SequenceName := GetNewSequenceName;
    {ULSQ.MethodFileName := AO.MethodFileName;
    ULSQ.PrgFileName := AO.PrgFileName;}
  end;
  FullFileName := ULSQ.SequenceName;
  CheckDir;
end;

procedure TSSequence.CheckDir;
begin
  DefMethod.Obj.FindField('CalibrationFileName').FldDesc.DefDir := DirName;
  CreateDir(DirName);
  if not FileExists(FileName) then
    Save;
end;

procedure TSSequence.LogState(const msg: string);
begin
  ExeLog.LogErr('Sequence.' + LogHead + ' ' + msg);
end;

procedure TSSequence.Log(const msg: string);
begin
  ExeLog.Log('Sequence.' + LogHead + ' ' + msg);
end;

procedure TSSequence.TimerAdd;
begin
  if not FTimerAdded then begin
    Log('TimerAdd begin');
    Timers.AddTimerProc(DoTimer, 1000);
    FTimerAdded := true;
    Log('TimerAdd end');
  end;
end;

procedure TSSequence.TimerDel;
begin
  if FTimerAdded then begin
    Log('TimerDel begin');
    Timers.DeleteTimerProc(DoTimer);
    FTimerAdded := false;
    Log('TimerDel end');
  end;
end;

procedure TSSequence.DoCurSampleSelected;
begin
  CurSample.Prg.LoadFromFile(
     AbsoluteFileName(DefPrg.Obj.ObjDesc.DefDir, CurSample.ULSR.PrgFileName, {v0.49}GetPrgExt{v0.49 AAPGExt})
  );
  CurSample.Method.LoadFromFile(
    AbsoluteFileName(DefMethod.Obj.ObjDesc.DefDir, CurSample.ULSR.MethodFileName, ULMExt)
  );
end;

procedure TSSequence.ObjUpdated;
begin
  inherited;
  CurSampleStateChanged;
end;

procedure TSSequence.CurSampleStateChanged;
begin
//  AO.DoChange;
end;

procedure TSSequence.DoOK;
begin
  if FSeqForm <> nil then begin
    Log('OK pressed');
    DoConfirm;
  end;
end;

procedure TSSequence.DoConfirm;
begin
  if SequenceState <= sesOff then begin
    Log('DoConfirm ... OFF - SeqFormFree');
    SeqFormFree;
    exit;
  end;
  if FSeqForm = nil then
    exit;
  {TSeqForm(FSeqForm).MsgMemo.Lines.Add('OK pressed');}
  case TSeqForm(FSeqForm).State of
    sfsLoadSample: begin
      DoLoadSample;
      {CurSample.ULSR.SampleState := sasInLoop;}
    end;
    sfsInjectSample: begin
      DoInjectSample;
      {CurSample.ULSR.SampleState := sasRunning;}
    end;
    sfsLoadAndInjectSample: begin
      DoLoadSample;
      DoInjectSample;
    end;
  end;
end;

procedure TSSequence.DoCancel;
begin
  if FSeqForm <> nil then begin
    if SequenceState <= sesOff then begin
      SeqFormFree;
      exit;
    end;
    {TSeqForm(FSeqForm).MsgMemo.Lines.Add('Cancel pressed'); ulstringgrid}
  end;
  SequenceState := sesAborting;
end;

function TSSequence.GetDataTemplate: TAcqData;
var
  d: TAcqData;
{  ad: TULADObj;
  cnt, i: integer;
  o: TULObj;}
  ul: TUserViewLimit;
begin
  if FDataTemplate = nil then begin
    d := TAcqData.Create(DataTemplateFileName, omRead);
    try
      {
      cnt := 0;
      i := 0;
      while i < d.ULA.ChildCount do begin
        o := d.ULA.Childs[i];
        inc(i);
        if o is TULADObj then begin
          inc(cnt);
          if cnt = 1 then begin
            TULADObj(o).Color := clGreen;
          end else if cnt = 2 then begin
            TULADObj(o).Color := clBlue;
            TULADObj(o).DataName := 'B';
          end else begin
            o.Free;
            dec(i);
          end
        end;
      end;
      if cnt = 0 then begin
        ad := TULADObj(d.ULA.Add(ULADID));
        inc(cnt);
      end;
      if cnt = 1 then begin
        ad := TULADObj(d.ULA.Add(ULADID));
        ad.DataName := 'B';
        ad.Color := clBlue;
      end;
      d.ULAD.Update; }

      if d.ULI.Duration <> 0 then begin
        ul := NewUserViewLimit;
        d.ULVL.MinX := ul.Min.X;
        d.ULVL.MinY := ul.Min.Y;
        d.ULVL.MaxX := d.ULI.Duration / 60; //min
        d.ULVL.MaxY := ul.Max.Y;
      end;
      d.ULF.SaveToFile(d.ULF.FileName);

    except
      d.Free;
    end;
    FDataTemplate := d;
  end;
  Result := FDataTemplate;
end;

procedure TSSequence.SetDataTemplateFileName(const AFileName: TFileName);
begin
  if (AFileName = ULSQ.DataTemplateFileName) then
    exit;
  FDataTemplate.Free;
  FDataTemplate := nil;
  ULSQ.DataTemplateFileName := AFileName;
end;

function TSSequence.GetDataTemplateFileName: TFileName;
begin
  if ULSQ.DataTemplateFileName = '' then begin
    ULSQ.DataTemplateFileName := AddBackSlash(TemplateDir) + pvUlanDefaultSeq;
  end;
  Result := ULSQ.DataTemplateFileName;
end;

procedure TSSequence.SeqFormCheck(sfs: TSeqFormState; const ASampleName: string);
begin
  if FSeqForm = nil then begin
    FSeqForm := TSeqForm.Create(Self);
    TSeqForm(FSeqForm).Sequence := Self;
  end;
  with FSeqForm as TSeqForm do begin
    SampleName := ASampleName;
    if State <> sfs then begin
      State := sfs;
    end;
  end;
  Obj.UsersNotify(cmULObjFileNameChanged);{forces updating caption of browser}
end;

procedure TSSequence.SeqFormDoTimer;
begin
  if FSeqForm is TSeqForm then with FSeqForm as TSeqForm do begin
    if State in [sfsLoadSample, sfsInjectSample, sfsLoadAndInjectSample] then begin
      DoSound;
      Show;
      BringToFront;
    end;
  end;
end;

function TSSequence.GetSampleToLoad: TSeqSample;
begin
  Result := nil;
  if CurSample.ULSR.SampleState = sasWaiting then begin
    Result := CurSample;
  end else if NextSample <> nil then begin
    if CurSample.ULSR.PrgFileName <> NextSample.ULSR.PrgFileName then begin
      {Log('LOAD - ignored (next sample has dif.program)');}
    end else begin
      Result := NextSample;
    end;
  end else begin
    {Log('LOAD - no more samples');}
  end;
end;

procedure TSSequence.DoLoadSample;
var
  cs: TSeqSample;
  vnr: integer;
begin
{  if not Automatic then
    CurPrg.Resume;}
  cs := nil;
  {v0.46}
  vnr := 0;
  {/v0.46}

  if CurSample.ULSR.SampleState = sasWaiting then begin

    cs := CurSample;
    vnr := CurSample.ULSR.VialNr;
    CurSample.ULSR.SampleState := sasInLoop;

    Log('LOAD - loading current sample');

  end else if NextSample <> nil then begin

    if CurSample.ULSR.PrgFileName <> NextSample.ULSR.PrgFileName then begin
      Log('LOAD - ignored (next sample has dif.program)');
    end else begin
      vnr := NextSample.ULSR.VialNr;
      cs := NextSample;
      NextSample.ULSR.SampleState := sasInLoop;
      NextSample.Obj.SetFlag(rfCantDelete, true);
      CurSampleStateChanged;
      Log('PRG LINE: LOAD - loading next sample');
    end;

  end else begin

    Log('LOAD - no more samples');

  end;

  if vnr <> 0 then begin
    {v0.47}
    if Automatic then begin

      AutoSamplerLoad(vnr);

    end else
    {/v0.47}
      SeqFormCheck(sfsLoaded, cs.ULSR.FileName);

  end else begin
    {v0.47}
    if not Automatic then
    {/v0.47}
      SeqFormCheck(sfsIdle,'');

  end;

  {
  if vnr <> 0 then begin

    if (FDetState <> dstOK) and (not SimulationOn) then begin
      LogState('Before LOAD - DETECTOR FAILURE(' + GetDetStateMsg +
        ') detected, STOPPING before ' + CurSample.ULSR.FileName);
      SetAAAState(aasAborting);
      Result := false;
    end else  begin

      AS_PREPSAMP.AsInteger := vnr;
      Log('AS_PREPSAMP=' + IntToStr(vnr));

      if SimulationOn then begin
        AS_SAMPNUM.AsInteger := vnr;
      end;

    end;

  end;
  }

end;

procedure TSSequence.DoInjectSample;
var
  vnr: integer;
  aborted:boolean;
begin
  aborted := false;                                        {aaau}
  if {v0.47}Automatic and (AutoSampler.State <> astPrepared){/v0.47 false}
    {(FASState <> astPrepared)} then
  begin
    vnr := 0;
    { AS Not prepared: }
    if FCurPrg.Equil then begin
      Log('INJECT - Sample not prepared - Ignored (equilibrating)');
    end else begin
      //Result := false;
      LogState('INJECT - AS NOT READY');
      aborted := true;
      SequenceState := sesAborting;
    end;
  end else begin
    { AS Prepared: }
    {vnr := AS_SAMPNUM.AsInteger;}
    vnr := CurSample.ULSR.VialNr;{!!!}
    if (CurSample.ULSR.VialNr = vnr) then begin
      { Prepared vial position is ok: }
      if (CurSample.ULSR.SampleState <> sasInLoop) then
      begin
        if FCurPrg.Equil then begin
          Log('INJECT - Ignored (equilibrating), VialNr:' + IntToStr(vnr));
        end else begin
          LogState('INJECT - Sample NOT LOADED!, VialNr:' + IntToStr(vnr));
          SequenceState := sesAborting;
        end;
      end else begin
        {AS_Inject.AsInteger := 1;}
        {v0.47}
        if Automatic then begin
          if not AutoSamplerInject then begin
            aborted := true;
            vnr := 0;
          end;
        end;
        if not aborted then
        {/v0.47}
        begin
          Log('INJECTED VialNr: ' + IntToStr(vnr));
          AcqStart;
          CurSample.ULSR.SampleState := sasRunning;
          CurSampleStateChanged;
        end;
      end;
    end else begin
      LogState('INJECTED - Dif.Cur.Sample VialNr(' +
        IntToStr(CurSample.ULSR.VialNr) + ') and Prepared VialNr(' + IntToStr(vnr));
      //Result := false;
      vnr := 0;
      aborted := true;
      SequenceState := sesAborting;
    end;

  end;

  if not Automatic then
    CurPrg.Resume;

  if vnr <> 0 then begin
    SeqFormCheck(sfsInjected, CurSample.ULSR.FileName);

    {PumpPrgRun;}
  end else begin
    if not aborted then
      SeqFormCheck(sfsIdle, '');
  end;

{  if not Result then begin
    LogState('INJECT FAILED, ABORTING. Sample=' + CurSample.ULSR.FileName);
    SequenceState := aasAborting;
  end;}
end;

procedure TSSequence.PumpPrgEnd(const msg:string);
begin
  if Pump = nil then begin
    Log('[PUMP PRGEND]');
    exit;
  end;
  if Pump.PRGEND <> nil then begin
    Pump.PRGEND.AsInteger := 1;{end any eventually running program}
    Log('Pump.PRGEND ' + msg);
    if Pump.START <> nil then
      Log('Pump.START ' + msg);
  end;
end;

procedure TSSequence.PumpPrgRun(const msg:string);
begin
  if Pump = nil then begin
    Log('[PUMP PRGRUN]');
    exit;
  end;
  if Pump.PRGRUN <> nil then begin
    if Pump.STATUS <> nil then begin
      {if Pump.STATUS.AsInteger < 256 then}
      begin
        Pump.PRGRUN.AsInteger := 1;
        Log('Pump.PRGRUN ' + msg);
      end;
    end else begin
      Pump.PRGRUN.AsInteger := 1;
      Log('Pump.PRGRUN ' + msg);
    end;
  end;
end;

procedure TSSequence.PumpStartOrRun(const msg: string);
begin
  if Pump = nil then begin
    if not FPumpTimerLogged then begin
      Log('[PUMP START OR RUN]');
      FPumpTimerLogged := true;
    end else begin
      DebLog('[PUMP START OR RUN]');
    end;
    exit;
  end;

  if Pump.STATUS <> nil then begin

    if Pump.STATUS.AsInteger = 0 then begin

      if Pump.START <> nil then begin
        Pump.START.AsInteger := 1;
        Log('Pump.START ' + msg);
      end;

    end else if Pump.STATUS.AsInteger = 1 then begin

      if Pump.PRGRUN <> nil then begin
        Pump.PRGRUN.AsInteger := 1;
        Log('Pump.PRGRUN ' + msg);
      end;

    end;
  end;
end;

procedure TSSequence.PumpPrgActNrSelect(i:integer);
var prgid: integer;
begin
  if Pump = nil then begin
    Log('[PUMP PRG ACT NR SELECT ' + IntToStr(i) + ']');
    exit;
  end;
  prgid := i;
  if prgid <= 0 then
    prgid := 1;
  if Pump.PRGACTN <> nil then begin
    Pump.PRGACTN.AsInteger := prgid;
    Log('Pump.PRGACTN=' + IntToStr(prgid));
  end;
  if Pump.START <> nil then begin
    Pump.START.AsInteger := 1;
    Log('Pump.START');
  end;
end;

procedure TSSequence.DoTimerRunningStopRunning;
var
  {v0.49}
  pl: TPrgLine;
  {/v0.49 ulsrtype
  pl: TAAPrgLine;}
  timedif: integer;

  {procedure DoBuffer;
  var
     bnr: integer;
  begin
    bnr := ord(pl.AAPL.BufferNr);
    if bnr <> 0 then begin
      P1_AUXVALV.AsInteger := bnr;
      Log('BUFFER=' + IntToStr(bnr));
    end;
  end;

  procedure DoColumnTemp;
  var
    ot: extended;
    nt: extended;
  begin
    ot := StrToFloat(AS_TEMP1RQ.AsUsrString);
    nt := pl.AAPL.Temperature;
    if abs(ot - nt) > 1 then begin
      FColumnTempHistory.ChangedCounter := 5*60;
    end;
    AS_TEMP1.AsUsrString := FloatToStr(nt);
    Log('TEMP=' + IntToStr(round(nt)));
  end;
  }

  function DoInject: boolean;
  {var vnr: integer;}
  begin
    Result := true;
    {if SimulationOn then begin
      if not FCurPrg.Equil then begin
        FASState := astPrepared;
      end;
    end;}

    if not Automatic then begin
      CurPrg.Suspend;{ulsrtype}
      AcqGetReady;
      if CurSample.ULSR.SampleState <> sasInLoop then begin
        SeqFormCheck(sfsLoadAndInjectSample, CurSample.ULSR.FileName);
      end else begin
        SeqFormCheck(sfsInjectSample, CurSample.ULSR.FileName);
      end;
      PumpPrgRun('DoInject');
      exit;
    end;

    DoInjectSample;
  end;

  function DoLoad: boolean;
  var
    {vnr: integer;}
    ss: TSeqSample;
  begin
    Result := true;
    {vnr := 0;}
    if not Automatic then begin
      {CurPrg.Suspend;}
      ss := GetSampleToLoad;
      if ss <> nil then
        SeqFormCheck(sfsLoadSample, ss.ULSR.FileName);
      exit;
    end;

    DoLoadSample;
  end;

begin
  {v0.43}
  DebLog('SSequence DoTimerRun begin');
  try
    if FCurPrg = nil then begin
      DebLog('SSequence DoTimerRunnn... FCurPrg = nil');
      exit;
    end;
    {/v0.43}
    if FCurPrg.LineReady(pl, FStateStartTime) then begin

      if FCurPrg.Equil then
        LogHead := 'EQUIL:PRG_LINE: '
      else
        LogHead := 'PRG_LINE: ';

      try
        Log('START');

        {DoBuffer;
        DoColumnTemp;}

        {command}
        {v0.49}
        if pl is TAAPrgLine then
        with pl as TAAPrgLine do
        {/v0.49}
        begin

        case {v0.49}{/v0.49 pl.}AAPL.Command of

          acInject: begin
            Log('CMD INJECT');
            if not DoInject then
              exit;
          end;

          acZero: begin
            Log('DET_ZERO');
            {DET_ZERO.AsInteger := 1;}
          end;

          acH2O: begin
            {P2_GRADDIR.AsInteger := 0;}
            Log('P2_GRADDIR=H2O(0)');
          end;

          acNHD: begin
            {P2_GRADDIR.AsInteger := 1;}
            Log('P2_GRADDIR=NHD(1)');
          end;

          acAcqStop: begin
            if not FCurPrg.Equil then begin
              AcqStop;
              CurSample.ULSR.SampleState := sasCompleting;{ulsrtype}
              Log('CMD ACQ STOP');
            end else begin
              {AcqEquilStop;}
              Log('CMD ACQ STOP - ignored (equilibrating)');
            end;
          end;

          acStartEquil: begin
            Log('CMD START EQUIL');
          end;

          acLoad: begin
            Log('CMD LOAD');
            if not DoLoad then
              exit;
          end;

        end;
        {v0.49}
        end;
        {/v0.49}
        {/command}

      finally
        Log('END');
        LogHead := '';
        Log('');
        {v0.38}
        {v0.49}
        pl.State := plsDone;
        {/v0.49
        pl.AAPL.State := plsDone;}
        {/v0.38}
      end;
    end;

    if not FCurPrg.Running then begin
      { CurPrg finished (no more lines): }
      {v0.43}
      Log('CurPrg Not running');
      {/v0.43}
      if FCurPrg.Equil then begin
        AcqEquilStop
      end else begin
        AcqStop;{exelogu}
          { just to be sure the acq is stopped (if AcqStop command was not in program) }
      end;
      if SequenceState = sesStopRunning then begin
        Log('SEQUENCE STOPPED BY USER REQUEST DURING LAST SAMPLE RUN');
        SequenceState := sesStandby;
      end else
      begin
        if FCurPrg.Equil then begin
          { was equilibrating: }
          CurPrg := FCurPrg; { reselect/reactivate the same prg }
          FCurPrg.Start;
          StateStart(sesRunning, 0);
          Log('PRG ' + FCurPrg.FileName + ' STARTED (AFTER EQUIL) Sample ' +
            IntToStr(CurSample.ULSR.VialNr) + ' ' + CurSample.ULSR.FileName);
        end else begin
          { CurSample finihed }
          CurSample.ULSR.SampleState := sasDone;
          Log('SAMPLE DONE: Sample='+ IntToStr(CurSample.ULSR.VialNr));

          if Next then begin
            DoCurSampleSelected;
            Log('SAMPLE NEXT: Sample='+ IntToStr(CurSample.ULSR.VialNr) + ' PRG LOADED=' + CurSample.ULSR.PrgFileName);
            CurPrg := CurSample.Prg;

            if LastSample.ULSR.PrgFileName <> CurSample.ULSR.PrgFilename then
            begin
              FCurPrg.StartEquil(timedif);
              AcqEquilStart;
              StateStart(sesRunning, timedif);
              Log('PRG ' + FCurPrg.FileName + ' EQUIL STARTED');
            end else begin
              FCurPrg.Start;
              StateStart(sesRunning, 0);
              Log('PRG ' + FCurPrg.FileName + ' STARTED');
            end;

          end else begin

            CurPrg := nil;
            SequenceState := sesFinishing;

          end;

        end;
      end;

    end else begin
      { CurPrg is runnning }
      if FAcqInfo <> nil then begin

        PumpStartOrRun('from acq timer');

        AcqDoTimer;
        Obj.UsersNotify(cmULObjFileNameChanged);{forces updating caption of browser}
      end;
    end;
  {v0.43}
  finally
    DebLog('SSequence DoTimerRun.. end');
  end;
  {/v0.43}
end;


procedure TSSequence.DoTimer(Sender: TObject);

  procedure DoStarting;
  begin
    {inc(FSubState);
    case FSubState of
      1: exit;
    end;}
    SequenceState := sesReady;{!!!for now; should wait for some condition met}
  end;

  procedure DoAborting;
  begin
    SequenceState := sesAborted;{!!!for now, should wait for some conditions met}
    SeqFormCheck(sfsAborted, '');
  end;

  procedure DoStopping;
  begin
    SequenceState := sesStandby;
  end;

  procedure DoRunnig;
  begin
    if FSubState < 10 then begin
      inc(FSubState);
      case FSubState of
        1: begin
          PumpPrgEnd('DoRunning');
        end;
      end;
    end;
    DoTimerRunningStopRunning;
    {
    case CurSample.ULSR.SampleState of
      sasWaiting: begin
        SeqFormCheck(sfsLoadSample);
      end;    // sample waiting for processing
      sasInLoop: begin;     // sample loaded to injector valve
        SeqFormCheck(sfsInjectSample);
      end;
      sasRunning: ;    // sample injected
      sasCompleting: ; // sample acquisition stopped, equilibrating
      sasDone:;       // sample finished
      sasError:;       // sample finished, during processing of the sample some
                       //error encountered
    end;
    }
  end;

begin
  if FIsInTimer then
    exit;
  FIsInTimer := true;
  try
    {v0.43}
    DebLog('SSequence timer begin');
    {/v0.43}
    {Log('Timer begin');}
    case FSequenceState of
      sesStarting: DoStarting;
      sesRunning, sesStopRunning: DoRunnig;
      sesAborting: DoAborting;
      sesFinishing, sesStopping: DoStopping;
    end;
    SeqFormDoTimer;
  finally
    {Log('Timer end');}
    {v0.43}
    DebLog('SSequence timer end');
    {/v0.43}
    FIsInTimer := false;
  end;
end;

function TSSequence.FirstSampleRun: TSequenceResult;
var
  timedif:integer;
  {prgid: integer;}
begin
  if First then begin
    DoCurSampleSelected;
    Log('PRG FIRST LOADED ' + CurSample.ULSR.PrgFileName);
    CurPrg := CurSample.Prg;
    if FCurPrg.StartEquil(timedif) then begin
      PumpPrgActNrSelect(ord(TAAPLObj(FCurPrg.Obj.Childs[0]).BufferNr));
      AcqEquilStart;
      StateStart(sesRunning, timedif);
      Log('PRG ' + FCurPrg.FileName + ' EQUIL START');
      Result := 0;
    end else begin
      LogState('PRQ EQUIL START FAILED');
      Result := urInvalidProgramNoEquil;
    end;
    //CurSampleStateChanged;
  end else begin
    CurPrg := nil;
    Result := urNoSamples;
    Log('RUN: NO SAMPLES IN SEQUENCE');
  end;
end;

procedure TSSequence.SetCurPrg(APrg: {v0.49}TPrg{/v0.49 TAAPrg});
begin
  if FCurPrg <> nil then begin
    FCurPrg.Active := false;
  end;

  if (FBrowsingCurPrg <> nil) then begin
    if (FBrowsingCurPrg = FCurPrg) then begin
      FCurPrg.Obj.UsersNotify(cmULObjCloseViews);
    end else begin
      FBrowsingCurPrg := nil;
    end;
  end;

  FCurPrg := APrg;

  if FCurPrg <> nil then begin
    FCurPrg.Active := true;
  end;

  if FBrowsingCurPrg <> nil then begin
    // was watching the current prog, open the view again if running:
    if FCurPrg <> nil then
      ShowRunningPrg
    else
      FBrowsingCurPrg := nil;
  end;
end;

procedure TSSequence.StateStart(ASequenceState: TSequenceState; AUsrTimeOffset: integer);
begin
  FUsrStateTimeOffset := AUsrTimeOffset;
  FStateStartTime := mstime;
  FStateTime := 0;
  FSequenceState := ASequenceState;
end;

procedure TSSequence.SetSequenceState(ASequenceState: TSequenceState);
begin
  Log('State Req=' + GetSequenceStateStr(ASequenceState) + ' (Now=' + SequenceStateStr + ')');
  try
    {v0.42}
    {if FSequenceState = ASequenceState then
      exit;}
    {/v0.42}
    case ASequenceState of
      sesStarting: begin
        StateStart(sesStarting, 0);
        TimerAdd;
      end;

      sesReady: begin
        StateStart(sesReady, 0);
      end;

      sesRunning: begin
        if FirstSampleRun = 0 then
          StateStart(sesRunning, 0);
      end;

      sesStopRunning: begin
        StateStart(sesStopRunning, 0);
      end;

      sesStopping: begin
        StateStart(sesStopping, 0);
        SeqFormCheck(sfsFinished, '');
        AcqStop;
      end;

      sesFinishing: begin
        StateStart(sesFinishing, 0);
        SeqFormCheck(sfsFinished, '');
        AcqStop;
      end;

      sesAborting: begin
        StateStart(sesAborting, 0);
        SeqFormCheck(sfsAborted, '');
        AcqStop;
      end;

      sesAborted: begin
        StateStart(sesAborted, 0);
        SeqFormCheck(sfsAborted, '');
        {TimerDel;}
      end;

      sesFinished: begin
        StateStart(sesFinished, 0);
        {TimerDel;}
        SeqFormCheck(sfsFinished, '');
      end;

      sesStandby: begin
        StateStart(sesStandby, 0);
        SeqFormCheck(sfsFinished, '');
        {TimerDel;}
      end;

    else
      SetResult(urSetSequenceStateInvalid, IntToStr(ord(ASequenceState)));
    end;
    Obj.UsersNotify(cmULObjFileNameChanged);{forces updating caption of browser}
  finally
    Log('State=' + SequenceStateStr);
  end;
end;

function TSSequence.CheckCurSample: boolean;
begin
  if CurSample = nil then begin
    Log('CurSample=nil');
    Result := false;
  end else begin
    Result := true;
  end;
end;

function TSSequence.AcqEquilStart: boolean;
var
  pn: string;
begin
  Result := false;
  if FAcqInfo <> nil then begin
    Log('AcqEquilStart - acquisition is already running');
    exit;
  end;

  if CheckCurSample then begin {sequenceu}
    FAcqData := TAcqData.Create(DataTemplateFileName, omCreate);
    pn := ChangeFileExt(ExtractFileName(CurSample.ULSR.PrgFileName),'');
    pn := DirName + pn + '_Equilibration.ULF';
    FAcqData.ChangeFileName(pn);
    AcqDataUpdateViewLimit;
    FAcqInfo := TAcqInfo.Create(FAcqData);
    try
      if not Automatic then
        FAcqInfo.OnMark := OnMark;
      SpectrumFormOpenForAcqData(FAcqData, FAcqInfo);
      FAcqInfo.Start;
      Log('AcqEquil Started ' + pn);
    except
      FAcqInfo.Free;             {acqinfou}
      FAcqInfo := nil;
      FAcqData.Free;
      FAcqData := nil;
    end;
    Result := true;
  end;
end;

procedure TSSequence.AcqEquilStop;
begin
  if FAcqInfo <> nil then begin
    Log('AcqEquil Stopping..');
    AcqStop;
  end;
end;

function TSSequence.AcqInfoCreate: boolean;
begin
  Result := false;
  if FAcqInfo <> nil then begin
    Log('AcqInfoCreate - acquisition already exists');
    exit;
  end;

  if CheckCurSample then begin {acqinfou sequenceu ulantype ulanglob}
    CheckDir;{!!!}
    FAcqData := TAcqData.Create(DataTemplateFileName, omCreate);
    FAcqData.ChangeFileName(DirName + CurSample.ULSR.FileName);
    if CurSample.ULSR.SampleName = '' then
      CurSample.ULSR.SampleName := CurSample.ULSR.FileName;{ulsrtype}
    FAcqData.ULA.AssignClass(CurSample.ULSR);
      { copy just header (class published fields, not childs) }
    FAcqData.ULM.Assign(CurSample.Method.ULM);
    FAcqData.CheckULMRecords;
    FAcqData.ULM.MethodTemplate := CurSample.ULSR.MethodFileName;

    AcqDataUpdateViewLimit;

    FAcqInfo := TAcqInfo.Create(FAcqData);
    if not Automatic then begin
      FAcqInfo.OnMark := OnMark;
    end;
    Result := true;
  end;
end;

procedure TSSequence.OnMark(Sender: TObject);
begin
  Log('Mark pressed');
  DoConfirm;
end;

function TSSequence.AcqGetReady: boolean;
begin
  Result := false;
  if FAcqInfo <> nil then begin
    Log('AcqGetReady - acquisition is already running');
    exit;
  end;
  Result := AcqInfoCreate;
  if Result then begin
    Log('AcqGetReady ' + FAcqData.ULF.FileName);
    FAcqInfo.Run;
  end;
end;

function TSSequence.AcqStart: boolean;
begin
  Result := false;
  if (FAcqInfo <> nil) and Automatic then begin
    Log('AcqStart - acquisition is already running');
    exit;
  end;
  if (FAcqInfo <> nil) or AcqInfoCreate then begin
    Log('AcqStart ' + FAcqData.ULF.FileName);
    SpectrumFormOpenForAcqData(FAcqData, FAcqInfo);
    FAcqInfo.Start;
    Result := true;
  end;
end;

procedure TSSequence.AcqDoTimer;
begin
  FAcqInfo.DoTimer;
  if FAcqInfo.SuspendedForNoData then{acqinfou ulstringgrid}
    SequenceState := sesAborting;
end;


procedure TSSequence.AutoSaveAll;
begin
  Save;
{  DefPrg.Save;
  DefMethod.Save;}
end;

procedure TSSequence.AcqShow;
begin
  if (FAcqInfo <> nil) and (FAcqData <> nil) then begin
    if FAcqInfo.TheSpecForm <> nil then
      FAcqInfo.TheSpecForm.BringToFront
    else
      SpectrumFormOpenForAcqData(FAcqData, FAcqInfo);
  end;
end;

procedure TSSequence.AcqDataUpdateViewLimit;
begin
  if (CurSample <> nil) and (FAcqData <> nil) then
    FAcqData.ULVL.MaxX := CurSample.Prg.TotalSecTime / 60;
end;

procedure TSSequence.AcqStop;
var
  ai: TAcqInfo;
  ad: TAcqData;
begin
  if (FAcqInfo = nil) and (FAcqData = nil) then
    exit;
  Log('AcqStop begin');

  ai := FAcqInfo;
  FAcqInfo := nil;{disables timer calls}
  ad := FAcqData;
  FAcqData := nil;

  if ai <> nil then begin
    if ad <> nil then
      ad.ULA.AutoDetectLater := true;
    ai.Stop;
    ai.Free;
    Log('AcqStopped');
  end;

  if ad <> nil then begin
    ad.Free;
  end;

  PumpPrgEnd('AcqStop');

  AutoSaveAll;
  Log('AcqStop end');
end;


procedure TSSequence.SequenceRun(Sender: TObject);
begin {aaau}
  SequenceState := sesRunning;
end;

procedure TSSequence.PrgEdit(Sender: TObject);
begin
  if DefPrg.RelFileName <> ULSQ.PrgFileName then begin
    DefPrg.FullFileName := ULSQ.PrgFileName;
    DefPrg.LoadFromFile('');
  end;
  AAPrgBrowserOpen(DefPrg.FileName, omRead);
{ DefPrg.Browse;}
end;

procedure TSSequence.DoAcqShow(Sender: TObject);
begin
  AcqShow;
end;

procedure TSSequence.MethodEdit(Sender: TObject);
var m: TUlanMethod;
begin
  if DefMethod.RelFileName <> ULSQ.MethodFileName then begin
    DefMethod.FullFileName := ULSQ.MethodFileName;
    DefMethod.LoadFromFile('');
  end;
  m := TUlanMethod.Load(DefMethod.FileName);
  try
    if m.EditModal = mrOK then begin
      m.Obj.DoFileSave;
      ULSQ.MethodFileName := m.RelFileName;
    end;
  finally
    m.Free;
  end;
  {
  if DefMethod.EditModal = mrOK then begin
    DefMethod.Obj.DoFileSave;
    ULSQ.MethodFileName := DefMethod.RelFileName;
  end;}
end;

{procedure TSSequence.SequenceStop(Sender: TObject);
begin
  SequenceState := sesStopping;
end;}

procedure TSSequence.SeqFormFree;
var
  f: TSeqForm;
begin
  f := TSeqForm(FSeqForm);
  FSeqForm := nil;
  {v0.43}
  if f <> nil then begin
    f.Sequence := nil;
    f.Release;
  end;
  {/v0.43
  f.Free;}
end;

destructor TSSequence.Destroy;
begin
  {v0.47}
  if Obj <> nil then begin
    {if CompareRec(Obj.OnGetWindowCaption, TMethod(OnGetWindowCaption)) = 0 then}
    Obj.OnGetWindowCaption := nil;
  end;
  {/v0.47}
  TimerDel;
  SeqFormFree;
  AcqStop;
  FDataTemplate.Free;
  inherited;
end;

function TSSequence.GetDefPrg:{v0.49}TPrg{/v0.49 TAAPrg};
begin
  Result := inherited GetDefPrg;
{  if Result.FileName = '' then
    Result.FullFileName := ULRecDefFileName(AAPGID);}
end;

function TSSequence.GetDirName: string;
var
  n: string;
  i: integer;
  fn: string;
begin
  n := ULSQ.SequenceName;
  for i := 1 to length(n) do begin
    if n[i] in [':',',','/','\'] then
      n[i] := '_';
  end;
  fn := ULSQ.RootFileDir;
  if fn = '' then
    fn := ULSQ.ObjDesc.DefDir;
  if n <> '' then
  Result := AddBackSlash(fn) + n + '\'
end;

procedure TSSequence.ShowRunningPrg;
begin
  if FCurPrg <> nil then begin
    FBrowsingCurPrg := FCurPrg;
    FCurPrg.Browse;
  end else begin
    FBrowsingCurPrg := nil;
  end;
end;




{/v0.41}
*)

{procedure TSequence.Run;{called by usr to start the sequence}
{begin
  SequenceState := ssRunning;
end;

procedure TSequence.Stop;{called by usr to stop the sequence}
{begin
  SequenceState := ssStopping;
end;}

procedure TSequence.CheckDir;
begin
  DefMethod.Obj.FindField('CalibrationFileName').FldDesc.DefDir := DirName;
  CreateDir(DirName);
  if not FileExists(FileName) then
    Save;
end;
{/TSSequence.}



{v0.50}
function SequenceNew(var s: TSequence; template: TULFObj): boolean;
var
  c: TULObj;
  uli: TULIObj;
  ulm: TULMObj;
  usp: TUSPObj;
  n: string;
  frm: TAnalSetupForm;
  r: integer;
begin
  Result := false;
  {v0.51}
  if template = nil then
    exit;
  {/v0.51}
  s := TSequence.Load('');
  try
    c := template.FindOrAdd(ULAID, '');
    {v0.51}
    uli := TULIObj(c.FindOrAdd(ULIID, ''));
    usp := nil;
    {/v0.51}

    s.Obj.Assign(c);
    s.ULSQ.DataTemplateFileName := template.FileName;
    s.SequenceKind := TULIObj(s.Obj.FindOrAdd(ULIID,'')).SequenceKind;


    if {v0.51}uli{/v0.51 c}.FindObj(USPID, foNotSelf + foNotRecursive, '', TULObj(usp)) then
      s.ULSQ.PrgFileName := usp.PrgName;

    if c.FindObj(ULMID, foNotSelf + foNotRecursive, '', TULObj(ulm)) then begin
      n := ulm.MethodFileName;
      if n = '' then
        n := ulm.MethodTemplate;
      s.ULSQ.MethodFileName := n;;{ulmtype}
    end;

    s.ULSQ.SequenceName := s.GetNewSequenceName;
    {v0.50}
    s.UpdateFileNameFromSequenceName;
    {/v0.50
    s.FileName := AbsoluteFileName(s.Obj.ObjDesc.DefDir, s.ULSQ.SequenceName, ULSExt);}

    {v0.50}
    CurULObj := s.DataTemplate.ULA;
    frm := TAnalSetupForm.Create(Application.MainForm);
    try
      frm.ULATabSheet.TabVisible := false;
      frm.SequenceTabSheet.Visible := true;
      frm.SequenceTabSheet.TabVisible := true;
      frm.PageControl.ActivePage := frm.SequenceTabSheet;
      {ULObjToForm(s.ULSQ, frm, [], '');}
      frm.SequenceNameEdit.Text := s.ULSQ.SequenceName;
      frm.SequenceDescEdit.Text := s.ULSQ.SequenceDesc;
      frm.SequenceKindEdit.ItemIndex := ord(s.ULSQ.SequenceKind);
      {}
      r := frm.ShowModal;
      if r <> mrOK then begin
        s.Free;
        exit;
      end else begin
        {FormToULObj(frm, s.ULSQ, [], '');}
        s.ULSQ.SequenceName := frm.SequenceNameEdit.Text;
        s.ULSQ.SequenceDesc := frm.SequenceDescEdit.Text;
        s.ULSQ.SequenceKind := TSequenceKind(frm.SequenceKindEdit.ItemIndex);
        {}
        s.UpdateFileNameFromSequenceName;
        {v0.51}
        if (s.ULSQ.SequenceKind = skStandalone) then begin
          s.DefPrg.Obj.Assign(s.DataTemplate.ULI_USP);
        end;
        {/v0.51}
      end;
    finally
      frm.Free;
    end;
    {/v0.50
    if s.Obj.EditModal <> mrOK then begin
      s.Free;
      exit;
    end;}
    CreateDir(s.DirName);
    if not FileExists(s.FileName) then
      s.Save;
  except
    s.Free;
    raise;
  end;
  Result := true;
end;
{/v0.50}

{v0.32}
function SequenceBrowserOpen(const AFileName: shortstring; AMode: TOpenMode): boolean;
var
  s: TSequence;
  {v0.50}
  t: TULFObj;
  {/v0.50
  t: TSequence;}
  fn: string;
  ext: string;
  {v0.41}
  sf: TSequenceClass;
  {/v0.41}
begin
  {v0.50}
  Result := false;
  {/v0.50}
  {v0.41}
  {v0.49}
  sf := TSequence;
  {/v0.49
  if AAAActive then begin
    sf := TSequence
  end else begin
    sf := TSSequence;
  end;}
  {/v0.41}
  if ChangeFileExt(ExtractFileName(AFileName), '') = 'Default' then begin
    fn := ''
  end else
    fn := AFileName;
  ext := ExtractFileExt(fn);
  if ext = '' then
    ext := ULSExt;
  if (AMode = omCreate) then begin
    if (fn <> '') then begin
      fn := ChangeFileExt(fn, ext); { ulsqtype ulanrecs.lst }
      if FileExists(fn) then begin
        {v0.50}
        t := TULFObj.Load(fn);{ulobju ulfobju}
        {/v0.50
        t := sf.Load(fn);}
        try
          {v0.50}
          if not SequenceNew(s, t) then
            exit;
          {/v0.50
          s := sf.Load('');
          try
            s.Obj.Assign(t.Obj);
            s.ULSQ.DataTemplateFileName := fn;
          except
            s.Free;
            raise;
          end; }
        finally
          t.Free;
        end;

      end else begin
        raise Exception.Create(GetTxt({#}'Sequence template not found') + ' ' + fn);
      end;
      {v0.41}
      if ExtractFileExt(AFileName) = ULTExt then begin
        {v0.50}{/v0.50
        s.SequenceKind := TULIObj(s.Obj.FindOrAdd(ULIID,'')).SequenceKind;}
        {v0.49}
        {v0.50}
        {/v0.50
        if s.SequenceKind <> skAAA then}
        {/v0.49
        if s is TSSequence then
          TSSequence}
        {v0.50}
        {/v0.50

          (s).DataTemplateFileName := AFileName;}
      end;
      {/v0.41}
    end else begin
      s := {v0.41}sf{/v0.41 TSequence}.Load('');
    end;
  end else begin
    s := {v0.41}sf{/v0.41 TSequence}.Load(fn);
    {v0.41}
    {if ExtractFileExt(AFileName) = ULTExt then begin
      if s is TSSequence then
        TSSequence(s).DataTemplateFileName := AFileName;
    end;}
    {/v0.41}
  end;
  s.Obj.BrowserAutoClose := true;
  s.Obj.SetFlag(rfBrowseModal, false);
  s.Browse;
  Result := true;
end;
{/v0.32}

{v0.24}
initialization
  RegisterClasses([TSequence, TSeqSample]);
{/v0.24}
end.
