module cubetuple_transpose
  use cubetools_parameters
  use cubedag_dag
  use cubedag_tuple
  use cube_types
  use cubeio_interfaces_public
  use cubetuple_messaging
  use cubetuple_get

  public :: cubetuple_autotranspose_cube
  private

contains
  !
  subroutine cubetuple_autotranspose_cube(cube,error)
    use cubeio_cube
    use cubeio_transpose
    use cubetuple_tuple
    !-------------------------------------------------------------------
    ! If needed, perform the tranposition of the relevant file
    !-------------------------------------------------------------------
    type(cube_t), target, intent(inout) :: cube
    logical,              intent(inout) :: error
    ! Local
    character(len=*), parameter :: rname='AUTO>TRANSPOSE'
    character(len=file_l) :: ffilename,tfilename
    type(cubeio_cube_t), pointer :: cubin,cubout
    integer(kind=code_k) :: fromorder
    logical :: insertin
    !
    if (cube%tuple%trans%do.eq.code_trans_none)  return
    !
    cubin  => cube%tuple%cube(cube%tuple%trans%from)
    cubout => cube%tuple%cube(cube%tuple%trans%to)
    !
    ! Sanity
    if (.not.associated(cubout,cube%tuple%current)) then
      call cubetuple_message(seve%e,rname,  &
        'Internal error: the cube to be created is not the current one')
      error = .true.
      return
    endif
    !
    ! ZZZ The new implementation in cubeio_transpose is actually able to
    ! deal with any case (input in memory or disk, output in memory or disk).
    ! But such mismatch does not make much sense as the input and output
    ! have strictly the same size.
    select case (cube%tuple%trans%do)
    case (code_trans_memo)
      insertin = cubin%memo%ready.ne.code_buffer_memory
      call cubeio_transpose_memory(cube%user,cube%prog,cube%head,cubin,cubout,error)
      if (error)  return
      !
      if (insertin) then
        ! Avoid reinserting the direct cube and changing its timestamp if it
        ! was already in memory
        call cubedag_tuple_upsert(cube%node%tuple,cubin%order(),  &
          code_buffer_memory,'<memory>',error)
        if (error)  return
      endif
      ! The transposed cube is now in memory
      call cubedag_tuple_upsert(cube%node%tuple,cubout%order(),  &
        code_buffer_memory,'<memory>',error)
      if (error)  return
      !
    case (code_trans_disk)
      ! Sanity
      if (cubout%desc%action.ne.code_read) then
        call cubetuple_message(seve%e,rname,'Internal error: implicit '//  &
          'transposition is relevant only for cubes opened in read mode')
        error = .true.
        return
      endif
      fromorder = cube%tuple%cube(cube%tuple%trans%from)%order()
      if (.not.cubedag_tuple_hasuptodatefile(cube%node%tuple,fromorder,code_buffer_disk,ffilename,error)) then
        call cubetuple_message(seve%e,rname,'Internal error: lost the file I am looking for')
        error = .true.
        return
      endif
      if (error)  return
      !
      tfilename = cubout%file%name
      call cubeio_transpose_disk(cube%user,cube%prog,ffilename,tfilename,  &
        cube%head,cubin,cubout,error)
      if (error)  return
      !
      ! Insert this new/updated file in the tuple, and set the tuple as
      ! consistent at this precise moment
      call cubedag_tuple_upsert(cube%node%tuple,cubout%order(),code_buffer_disk,tfilename,error)
      if (error)  return
      call cubedag_tuple_setconsistent(cube%node%tuple,error)
      if (error)  return
      !
    case default
      call cubetuple_message(seve%e,rname,'Transposition mode not implemented')
      error = .true.
      return
    end select
    !
    ! Transposition is now done
    call cubetuple_trans_reset(cube%tuple%trans,error)
    if (error)  return
  end subroutine cubetuple_autotranspose_cube
  !
end module cubetuple_transpose
