!> @file output_format_list.f90
!> @brief Parse a space/comma-separated output_format list and derive per-format
!!        filenames. Pure string utility — no solver dependency.
module output_format_list
  implicit none
  private
  public :: parse_format_list, ext_for_format, derived_filename, max_formats

  integer, parameter :: max_formats = 4

contains

  !> Split `spec` on spaces/commas into deduped tokens validated against
  !! `allowed`. Assumes `spec` is already lowercased by the config layer.
  subroutine parse_format_list(spec, allowed, tokens, n, is_ok, message)
    character(len=*), intent(in) :: spec
    character(len=*), intent(in) :: allowed(:)
    character(len=8), intent(out) :: tokens(max_formats)
    integer, intent(out) :: n
    logical, intent(out) :: is_ok
    character(len=*), intent(out) :: message

    character(len=len(spec)) :: work
    integer :: i, j, k
    character(len=8) :: tok
    logical :: is_allowed, is_dup

    is_ok = .false.; message = ''; n = 0; tokens = ''

    work = spec
    do i = 1, len(work)
      if (work(i:i) == ',') work(i:i) = ' '
    end do

    i = 1
    do
      do while (i <= len(work))
        if (work(i:i) /= ' ') exit
        i = i + 1
      end do
      if (i > len(work)) exit
      j = i
      do while (j <= len(work))
        if (work(j:j) == ' ') exit
        j = j + 1
      end do
      if (j - i > len(tok)) then
        message = 'output_format: token too long'; return
      end if
      tok = work(i:j - 1)
      i = j

      is_allowed = .false.
      do k = 1, size(allowed)
        if (trim(tok) == trim(allowed(k))) then
          is_allowed = .true.; exit
        end if
      end do
      if (.not. is_allowed) then
        message = 'output_format: unknown token "'//trim(tok)//'"'; return
      end if

      is_dup = .false.
      do k = 1, n
        if (trim(tokens(k)) == trim(tok)) then
          is_dup = .true.; exit
        end if
      end do
      if (.not. is_dup) then
        if (n == max_formats) then
          message = 'output_format: too many formats (max 4)'; return
        end if
        n = n + 1
        tokens(n) = tok
      end if
    end do

    if (n == 0) then
      message = 'output_format: empty list'; return
    end if
    is_ok = .true.
  end subroutine parse_format_list

  !> Canonical file extension for a format token.
  pure function ext_for_format(token) result(ext)
    character(len=*), intent(in) :: token
    character(len=4) :: ext
    select case (trim(token))
    case ('dat'); ext = '.dat'
    case ('vtk'); ext = '.vtk'
    case ('tec'); ext = '.tec'
    case ('plt'); ext = '.plt'
    case default; ext = '.dat'
    end select
  end function ext_for_format

  !> Derive the output filename for `token`. One format -> base verbatim;
  !! many formats -> stem (a trailing known extension stripped) + canonical ext.
  function derived_filename(base, token, n_formats) result(fname)
    character(len=*), intent(in) :: base, token
    integer, intent(in) :: n_formats
    character(len=:), allocatable :: fname
    character(len=:), allocatable :: stem
    integer :: m

    if (n_formats <= 1) then
      fname = trim(base)
      return
    end if

    stem = trim(base)
    m = len(stem)
    if (m >= 4) then
      select case (stem(m - 3:m))
      case ('.dat', '.vtk', '.tec', '.plt')
        stem = stem(1:m - 4)
      end select
    end if
    fname = stem//trim(ext_for_format(token))
  end function derived_filename

end module output_format_list
