unit uBafXlsModule;

// this code is under the BAF fair use license (BFUL) - https://bafbal.de/index.php?title=Bful
// exporting in xlsx- format
// needs http://www.kluug.net/xlsx-ods-delphi.php
// https://bafbal.de/index.php?title=Modul_XLS


interface

uses System.Math, System.SysUtils, System.Classes, uBafTypes, uBafInterpreter,
  OExport, OExport_FMX, System.UITypes, uBafPage, System.DateUtils, StrUtils,
  DB;

type
  TBafXlsModule = class(TBafInterpreterCustomModule)
  protected
    FExport: TOExport;
    FSheet: TExportWorkSheet;
    FSheetRow: TExportRow;
    FExportInvisibleColumns: boolean;
    procedure XlsStart;
    procedure XlsStop;
    procedure XlsAddSheet;
    procedure XlsAddRow;
    procedure XlsAddCell;
    procedure XlsDeleteSheet;
    procedure XlsPage;
    procedure XlsGrid;
    procedure XlsLoad;
    procedure XlsLoopRows;
    function ConvertAlign(AAlign: TBafAlignment): TCellHAlignment;
    function AddCellTyp(AType: TBafPageCellType; AValue: string): TExportCell;
    function AddCellFormula(AType: TBafPageCellType; AFormula: string): TExportCell;
    function SetCellTyp(AIndex: integer; AType: TBafPageCellType; AValue: string): TExportCell;
    function SetCellFormula(AIndex: integer; AType: TBafPageCellType; AFormula: string): TExportCell;
    procedure ExportSimpleGrid(AGrid: TBafSimpleGrid; ASheetTitle: string = '');
    procedure ExportRows(AGrid: TBafSimpleGrid; AType: TBafGridRowType);
    function ExportSegment(ASegment: TBafPageSegment): boolean;
    function GetBorderStyle(AStyle: string): TCellBorderStyle;
    function XlsGetCount(AParams: TStrings): string;
    function XlsGetCell(AParams: TStrings): string;
  protected
    procedure ttFlugtabelle;
    procedure ttBusrouten;
  public
    constructor Create; override;
    destructor Destroy; override;
    function InterpretLine(AExecInter: TBafCustomInterpreter): boolean; override;
    function ReplaceFunction(ACommand: string; AParams: TStrings;
        var AResult: string): boolean; override;
    procedure ExportSegmentXls(ASegment: TObject); override;
    procedure ExportPageXls(APage: TObject); override;
  end;

  TFlughafenWoche = class
    FTage: TStringList;
    constructor Create;
    destructor Destroy; override;
  end;

  TFlughafen = class
    FZuschlag: TStringList;
    FWochen: TStringList;
    procedure AddDaten(AZuschlag, ASaison, AVt, AVtChar, ASo: string;
        ADatum: TDate; AKgr: boolean; AZuschlagIx: integer);
    function GetRowCount: integer;
    function GetAufpreis: string;
    constructor Create;
    destructor Destroy; override;
  end;

  TBusroutenTag = class
    FPLZ: integer;
    FTag: string;
    FCount: integer;
  end;

  TBusroutenMonat = class
    FJahr: string;
    FMonat: string;
    FZuschlag: string;
    FKw: string;
    FMinTag: integer;
    FPlz: TStringList;
    FCellCount: integer;
    constructor Create;
    destructor Destroy; override;
  end;

implementation

uses foBafDialog, foMain, dmMain;

var
  mvFlughafen: TStringList;

{ TBafXlsModule }

function TBafXlsModule.AddCellFormula(AType: TBafPageCellType;
  AFormula: string): TExportCell;
begin
  case AType of
    ctInt: result := FSheetRow.AddCellFormulaNumber(AFormula, 0);
    ctCurr4: result := FSheetRow.AddCellFormulaNumber(AFormula, 4);
    else
      result := FSheetRow.AddCellFormulaNumber(AFormula);
  end;
end;

function TBafXlsModule.AddCellTyp(AType: TBafPageCellType; AValue: string): TExportCell;
var
  LDate: TDateTime;
begin
  case AType of
    ctDate, ctDateMin, ctDateSek: begin
      LDate := StrToDateTimeDef(AValue, -1000001);
      if LDate > -1000000 then begin
        case AType of
          ctDate: result := FSheetRow.AddCellDate(LDate);
          ctDateMin: result := FSheetRow.AddCellDateTimeWS(LDate);
          ctDateSek: result := FSheetRow.AddCellDateTime(LDate);
        end;
      end
      else
        result := FSheetRow.AddCellEmpty;
    end;
    ctInt: result := FSheetRow.AddCellNumber(StrToIntDef(AValue, 0), 0);
    ctCurr, ctCurrInt: result := FSheetRow.AddCellNumber(StrToCurrDef(AValue, 0), 2);
    ctCurr4: result := FSheetRow.AddCellNumber(StrToCurrDef(AValue, 0), 4);
    else
      result := FSheetRow.AddCellString(AValue);
  end;
end;

function TBafXlsModule.ConvertAlign(AAlign: TBafAlignment): TCellHAlignment;
begin
  case AAlign of
    taRightJustify: result := cahRight;
    taCenter: result := cahCenter;
    taExplicitLeft: result := cahLeft;
    taDecimal2, taDecimal4: result := cahJustify;
  else
    result := cahAuto;
  end;
end;

constructor TBafXlsModule.Create;
begin
  inherited;

end;

destructor TBafXlsModule.Destroy;
begin

  inherited;
end;

procedure TBafXlsModule.ExportPageXls(APage: TObject);
var
  LPage: TBafPage;
begin
  inherited;
  if Assigned(FExport) then
    FreeAndNil(FExport);
  FExport := TOExport.Create;
  try
    LPage := (APage as TBafPage);
    LPage.AllSegFunction(ExportSegment);
    FExport.SaveToFileWithDialog('baf_export', '', true);
  finally
    FreeAndNil(FExport);
  end;
end;

procedure TBafXlsModule.ExportRows(AGrid: TBafSimpleGrid; AType: TBafGridRowType);
var
  LRow, LCol, LColSpan: integer;
  LCell: TBafSgCell;
  LColumn: TBafSgColumn;
  LXlsCell: TExportCell;
  LWidth: single;
  LColOptions: string;
