module Output_m

  implicit None

  public

  character(120) :: Line = ''

  integer :: Pos = 0 ! Position of last used character in Line

  integer, private :: I ! just to give the name a type

  integer :: Tab(30) = (/ ( i*5, i=1,30 ) /)

  integer :: Places = 5 ! Places after decimal point for fixed-point output

  interface TypeFixed
    module procedure TypeFixedDouble, TypeFixedSingle
  end interface

  interface TypeFloat
    module procedure TypeFloatDouble, TypeFloatSingle
  end interface

contains

  subroutine Position ( Tabs, CRs )
    integer, intent(in) :: Tabs ! to do at the end
    integer, intent(in) :: CRs  ! Carriage returns to do
    integer :: I
    do i = 1, Crs
      write ( *, '(a)' ) trim(line)
      line = ''
      pos = 0
    end do
    call nextTab ( tabs )
  end subroutine Position

  subroutine TabulatingNumber ( Number )
    ! Type tabulating number and tab
    integer, intent(in) :: Number ! to be typed, followed by tab
    pos = min(pos,len(line)-5)
    write ( line(pos+1:), '(i4)' )
    pos = len_trim(line)
    call nextTab ( 1 )
  end subroutine TabulatingNumber

  subroutine TypeFixedDouble ( Word, Tabs, CRs )
    double precision, intent(in) :: Word
    integer, intent(in) :: Tabs ! after the number
    integer, intent(in) :: CRs  ! carriage returns after the number
    character :: TheFormat*8, Formatted*20
    write ( theFormat, "('(f20.',i2,')')" ) places
    write ( formatted, theFormat ) word
    formatted = adjustl(formatted)
    pos = min(pos,len(line)-len_trim(formatted)-1)
    line(pos+1:) = trim(formatted)
    pos = pos + len_trim(formatted)
    call position ( tabs, CRs )
  end subroutine TypeFixedDouble

  subroutine TypeFixedSingle ( Word, Tabs, CRs )
    real, intent(in) :: Word
    integer, intent(in) :: Tabs ! after the number
    integer, intent(in) :: CRs  ! carriage returns after the number
    character :: TheFormat*8, Formatted*20
    write ( theFormat, "('(f20.',i2,')')" ) places
    write ( formatted, theFormat ) word
    formatted = adjustl(formatted)
    pos = min(pos,len(line)-len_trim(formatted)-1)
    line(pos+1:) = trim(formatted)
    pos = pos + len_trim(formatted)
    call position ( tabs, CRs )
  end subroutine TypeFixedSingle

  subroutine TypeFloatDouble ( Word, Tabs, CRs )
    double precision, intent(in) :: Word
    integer, intent(in) :: Tabs ! after the number
    integer, intent(in) :: CRs  ! carriage returns after the number
    integer :: TheExp
    double precision :: TheFrac
    theExp = exponent(word)
    theFrac = fraction(word)
    pos = min(pos,len(line)-17)
    write ( line(pos+1:), '(f16.12)' ) sign(50+theExp+theFrac,word)
    pos = pos + 16
    call position ( tabs, CRs )
  end subroutine TypeFloatDouble

  subroutine TypeFloatSingle ( Word, Tabs, CRs )
    real, intent(in) :: Word
    integer, intent(in) :: Tabs ! after the number
    integer, intent(in) :: CRs  ! carriage returns after the number
    integer :: TheExp
    real :: TheFrac
    theExp = exponent(word)
    theFrac = fraction(word)
    pos = min(pos,len(line)-10)
    write ( line(pos+1:), '(f9.5)' ) sign(50+theExp+theFrac,word)
    pos = pos + 12
    call position ( tabs, CRs )
  end subroutine TypeFloatSingle

! ----- Private procedures  --------------------------------------------

  subroutine NextTab ( Tabs )
    integer, intent(in) :: Tabs ! Number of tabs to advance
    integer :: I
    do i = 1, size(tab)
      if ( pos < tab(i) ) exit
    end do
    i = i + tabs - 1
    if ( i > size(tab) ) then
      pos = len(line)
    else
      pos = min(tab(i),len(line))
    end if
  end subroutine NextTab

end module Output_m
