//
// This function include is meant to be used as an inner function!
//
// It requires the following variable declared in the outer scope:
//  readBuffer: RGMReadLineBuffer;
//

function ReadNextLine(const ASrcStream: ISequentialStream; const ACharKind: TGMCharKind; var ALine: TGMString; var ALineEnd: EGMLineEndKind; const ACaller: TObject): Boolean;
const cLineEndLF: array [Boolean] of EGMLineEndKind = (lekLF, leLFCR);
      cLineEndCR: array [Boolean] of EGMLineEndKind = (lekCR, lekCRLF);
//var byteLine: RawByteString; unicodeLine: TGMString; readMore: Boolean;

  function ReadByteChar(var ACh: AnsiChar): Boolean; inline;
  begin
    if readBuffer.byteBufChPos > readBuffer.bufByteCount then
     begin
      GMHrCheckObj(ASrcStream.Read(PAnsiChar(readBuffer.byteBuffer), Length(readBuffer.byteBuffer), @readBuffer.bufByteCount), ACaller, {$I %CurrentRoutine%});
      readBuffer.byteBufChPos := 1;
     end;
    Result := readBuffer.byteBufChPos <= readBuffer.bufByteCount;

    if Result then begin ACh := readBuffer.byteBuffer[readBuffer.byteBufChPos]; Inc(readBuffer.byteBufChPos, SizeOf(AnsiChar)); end;
  end;

  //function ReadUnicodeChar(var ACh: UnicodeChar): Boolean; inline;
  //var byteCh1, byteCh2: AnsiChar;
  //begin
  //  Result := ReadByteChar(byteCh1) and ReadByteChar(byteCh2);
  //  if Result then Word(ACh) := Ord(byteCh2) shl 8 + Ord(byteCh1);
  //end;

  function ReadUnicodeChar(var ACh: UnicodeChar): Boolean; inline;
  begin
    if readBuffer.byteBufChPos > readBuffer.bufByteCount then
     begin
      GMHrCheckObj(ASrcStream.Read(PAnsiChar(readBuffer.byteBuffer), Length(readBuffer.byteBuffer), @readBuffer.bufByteCount), ACaller, {$I %CurrentRoutine%});
      readBuffer.byteBufChPos := 1;
     end;
    Result := readBuffer.byteBufChPos <= readBuffer.bufByteCount-1; // <- SizeOf(UnicodeChar)

    if Result then begin ACh := PUnicodeChar(@readBuffer.byteBuffer[readBuffer.byteBufChPos])^; Inc(readBuffer.byteBufChPos, SizeOf(UnicodeChar)); end;
  end;

  function ReadByteLine: RawByteString;
  var ch, nextCh: AnsiChar; // byteBufRes: RGMGenericStringBuilder<RawByteString>;
  begin
    //byteBufRes.Len := 0;
    Result := '';
    While ReadByteChar(ch) do
     begin
      case ch of
       #10: begin
             if not ReadByteChar(nextCh) then begin ALineEnd := cLineEndLF[false]; end
             else
              begin
               ALineEnd := cLineEndLF[nextCh = #13];
               if nextCh <> #13 then Dec(readBuffer.byteBufChPos, SizeOf(AnsiChar)); // <- put last char back
              end;

             Break; // <- Breaks the loop not the case statement
            end;

       #13: begin
             if not ReadByteChar(nextCh) then begin ALineEnd := cLineEndCR[false]; end
             else
              begin
               ALineEnd := cLineEndCR[nextCh = #10];
               if nextCh <> #10 then Dec(readBuffer.byteBufChPos, SizeOf(AnsiChar)); // <- put last char back
              end;

             Break; // <- Breaks the loop not the case statement
            end;

        //else byteBufRes += ch;
        else Result += ch; // <- Using RGMStringBuilder<RawByteString> here is slower!
       end;
     end;

    //Result := byteBufRes;
  end;

  function ReadUnicodeLine: UnicodeString;
  var ch, nextCh: UnicodeChar;
  begin
    Result := '';
    While ReadUnicodeChar(ch) do
     begin
      case ch of
       #10: begin
             if not ReadUnicodeChar(nextCh) then begin ALineEnd := cLineEndLF[false]; end
             else
              begin
               ALineEnd := cLineEndLF[nextCh = #13];
               if nextCh <> #13 then Dec(readBuffer.byteBufChPos, SizeOf(UnicodeChar)); // <- put last char back
              end;

             Break; // <- Breaks the loop not the case statement
            end;

       #13: begin
             if not ReadUnicodeChar(nextCh) then begin ALineEnd := cLineEndCR[false]; end
             else
              begin
               ALineEnd := cLineEndCR[nextCh = #10];
               if nextCh <> #10 then Dec(readBuffer.byteBufChPos, SizeOf(UnicodeChar)); // <- put last char back
              end;

             Break; // <- Breaks the loop not the case statement
            end;

        else Result += ch; // <- Using RGMStringBuilder<UnicodeString> here is slower!
       end;
     end;
  end;

begin
  if ASrcStream = nil then begin ALine := ''; ALineEnd := lekUnknown; Exit(false); end;

  case ACharKind of
   ckAnsi: ALine := ReadByteLine;
   ckUtf8: ALine := Utf8Decode(ReadByteLine);
   ckUtf16LE: ALine := ReadUnicodeLine;
   else begin ALine := ''; ALineEnd := lekUnknown; Exit(false); end;
  end;

  Result := (readBuffer.bufByteCount > 0) or (Length(ALine) > 0);
end;