begin
  for LRow := 0 to AGrid.RowCount(AType) - 1 do begin
    FSheetRow := FSheet.AddRow;
    LColSpan := 0;
    for LCol := 0 to AGrid.Columns.Count - 1 do begin
      LCell := AGrid.Cells[AType, LCol, LRow];
      LColumn := LCell.Parents.Column;
      LWidth := FindParamSingleReplaced(LColumn.LineP, 'xw', -1);
      LColOptions := FindParamStringReplacedLower(LColumn.LineP, 'xop', '');
      if LWidth < 0 then
        LWidth := LColumn.Width;
      if LWidth > 0 then begin
        if LColSpan <= 0 then begin
          if AType = rtHeader then
            LXlsCell := FSheetRow.AddCellString(LCell.Text)
          else if (AType = rtFooter) and (LCell.GetDisplayText = '') then
            LXlsCell := FSheetRow.AddCellString('')
          else if LColumn.CellType in [ctGuid] then
            LXlsCell := AddCellTyp(LColumn.CellType, LCell.Text)
          else if (pos('n', LColOptions) > 0) and (LCell.Text = '') then
            LXlsCell := AddCellTyp(ctText, '')
          else
            LXlsCell := AddCellTyp(LColumn.CellType, LCell.GetDisplayText);
          LXlsCell.Width := LWidth;
          if (AType = rtHeader) then begin
            LColSpan := FindParamIntegerReplaced(LColumn.LineP,
                'xcs' + IntToStr(LRow + 1), 1);
            LXlsCell.ColSpan := LColSpan;
            LXlsCell.BGColor := FInter.FindParamColor(LColumn.LineP, 'xhcl', $FFCCBB);
            LXlsCell.SetBorders(cbAll, ebThin);
          end
          else case LCell.CellColor of
            ccGreen: LXlsCell.BGColor := BafName2Color('green');
            ccYellow: LXlsCell.BGColor := BafName2Color('yellow');
            ccRed: LXlsCell.BGColor := BafName2Color('red');
            ccHeader: LXlsCell.BGColor := FInter.FindParamColor(LColumn.LineP, 'xhcl', $FFCCBB);
          end;
        end;
      end;
      dec(LColSpan);
    end;
  end;
// procedure TBafXlsModule.ExportRows
end;

function TBafXlsModule.ExportSegment(ASegment: TBafPageSegment): boolean;
begin
  result := true;
  if ASegment.XlsCommand = '' then begin
    case ASegment.SegmentType of
      stValueList, stGrid, stXGrid, stXXGrid, stSGrid: ExportSimpleGrid(ASegment.Grid);

    end;
  end
  else
    TBafInterpreterLevel.ExecInNewLevel(ASegment.XlsCommand, FExecInter, FInter);
end;

procedure TBafXlsModule.ExportSegmentXls(ASegment: TObject);
begin
  inherited;
  if Assigned(FExport) then
    FreeAndNil(FExport);
  FExport := TOExport.Create;
  try
    ExportSegment(ASegment as TBafPageSegment);
    FExport.SaveToFileWithDialog('baf_export', '', true);
  finally
    FreeAndNil(FExport);
  end;
end;

procedure TBafXlsModule.ExportSimpleGrid(AGrid: TBafSimpleGrid; ASheetTitle: string = '');
var
  s: string;
begin
  if ASheetTitle = '' then
    FSheet := FExport.AddWorkSheet(AGrid.Parents.Segment.SegmentName)
  else
    FSheet := FExport.AddWorkSheet(ASheetTitle);
  ExportRows(AGrid, rtHeader);
  ExportRows(AGrid, rtDisplayData);
  ExportRows(AGrid, rtFooter);
end;

function TBafXlsModule.GetBorderStyle(AStyle: string): TCellBorderStyle;
begin
  if AStyle = 'auto'
    then result := ebAuto
  else if AStyle = 'none'
    then result := ebNone
  else if AStyle = 'thin'
    then result := ebThin
  else if AStyle = 'medium'
    then result := ebMedium
  else if AStyle = 'dashed'
    then result := ebDashed
  else if AStyle = 'dotted'
    then result := ebDotted
  else if AStyle = 'thick'
    then result := ebThick
  else if AStyle = 'double'
    then result := ebDouble
  else if AStyle = 'hair'
    then result := ebHair
  else if AStyle = 'mediumdashed'
    then result := ebMediumDashed
  else if AStyle = 'mediumdotted'
    then result := ebDashDotted
  else if AStyle = 'dashdotted'
    then result := ebDashDotted
  else if AStyle = 'mediumdashdotted'
    then result := ebMediumDashDotted
  else if AStyle = 'dashdotdotted'
    then result := ebDashDotDotted
  else if AStyle = 'mediumdashdotdotted'
    then result := ebMediumDashDotDotted
  else if AStyle = 'slanteddashdotted'
    then result := ebSlantedDashDotted
  else result := ebThin;
end;

function TBafXlsModule.InterpretLine(AExecInter: TBafCustomInterpreter): boolean;
var
  LNum: integer;
  LInter: TBafCustomInterpreter;
begin
  result := false;
  LInter := FExecInter;
  try
    FExecInter := AExecInter;

    result := true;
    if FExecInter.LineF = '#xls_start' then XlsStart                            // start a calc sheet
    else if FExecInter.LineF = '#xls_stop' then XlsStop                         // ends a calc sheet
    else if FExecInter.LineF = '#xls_sheet' then XlsAddSheet                    // adds a sheet
    else if FExecInter.LineF = '#xls_row' then XlsAddRow                        // adds a row
    else if FExecInter.LineF = '#xls_cell' then XlsAddCell                      // adds a cell

    else if FExecInter.LineF = '#xls_delete_sheet' then XlsDeleteSheet          // deletes the current sheet

    else if FExecInter.LineF = '#xls_page' then XlsPage                         // exports a BAF Page
    else if FExecInter.LineF = '#xls_grid' then XlsGrid                         // exports a BAF Grid

    else if FExecInter.LineF = '#tt_flugtabelle' then ttFlugtabelle             // tt intern
    else if FExecInter.LineF = '#tt_busrouten_print' then ttBusrouten           // tt intern

    else if FExecInter.LineF = '#xls_load' then XlsLoad                         // loads a cakc sgeet
    else if FExecInter.LineF = '#xls_looprows' then XlsLoopRows                 // lLoops through all rows

    else result := false;
  finally
    FExecInter := LInter;
  end;


end;

function TBafXlsModule.ReplaceFunction(ACommand: string; AParams: TStrings;
  var AResult: string): boolean;
begin
  inherited;
  result := true;
  if ACommand = '$XLS_COUNT' then
    AResult := XlsGetCount(AParams)
  else if ACommand = '$XLS_CELL' then
    AResult := XlsGetCell(AParams)
  else result := false;
end;

function TBafXlsModule.SetCellFormula(AIndex: integer; AType: TBafPageCellType;
  AFormula: string): TExportCell;
begin
  result := FSheetRow.FindCreateCell(AIndex, TExportCellString);
  (result as TExportCellString).SetFormula(AFormula);
end;

function TBafXlsModule.SetCellTyp(AIndex: integer; AType: TBafPageCellType;
  AValue: string): TExportCell;
var
  LDate: TDateTime;
begin
  if AType in [ctDate, ctDateMin, ctDateSek] then begin
    LDate := StrToDateTimeDef(AValue, -1000001);
    if LDate > -1000000 then begin
      if AType in [ctDate] then begin
        result := FSheetRow.FindCreateCell(AIndex, TExportCellDate);
        (result as TExportCellDate).SetDateTime(LDate);
      end
      else if AType in [ctDateMin] then begin
        result := FSheetRow.FindCreateCell(AIndex, TExportCellDateTimeWS);
        (result as TExportCellDateTimeWS).SetDateTime(LDate);
      end
      else if AType in [ctDateSek] then begin
        result := FSheetRow.FindCreateCell(AIndex, TExportCellDateTime);
        (result as TExportCellDateTime).SetDateTime(LDate);
      end;
    end
    else
      result := FSheetRow.FindCreateCell(AIndex, TExportCellEmpty);
  end
  else if AType in [ctInt] then begin
    result := FSheetRow.FindCreateCell(AIndex, TExportCellNumber);
    (result as TExportCellNumber).SetValue(StrToIntDef(AValue, 0));
    (result as TExportCellNumber).SetDecimalPlaces(0);
  end
  else if AType in [ctCurr, ctCurrInt] then begin
    result := FSheetRow.FindCreateCell(AIndex, TExportCellNumber);
    (result as TExportCellNumber).SetValue(StrToCurrDef(AValue, 0));
    (result as TExportCellNumber).SetDecimalPlaces(2);
  end
  else if AType in [ctCurr4] then begin
    result := FSheetRow.FindCreateCell(AIndex, TExportCellNumber);
    (result as TExportCellNumber).SetValue(StrToCurrDef(AValue, 0));
    (result as TExportCellNumber).SetDecimalPlaces(4);
  end
  else begin
    result := FSheetRow.FindCreateCell(AIndex, TExportCellString);
    (result as TExportCellString).SetText(AValue);
  end;
// function TBafXlsModule.SetCellTyp
end;

function WochenSort(List: TStringList; Index1, Index2: Integer): Integer;
var
  LWoche1, LWoche2: string;
  LErster1, LErster2, LLetzter1, LLetzter2: integer;

  procedure lokErsterLetzterTag(AWoche: string; var AErster, ALetzter: integer);
  var
    i, ix, j, LTag: integer;
    LFlhObject: TFlughafen;
    LWoche: TFlughafenWoche;
  begin
    AErster := 32;
    ALetzter := 0;
    for i := 0 to mvFlughafen.Count - 1 do begin
      LFlhObject := mvFlughafen.Objects[i] as  TFlughafen;
      ix := LFlhObject.FWochen.IndexOf(AWoche);
      if ix >= 0 then begin
        LWoche := LFlhObject.FWochen.Objects[ix] as TFlughafenWoche;
        for j := 0 to LWoche.FTage.Count - 1 do begin
          LTag := StrToIntDef(LWoche.FTage[j], -1);
          if LTag > 0 then begin
            AErster := Min(AErster, LTag);
            ALetzter := Max(ALetzter, LTag);
          end;
        end;
      end; // if ix >= 0
    end; // for i := 0 to
  end; // procedure lokErsterLetzterTag

begin
  LWoche1 := List[Index1];
  LWoche2 := List[Index2];
  result := AnsiCompareStr(copy(LWoche1, 1, 7), copy(LWoche2, 1, 7));
  if (result = 0) and (LWoche1 <> LWoche2) then begin
    lokErsterLetzterTag(LWoche1, LErster1, LLetzter1);
    lokErsterLetzterTag(LWoche2, LErster2, LLetzter2);
    if LLetzter1 < LErster2 then
      result := -1
    else if LLetzter2 < LErster1 then
      result := 1
    else
      result := AnsiCompareStr(copy(LWoche1, 8, 1), copy(LWoche2, 8, 1));
  end;
end; // function WochenSort

function FlughafenSort2(List: TStringList; Index1, Index2: Integer): Integer;
var
  LFh1, LFh2: TFlughafen;
  LName1, LName2: string;
  LMinPreis1, LMinPreis2: currency;

  function lokMinPreis(AName: string): currency;
  var
    i, j: integer;
    LName: string;
    LFh: TFlughafen;
  begin
    result := 10000;
    for i := 0 to List.Count - 1 do begin
      LName := copy(List[i], 1, Pos('|', List[i]) - 1);
      if LName = AName then begin
        LFh := List.Objects[i] as TFlughafen;
        for j := 0 to LFh.FZuschlag.Count - 1 do
          result := System.Math.Min(result, StrToCurrDef(LFh.FZuschlag[j], 0));
      end;
    end;
  end; // function lokMinPreis

begin
  LFh1 := List.Objects[Index1] as TFlughafen;
  LFh2 := List.Objects[Index2] as TFlughafen;
  LName1 := copy(List[Index1], 1, Pos('|', List[Index1]) - 1);
  LName2 := copy(List[Index2], 1, Pos('|', List[Index2]) - 1);
  LMinPreis1 := lokMinPreis(LName1);
  LMinPreis2 := lokMinPreis(LName2);
  result := round(LMinPreis1 * 100 - LMinPreis2 * 100);
  if result = 0 then
    result := AnsiCompareText(List[Index1], List[Index2]);
end;

function TT_Busrouten_Print3Sort(List: TStringList; Index1, Index2: Integer): Integer;
var
  LMonat1, LMonat2: TBusroutenMonat;
begin
  LMonat1 := List.Objects[Index1] as TBusroutenMonat;
  LMonat2 := List.Objects[Index2] as TBusroutenMonat;
  result := AnsiCompareStr(LMonat1.FJahr, LMonat2.FJahr);
  if result = 0 then
    result := AnsiCompareStr(LMonat1.FMonat, LMonat2.FMonat);
  if result = 0 then
    result := LMonat1.FMinTag - LMonat2.FMinTag;
end;

procedure TBafXlsModule.ttBusrouten;
// Macht eine Tabelle für den Folder - PLZ-Gebiete untereinander
var
  LFileName, LSql, LKey: string;
  LDataSet: TDataSet;
  LParams: TBafParams;
  LKlammer, LMin, ix: integer;
  slMonate, slDatum, slWork: TStringList;
  LBusroutenMonat: TBusroutenMonat;
  LBusroutenTag: TBusroutenTag;
  LHoz: array[0..9] of string;

  procedure lokRead;
  begin
    LKey := LDataSet.FieldByName('jahr').AsString + ' - '
      + LDataSet.FieldByName('monat').AsString + ' - '
      + LDataSet.FieldByName('sz').AsString;
    ix := slMonate.IndexOf(LKey);
    if ix < 0 then begin
      LBusroutenMonat := TBusroutenMonat.Create;
      LBusroutenMonat.FJahr := LDataSet.FieldByName('jahr').AsString;
      LBusroutenMonat.FMonat :=  LDataSet.FieldByName('monat').AsString;
      LBusroutenMonat.FZuschlag := LDataSet.FieldByName('sz').AsString;
      LBusroutenMonat.FMinTag := 31;
      slMonate.AddObject(LKey, LBusroutenMonat);
    end
    else
      LBusroutenMonat := (slMonate.Objects[ix] as TBusroutenMonat);
    if LDataSet.FieldByName('tag').AsInteger < LBusroutenMonat.FMinTag then
      LBusroutenMonat.FMinTag := LDataSet.FieldByName('tag').AsInteger;
    LBusroutenTag := TBusroutenTag.Create;
    LBusroutenTag.FPLZ := LDataSet.FieldByName('plz').AsInteger;
    LBusroutenTag.FTag := LDataSet.FieldByName('tag').AsString;
    LBusroutenTag.FCount := LDataSet.FieldByName('cnt').AsInteger;
    LKey := LDataSet.FieldByName('plz').AsString + ' - '
        + LDataSet.FieldByName('tag').AsString;
    LBusroutenMonat.FPlz.AddObject(LKey, LBusroutenTag);
    slDatum.Add(LDataSet.FieldByName('jahr').AsString
        + LDataSet.FieldByName('monat').AsString
        + LDataSet.FieldByName('tag').AsString);
  end; // procedure lokRead

  procedure lokHoz;
  var
    i, ix: integer;
    s: string;
  begin
    slWork.DelimitedText := LDataSet.FieldByName('hoz').AsString;
    ix := LDataSet.FieldByName('plz').AsInteger;
    for i := 0 to slWork.Count - 1 do begin
      s := slWork[i];
      if Pos(s, LHoz[ix]) = 0 then
        LHoz[ix] := LHoz[ix] + ', ' + s;
    end;
  end; // procedure lokHoz

  procedure lokHeader;
  var
    i: integer;
    s: string;
  begin
    FSheet := FExport.AddWorkSheet('Tabelle');
    FSheetRow := FSheet.AddRow;
    FSheetRow.AddCellString('Reisemonat').SetWidth(150).
        SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
    FSheetRow.AddCellString('Halteortzuschlag').SetWidth(150).
        SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
    slMonate.CustomSort(TT_Busrouten_Print3Sort);
    for i := 0 to slMonate.Count - 1 do begin
      LBusroutenMonat := slMonate.Objects[i] as  TBusroutenMonat;
      case StrToIntDef(LBusroutenMonat.FMonat, -1) of
        1: s := 'Januar';
        2: s := 'Februar';
        3: s := 'März';
        4: s := 'April';
        5: s := 'Mai';
        6: s := 'Juni';
        7: s := 'Juli';
        8: s := 'August';
        9: s := 'September';
        10: s := 'Oktober';
        11: s := 'November';
        12: s := 'Dezember';
      end;
      FSheetRow.AddCellString(s + ' ' + LBusroutenMonat.FJahr).
          SetColSpan(LBusroutenMonat.FCellCount).
          SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium).
          SetAlignment(cahCenter);
      // uns jetzt sortieren wir auch noch nach PLZ und Tag
      LBusroutenMonat.FPlz.Sort;
    end;
  end; // procedure lokHeader

  procedure lokFooter;
  var
    i: integer;
  begin
    FSheetRow := FSheet.AddRow;
    FSheetRow.AddCellString('Saisonzuschlag [€]').
        SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
    FSheetRow.AddCellString('').
        SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
    for i := 0 to slMonate.Count - 1 do begin
      LBusroutenMonat := slMonate.Objects[i] as  TBusroutenMonat;
      FSheetRow.AddCellString(LBusroutenMonat.FZuschlag).
        SetColSpan(LBusroutenMonat.FCellCount).
        SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium).
        SetAlignment(cahCenter);
    end;
  end; // procedure lokFooter

  procedure lokData;
  var
    LPlz, LMonat, i, LCount: integer;
  begin
    for LPlz := 0 to 9 do begin
      FSheetRow := FSheet.AddRow;
      FSheetRow.AddCellString('PLZ ' + IntToStr(LPlz)).
          SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
      FSheetRow.AddCellString(copy(LHoz[LPlz], 3, MaxInt)).
          SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
      for LMonat := 0 to slMonate.Count - 1 do begin
        LBusroutenMonat := slMonate.Objects[LMonat] as TBusroutenMonat;
        LCount := LBusroutenMonat.FCellCount;
        for i := 0 to LBusroutenMonat.FPlz.Count - 1 do begin
          LBusroutenTag := LBusroutenMonat.FPlz.Objects[i] as TBusroutenTag;
          if LBusroutenTag.FPLZ = LPlz then begin
            if LBusroutenTag.FCount >= LMin then begin
              if LBusroutenTag.FCount <= LKlammer then
                FSheetRow.AddCellString(LBusroutenTag.FTag + '*').SetWidth(50).
                    SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium).
                    SetAlignment(cahCenter)
              else
                FSheetRow.AddCellString(LBusroutenTag.FTag).SetWidth(50).
                    SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium).
                    SetAlignment(cahCenter);
              dec(LCount);
            end;
          end;
        end;
        for i := LCount downto 1 do
          FSheetRow.AddCellString('').SetWidth(50).
              SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
      end;
    end;
  end; // procedure lokData

  procedure lokDataCount;
  var
    LPlz, LMonat, i, LCount: integer;
  begin
    for LPlz := 0 to 9 do begin
      for LMonat := 0 to slMonate.Count - 1 do begin
        LBusroutenMonat := slMonate.Objects[LMonat] as TBusroutenMonat;
        LCount := 0;
        for i := 0 to LBusroutenMonat.FPlz.Count - 1 do begin
          LBusroutenTag := LBusroutenMonat.FPlz.Objects[i] as TBusroutenTag;
          if LBusroutenTag.FPLZ = LPlz then begin
            if LBusroutenTag.FCount >= LMin then
              inc(LCount);
          end;
        end;
        if LCount > LBusroutenMonat.FCellCount then
          LBusroutenMonat.FCellCount := LCount;
      end;
    end;
  end; // procedure lokDataCount

  procedure lokDatumsliste;
  var
    i: integer;
    s, t: string;
  begin
    FSheetRow := FSheet.AddRow;
    FSheetRow := FSheet.AddRow;
    for i := 0 to slDatum.Count - 1 do begin
      s := slDatum[i];
      t := copy(s, 5, 2) + '.' + copy(s, 3, 2) + '.20' + copy(s, 1, 2);
      FSheetRow := FSheet.AddRow;
      FSheetRow.AddCellDate(StrToDateDef(t, 0)).
          SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebNone);
    end;
  end;

begin
  LKlammer := FindParamIntegerReplaced('z', 5);
  LMin := FindParamIntegerReplaced('min', 0);

  slMonate := TStringList.Create;
  slDatum := TStringList.Create;
  slWork := TStringList.Create;
  slDatum.Sorted := true;
  slDatum.Duplicates := dupIgnore;
  FExport := TOExport.Create;
  try
    LSql := FInter.GetSqlAndClear(1);
    LParams := dataMain.QueryPrepare(dataMain.DefaultCon, 'bustabelle', LSql);
    LDataSet := dataMain.QueryOpen(dataMain.DefaultCon, 'bustabelle');
    while not LDataSet.Eof do begin
      lokRead;
      lokHoz;
      LDataSet.Next;
    end;
    lokDataCount;
    lokHeader;
    lokData;
    lokFooter;
    lokDatumsliste;
    FExport.SaveToFileWithDialog('bustabelle', '', true);
  finally
    FreeAndNil(FExport);
    slWork.Free;
    slMonate.Free;
    slDatum.Free;
  end;
// procedure TBafXlsModule.ttBusrouten
end;

function DatumslisteSort(List: TStringList; Index1, Index2: Integer): Integer;
var
  LDate1, LDate2: TDate;
begin
  LDate1 := StrToDateDef(List[Index1], 0);
  LDate2 := StrToDateDef(List[Index2], 0);
  result := round(LDate1 - LDate2);
end;

procedure TBafXlsModule.ttFlugtabelle;
var
  LSql, LZus1, LZus2, LZus3, LVt, LVtChar, LId, LHeaderLine: string;
  LWochen, LSonder, slDatum: TStringList;
  LFlhObject: TFlughafen;

  function lokGetSonder(AWert, AText: string): string;
  var
    s: string;
    ix: integer;
  begin
    result := '';
    if AText <> '' then begin
      s := AWert + ' - ' + AText;
      ix := LSonder.IndexOf(s);
      if ix = -1 then
        ix := LSonder.Add(s);
      result := Format('(%d)', [ix + 1]);
    end;
  end; // function lokGetSonder

  procedure lokQueryData(APara: string; AKg: boolean);
  var
    LParams: TBafParams;
    LDataset: TDataset;
    LFlh: TFlughafen;
    LFlhName, LWo, LSo: string;
    ix, LZuschlagIx, LZuschlagWert: integer;
    LDatum: TDate;
  begin
    LId := FindParamStringReplaced(APara, '');
    if Length(LId) > 30 then begin
      LParams := dataMain.QueryPrepare(dataMain.DefaultCon, 'flugtabelle',
        'select kuerzel   from xr_jahr j   where j.xr_jahr_id = :kid');
      LParams.ParamAsString('kid', LId);
      LDataSet := dataMain.QueryOpen(dataMain.DefaultCon, 'flugtabelle');
      if not LDataSet.Eof then begin
        if AKg then
          LHeaderLine := LHeaderLine + ' / ' + LDataSet.Fields[0].AsString
        else
          LHeaderLine := LDataSet.Fields[0].AsString;
      end;
      LParams := dataMain.QueryPrepare(dataMain.DefaultCon, 'flugtabelle', LSql);
      LParams.ParamAsString('kid', LId);
      LDataSet := dataMain.QueryOpen(dataMain.DefaultCon, 'flugtabelle');
      LZuschlagIx := 0;
      LZuschlagWert := LDataset.FieldByName('saison_zuschlag').AsInteger;
      while not LDataSet.Eof do begin
        LFlhName := LDataset.FieldByName('name').AsString + '|'
            + LDataset.FieldByName('flh_zuschlag').AsString;
        ix := mvFlughafen.IndexOf(LFlhName);
        if ix < 0 then
          ix := mvFlughafen.AddObject(LFlhName, TFlughafen.Create);
        LFlh := mvFlughafen.Objects[ix] as TFlughafen;
        slDatum.Add(LDataset.FieldByName('ft').AsString);
        LDatum := StrToDateDef(LDataset.FieldByName('ft').AsString, -1);
        if LDatum > 0 then begin
          if LZuschlagWert <> LDataset.FieldByName('saison_zuschlag').AsInteger then begin
            inc(LZuschlagIx);
            LZuschlagWert := LDataset.FieldByName('saison_zuschlag').AsInteger;
          end;
          LSo := lokGetSonder(LDataset.FieldByName('soz_wert').AsString,
              LDataset.FieldByName('soz_text').AsString);
          LFlh.AddDaten(LDataset.FieldByName('flh_zuschlag').AsString,
              LDataset.FieldByName('saison_zuschlag').AsString,
              LVt, LVtChar, LSo, LDatum, AKg, LZuschlagIx);
          LWo := FormatDateTime('yy-mm', LDatum) + '-'
              + IntToStr(BafWeekOfTheMonth(LDatum)) + IfThen(AKg, 'K', 'A')
              + IntToStr(LZuschlagIx);
          LWochen.AddObject(LWo,
              TObject(LDataset.FieldByName('saison_zuschlag').AsInteger));
        end;
        LDataSet.Next;
      end;
    end;
  end; // procedure lokQueryData

  procedure lokCell(AText: string; AWidth, AColSpan, ARowSpan: integer;
      AColor: TColor = clWhite; AAlignment: TCellHAlignment = cahCenter);
  begin
    with FSheetRow.AddCellString(AText) do begin
      SetWidth(AWidth);
      SetFontStyle([TFontStyle.fsBold]);
      SetFontSize(11);
      SetColSpan(AColSpan);
      SetRowSpan(ARowSpan);
      SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebMedium);
      SetAlignment(AAlignment);
      SetVAlignment(cavCenter);
      SetBGColor(AColor);
    end;
  end; // procedure lokCell

  procedure lokHeader;
  var
    i, LCount: integer;
    LWo, LWoAlt: string;

    procedure lokHeaderWoche;
    var
      LMonatName: string;
    begin
      LMonatName := FormatDateTime('mmmm yy', StrToDate('01.'
          + copy(LWoAlt, 4, 2) + '.' + copy(LWoAlt, 1, 2)));
      lokCell(LMonatName, 40, LCount, 1);
      LCount := 1;
      LWoAlt := LWo
    end; // procedure lokHeaderWoche

  begin
    FSheetRow := FSheet.AddRow;
    FSheetRow.AddCellString(LHeaderLine);
    FSheetRow := FSheet.AddRow;
    FSheetRow := FSheet.AddRow;
    FSheetRow.SetHeight(40);
    lokCell('Flughafen', 160, 1, 1);
    lokCell('Aufpreis', 80, 1, 1);
    LCount := 0;
    if LWochen.Count > 0 then
      LWoAlt := copy(LWochen[0], 1, 5)
    else
      raise Exception.Create('Keine Wochen... sind denn die Flugkontingente korrekt angelegt?');
    for i := 0 to LWochen.Count - 1 do begin
      LWo := copy(LWochen[i], 1, 5);
      if LWo <> LWoAlt then
        lokHeaderWoche
      else
        inc(LCount);
    end;
    lokHeaderWoche;
  end; // procedure lokHeader

  procedure lokFahrtage(ARowCount: integer);
  var
    LRow, LWch, ix: integer;
    LWoche: TFlughafenWoche;
    LWochenname: string;
    LColor: TColor;
  begin
//    Clipboard.AsText := LWochen.Text;
    for LRow := 0 to ARowCount - 1 do begin
      if LRow > 0 then begin
        FSheetRow := FSheet.AddRow;
        FSheetRow.AddCellString('');
        FSheetRow.AddCellString('');
      end;
      for LWch := 0 to LWochen.Count - 1 do begin
        LWochenname := LWochen[LWch];
        if LWochenname[8] = 'K' then
          LColor := TColorRec.Yellow
        else
          LColor :=  TColorRec.White;
        ix := LFlhObject.FWochen.IndexOf(LWochenname);
        if ix >= 0 then begin
          LWoche := LFlhObject.FWochen.Objects[ix] as TFlughafenWoche;
          if LWoche.FTage.Count > LRow then
            lokCell(LWoche.FTage[LRow], 40, 1, 1, LColor)
          else
            lokCell('', 40, 1, 1, LColor);
        end
        else
          lokCell('', 40, 1, 1, LColor);
      end;
    end;
  end; // procedure lokFahrtage

  procedure lokSaison;
  var
    i, LZu, LZuAlt, LCount: integer;

    procedure lokSaisonCell;
    begin
      lokCell(IntToStr(LZuAlt), 40, LCount, 1, clBtnFace);
      LCount := 1;
      LZuAlt := LZu;
    end; // procedure lokSaisonCell

  begin
    FSheetRow := FSheet.AddRow;
    FSheetRow.SetHeight(24);
    lokCell('Saisonzuschlag', 160, 1, 1, clBtnFace);
    lokCell('', 80, 1, 1, clBtnFace);
    LCount := 0;
    for i := 0 to LWochen.Count - 1 do begin
      LZu := integer(LWochen.Objects[i]);
      if i = 0 then
        LZuAlt := LZu;
      if LZuAlt <> LZu then
        lokSaisonCell
      else
        inc(LCount);
    end;
    lokSaisonCell;
  end; // procedure lokSaison

  procedure lokZusatz;
  var
    i: integer;
    s: string;
  begin
    FSheetRow := FSheet.AddRow;
    FSheetRow.SetHeight(24);
    lokCell(LZus1, 160, 21, 1, clWhite, cahLeft);
    FSheetRow := FSheet.AddRow;
    FSheetRow.SetHeight(24);
    lokCell(LZus2, 160, 21, 1, clWhite, cahLeft);
    FSheetRow := FSheet.AddRow;
    FSheetRow.SetHeight(24);
    lokCell(LZus3, 160, 21, 1, clWhite, cahLeft);
    for i := 0 to LSonder.Count - 1 do begin
      FSheetRow := FSheet.AddRow;
      FSheetRow.SetHeight(24);
      s := Format('(%d) ', [i + 1]) + LSonder[i];
      lokCell(s, 160, 21, 1, clWhite, cahLeft);
    end;
  end; // procedure lokZusatz

  procedure lokDatumsliste;
  var
    i: integer;
    s, t: string;
  begin
    FSheetRow := FSheet.AddRow;
    FSheetRow := FSheet.AddRow;
    slDatum.Sorted := false;
    slDatum.CustomSort(DatumslisteSort);
    for i := 0 to slDatum.Count - 1 do begin
      s := slDatum[i];
      FSheetRow := FSheet.AddRow;
      FSheetRow.AddCellDate(StrToDateDef(s, 0)).
          SetBorders([cbTop, cbRight, cbBottom, cbLeft], ebNone);
    end;
  end;


  procedure lokExport;
  var
    i, LRowSpan: integer;
    s: string;
  begin
    FExport := TOExport.Create;
    try
      FSheet := FExport.AddWorkSheet('Tabelle');
      lokHeader;
      mvFlughafen.Sorted := false;
      mvFlughafen.CustomSort(FlughafenSort2);
      for i := 0 to mvFlughafen.Count - 1 do begin
        LFlhObject := mvFlughafen.Objects[i] as  TFlughafen;
        LRowSpan := LFlhObject.GetRowCount;
        FSheetRow := FSheet.AddRow;
        FSheetRow.SetHeight(24);
        s := copy(mvFlughafen[i], 1, Pos('|', mvFlughafen[i]) - 1);
        lokCell(s, 160, 1, LRowSpan);
        lokCell(LFlhObject.GetAufpreis, 80, 1, LRowSpan);
        lokFahrtage(LRowSpan);
      end;
      lokSaison;
      lokZusatz;
      lokDatumsliste;
      FExport.SaveToFileWithDialog('flugtabelle', '', true);
    finally
      FreeAndNil(FExport);
    end;
  end; // procedure lokExport

begin
    LSql := FInter.GetSqlAndClear(1);

    // Zusatzzeilen und Kennzeichnung für Verkehrstage
    LZus1 := FindParamStringReplaced('z1', '');
    LZus2 := FindParamStringReplaced('z2', '');
    LZus3 := FindParamStringReplaced('z3', '');
    LVt := FindParamStringReplaced('vt', '');
    LVtChar := FindParamStringReplaced('vtc', '*');

    mvFlughafen := TStringList.Create;
    try
      mvFlughafen.OwnsObjects := true;
      mvFlughafen.Sorted := true;
      mvFlughafen.Duplicates := dupError;
      LWochen := TStringList.Create;
      LSonder := TStringList.Create;
      slDatum := TStringList.Create;
      slDatum.Sorted := true;
      slDatum.Duplicates := dupIgnore;
      try
        LWochen.Sorted := true;
        LWochen.Duplicates := dupIgnore;
        lokQueryData('kid', false);
        lokQueryData('kid_kg', true);
        LWochen.Sorted := false;
        LWochen.CustomSort(WochenSort);
        lokExport;
      finally
        slDatum.Free;
        LSonder.Free;
        LWochen.Free;
      end;
    finally
      mvFlughafen.Free;
    end;
// procedure TBafXlsModule.ttFlugtabelle
end;

procedure TBafXlsModule.XlsAddCell;
var
  LCell: TExportCell;
  LValue, s, LFormula: string;
  LType: TBafPageCellType;
  LWidth: single;
  LAlign: TBafAlignment;
  LVAlignment: TCellVAlignment;
  LColor: TColor;
  LStyles: TFontStyles;
  LIndex: integer;

  procedure lokFontAndColor;
  begin
    LColor := FindParamColor('cl', clWhite);
    if LColor <> clWhite then
      LCell.SetBGColor(LColor);
    LCell.SetFontColor(FindParamColor('fc', clBlack));
    LStyles := [];
    s := FindParamStringReplacedLower('fs', '');
    if Pos('b', s) > 0 then
      Include(LStyles, TFontStyle.fsBold);
    if Pos('i', s) > 0 then
      Include(LStyles, TFontStyle.fsItalic);
    if Pos('u', s) > 0 then
      Include(LStyles, TFontStyle.fsUnderline);
    if Pos('s', s) > 0 then
      Include(LStyles, TFontStyle.fsStrikeOut);
    LCell.SetFontStyle(LStyles);
  end; // procedure lokFontAndColor

  procedure lokAlign;
  begin
    LAlign := FInter.FindParamAlignment(FExecInter.LineP, 'a', taLeftJustify);
    s := FindParamStringReplaced('va', 'l');
    case s[1] of
      'c', 'C': LVAlignment := cavCenter;
      'b', 'B': LVAlignment := cavBottom;
      else
        LVAlignment := cavTop;
    end;
    LCell.SetVAlignment(LVAlignment);
    LCell.SetAlignment(ConvertAlign(LAlign));
  end; // procedure lokAlign

  procedure lokBorders;
  var
    s: string;
  begin
    s := FindParamStringReplacedLower('bt', '');
    LCell.SetBorder(cbTop, GetBorderStyle(s));
    s := FindParamStringReplacedLower('bl', '');
    LCell.SetBorder(cbLeft, GetBorderStyle(s));
    s := FindParamStringReplacedLower('br', '');
    LCell.SetBorder(cbRight, GetBorderStyle(s));
    s := FindParamStringReplacedLower('bb', '');
    LCell.SetBorder(cbBottom, GetBorderStyle(s));
  end; // procedure lokBorders

begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LValue := FindParamStringReplaced('z', '');
    LFormula := FindParamStringReplaced('frml', '');
    LType := BafGetCellType(FindParamStringLower('y', ''));
    LIndex := FindParamIntegerReplaced('n', -1);
    if LFormula = '' then begin
      if (LIndex >= 0) then
        LCell := SetCellTyp(LIndex, LType, LValue)
      else
        LCell := AddCellTyp(LType, LValue);
    end
    else begin
      if (LIndex >= 0) then
        LCell := SetCellFormula(LIndex, LType, LFormula)
      else
        LCell := AddCellFormula(LType, LFormula);
    end;
    LWidth := FindParamSingleReplaced('w', -1);
    if LWidth >= 0 then
      LCell.SetWidth(LWidth);
    lokAlign;
    lokFontAndColor;
    lokBorders;
    LCell.ColSpan := FindParamIntegerReplaced('cs', 1);
  end;
// procedure TBafXlsModule.XlsAddCell
end;

procedure TBafXlsModule.XlsAddRow;
var
  LIndex: integer;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LIndex := FindParamIntegerReplaced('n', -1);
    if (LIndex >= 0) and (LIndex < FSheet.Rows.Count) then
      FSheetRow := FSheet.Rows.Items[LIndex]
    else
      FSheetRow := FSheet.AddRow;
    FSheetRow.Height := FindParamSingle('h', 20);
  end;
end;

procedure TBafXlsModule.XlsAddSheet;
var
  LIndex: integer;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LIndex := FindParamIntegerReplaced('n', -1);
    if (LIndex >= 0) and (LIndex < FExport.WorkSheets.Count) then
      FSheet := FExport.WorkSheets.Items[LIndex]
    else
      FSheet := FExport.AddWorkSheet(FindParamStringReplaced('c', ''));
    FSheet.WindowSettings.Split.Row := FindParamIntegerReplaced('fr', 0);
    FSheet.WindowSettings.Split.Col := FindParamIntegerReplaced('fc', 0);
  end;
end;

procedure TBafXlsModule.XlsDeleteSheet;
begin
  if FindParamBooleanReplaced('cnd', true) then
    FExport.WorkSheets.Remove(FSheet);
end;

function TBafXlsModule.XlsGetCell(AParams: TStrings): string;
var
  ix: integer;
begin
  if AParams.Count > 0 then begin
    ix := StrToIntDef(AParams[0], 0);
    result := FSheetRow.Cells[ix].SqlText;
  end
  else
    FInter.DoLog('E', '$XLS_CELL - Number of Params less 1');
end;

function TBafXlsModule.XlsGetCount(AParams: TStrings): string;
var
  s: string;
  LResult: integer;
begin
  if AParams.Count > 0 then begin
    s := AnsiLowerCase(AParams[0]);
    if s = 'sheets' then
      LResult := FExport.WorkSheets.Count
    else if s = 'rows' then
      LResult := FSheet.Rows.Count
    else if s = 'cells' then
      LResult := FSheetRow.Cells.Count
    ;
    if AParams.Count > 1 then
      LResult := LResult + StrToIntDef(AParams[1], 0);
    result := IntToStr(LResult);
  end
  else
    FInter.DoLog('E', '$XLS_COUNT - Number of Params less 1');
end;

procedure TBafXlsModule.XlsGrid;
var
  LPage: TBafPage;
  LSegName, LName: string;
  LSegment: TBafPageSegment;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LSegName := FindParamStringReplaced('i', '');
    LName := FindParamStringReplaced('n', LSegName);
    LPage := FExecInter.GetFormObject(foPage) as TBafPage;
    LSegment := LPage.PrimaryDivs.FindSegmentByName(LSegName);
    ExportSimpleGrid(LSegment.Grid, LName);
  end;
end;

procedure TBafXlsModule.XlsLoad;
var
  LFileName: string;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    if Assigned(FExport) then
      FreeAndNil(FExport);
    FExport := TOExport.Create;
    FExportInvisibleColumns := FindParamBooleanReplaced('eic', false);
    LFileName := FindParamStringReplaced('fn', '');
    if LFileName = '' then
      FExport.LoadFromFileWithDialog()
    else
      FExport.LoadFromFile(LFileName);
  end;
end;

procedure TBafXlsModule.XlsLoopRows;
var
  i, LMax: integer;
  LName, LBafConName, LEachRow: string;
  LEachRowTrans, LNoException: boolean;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LName := FindParamStringReplaced('n', '');
    LEachRow := FindParamStringReplaced('er', '');
    LBafConName := FindParamStringReplacedLower('db', DC_DEFAULT);
    LMax := FindParamIntegerReplaced('m', MaxInt);
    LEachRow := FindParamString('ern', '');
    if LEachRow = '' then
      LEachRow := FindParamStringReplaced('er', '');
    LEachRowTrans := FindParamBooleanReplaced('ert', false);
    LNoException := FindParamBooleanReplaced('nex', false);
    for i := 0 to FSheet.Rows.Count - 1 do begin
      FSheetRow := FSheet.Rows[i];
      if LName <> '' then
        FInter.Variable[LName] := IntToStr(i);    // write loop var in a var
      FExecInter.EachRow(LBafConName, LEachRow, '#xls_looprows',
          LEachRowTrans, LNoException);
      if i >= LMax then begin
        FInter.DoLog('I', Format('#xls_looprows, Max (%d) reached, loop aborted', [LMax]));
        Break;
      end;
    end;
  end;
// procedure TBafXlsModule.XlsLoopRows
end;

procedure TBafXlsModule.XlsPage;
var
  LPage: TBafPage;
  LPrim, LCat, LSeg: integer;
  LCategory: TBafPageCategory;
  LSegment: TBafPageSegment;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    if Assigned(FExport) then
      FreeAndNil(FExport);
    FExport := TOExport.Create;
    try
      LPage := FExecInter.GetFormObject(foPage) as TBafPage;
      for LPrim := 0 to LPage.PrimaryDivs.Count - 1 do begin
        for LCat := 0 to LPage.PrimaryDivs.Items[LPrim].Categories.Count - 1 do begin
          LCategory := LPage.PrimaryDivs.Items[LPrim].Categories.Items[LCat];
          for LSeg := 0 to LCategory.Segments.Count - 1 do begin
            LSegment := LCategory.Segments.Items[LSeg];
            ExportSegment(LSegment);
          end;
        end;
      end;
      FExport.SaveToFileWithDialog('baf_export', '', true);
    finally
      FreeAndNil(FExport);
    end;
  end;
end;

procedure TBafXlsModule.XlsStart;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    if Assigned(FExport) then
      FreeAndNil(FExport);
    FExport := TOExport.Create;
    FExportInvisibleColumns := FindParamBooleanReplaced('eic', false);
  end;
end;


procedure TBafXlsModule.XlsStop;
var
  LOpen: boolean;
  LFilename: string;
begin
  if FindParamBooleanReplaced('cnd', true) then begin
    LOpen := FindParamBooleanReplaced('o', true);
    LFilename := FindParamStringReplaced('fn', '');
    if LFilename = '' then
      FExport.SaveToFileWithDialog('baf_export', '', LOpen)
    else
      FExport.SaveToFile(LFilename, LOpen);
    FreeAndNil(FExport);
  end;
end;

{ TFlughafenWoche }

constructor TFlughafenWoche.Create;
begin
  FTage := TStringList.Create;
  FTage.Sorted := true;
  FTage.Duplicates := dupIgnore;
end;

destructor TFlughafenWoche.Destroy;
begin
  FreeAndNil(FTage);
  inherited;
end;

{ TFlughafen }

procedure TFlughafen.AddDaten(AZuschlag, ASaison, AVt, AVtChar, ASo: string;
  ADatum: TDate; AKgr: boolean; AZuschlagIx: integer);
var
  LWeek, LTag: string;
  ix, LDof: integer;
  LWoche: TFlughafenWoche;
begin
  FZuschlag.Add(AZuschlag);
  LWeek := FormatDateTime('yy-mm', ADatum) + '-'
      + IntToStr(BafWeekOfTheMonth(ADatum)) + IfThen(AKgr, 'K', 'A')
      + IntToStr(AZuschlagIx);
  ix := FWochen.IndexOf(LWeek);
  if ix < 0 then
    ix := FWochen.AddObject(LWeek, TFlughafenWoche.Create);
  LWoche := FWochen.Objects[ix] as TFlughafenWoche;
  LTag := FormatDateTime('dd', ADatum);
  LDof := DayOfTheWeek(ADatum); // ISO-konform
  if Pos(IntToStr(LDof), AVt) > 0 then
    LTag := LTag + AVtChar;
  if ASo <> '' then
    LTag := LTag + ' ' + ASo;
  LWoche.FTage.Add(LTag);

end;

constructor TFlughafen.Create;
begin
  FZuschlag := TStringList.Create;
  FZuschlag.Sorted := true;
  FZuschlag.Duplicates := dupIgnore;
  FWochen := TStringList.Create;
  FWochen.Sorted := true;
  FWochen.Duplicates := dupError;
end;

destructor TFlughafen.Destroy;
begin
  FreeAndNil(FWochen);
  FreeAndNil(FZuschlag);
  inherited;
end;

function TFlughafen.GetAufpreis: string;
var
  i: integer;
begin
  result := '';
  for i := 0 to FZuschlag.Count - 1 do
    result := result + ' / € ' + FZuschlag[i];
  Delete(result, 1, 3);
end;

function TFlughafen.GetRowCount: integer;
var
  LWch: integer;
  LWoche: TFlughafenWoche;
begin
  result := 1;
  for LWch := 0 to FWochen.Count - 1 do begin
    LWoche := FWochen.Objects[LWch] as TFlughafenWoche;
    result := System.Math.Max(result, LWoche.FTage.Count);
  end;
end;

{ TBusroutenMonat }

constructor TBusroutenMonat.Create;
begin
  inherited;
  FPlz := TStringList.Create;
end;

destructor TBusroutenMonat.Destroy;
begin
  FPlz.Free;
  inherited;
end;

initialization
  OExportDateFormat := 'dd.mm.yyyy';
  OExportTimeFormat := 'hh:mm:ss';

end.
