module IO_m

  ! Input/Output edge for 1401 ALD

  implicit NONE
  public

  type :: IO_T
    character :: IO ! I or O
    integer :: Major = 0, Minor = 0 ! 1..9 for a..hj, 1..18 within box row
    character(10) :: Logic = ''
    character(15) :: Title(2) = ''
    integer :: Note = 0
  end type IO_T

contains

  subroutine Parse_Edge ( Line, N_Lines, Edges )
    use Logic_m, only: RowNum
    use Scan_m, only: Scan
    character(*), intent(inout) :: Line
    integer, intent(in) :: N_Lines    ! For error messages
    type(IO_t), intent(inout) :: Edges(:)

    integer :: Major, Number, Stat
    character(len=len(line)) :: Token

  1 format ( 9(a,i0) )

    call scan ( line, token )
    read ( token, *, iostat=stat ) number
    if ( stat /= 0 ) then
      print 1, 'Edge label must be an integer at line ', n_lines
      return
    end if
    if ( number < 1 .or. number > size(edges) ) then
      print 1, 'Edge label number must be in range 1..', &
        & size(edges), ' at line ', n_lines
      return
    end if

    if ( edges(number)%major /= 0 ) then
      print *, 'Duplicate edge label at line ', n_lines
      return
    end if

    call scan ( line, token )
    major = rowNum(token(1:1))
    if ( major == 0 ) then
      print 1, 'Major part of row must be in A..HJ or a..hj at line ', n_lines
      return
    end if
    read ( token(2:), *, iostat=stat ) edges(number)%minor
    if ( stat /= 0 ) then
      print 1, 'Minor part of row must be an integer at line ', n_lines
      return
    end if
    if ( edges(number)%minor < 1 .or. edges(number)%minor > 18 ) then
      print 1, 'Minor part of row must be in range 1..18 at line ', n_lines
      return
    end if
    
    call scan ( line, token )
    edges(number)%logic = token
    if ( token == '' ) then
      print 1, 'Logic number must be supplied at line ', n_lines
      return
    end if
    if ( edges(number)%logic /= token ) then
      print 1, 'Logic number must not be longer than ', len(edges(number)%logic), &
        & ' characters at line ', n_lines
      return
    end if

    do stat = 1, 3
      call scan ( line, token )
      if ( token(1:1) /= '"' .or. stat > 2 ) then
        edges(number)%title(stat:) = ''
        exit
      end if
      edges(number)%title(stat) = token(2:)
      if ( edges(number)%title(stat) /= token(2:) ) then
        print 1, 'Title(', stat, ') must not be longer than ', &
          &  len(edges(number)%title), ' characters at line ', n_lines
        return
      end if
    end do

    if ( token /= '' ) then
      if ( token(1:1) /= '*' ) then
        print 1, 'Note must begin with * at line ', n_lines
        return
      end if
      read ( token(2:), *, iostat=stat ) edges(number)%note
      if ( stat /= 0 ) then
        print 1, 'Note must be integer at line ', n_lines
        return
      end if
      if ( edges(number)%note < 1 .or. edges(number)%note > 99 ) then
        print 1, 'Note number must be in 1.99 at line ', n_lines
        return
      end if
    end if
      
    edges(number)%major = major ! Mark as used if OK

  end subroutine Parse_Edge

  subroutine Draw_Edge ( Page, Edges )

    character(*), intent(inout) :: Page(:)
    type(io_t), intent(in) :: Edges(:)
    integer :: Side                     ! 1 = left, 2 = right
    integer :: I, J, Row, K, L
    character(3) :: Note

    side = merge ( 1, 2, edges(1)%io == 'I' )
    k = 6*17 + 2 + side     ! Where to flag duplicates
    l = (side-1)*6*17 + 1
    do i = 1, size(edges)
      if ( edges(i)%major == 0 ) cycle
      row = (edges(i)%major-1)*18 + edges(i)%minor
      if ( page(row)(l:l+16) /= '' ) then
        page(row)(k:k) = 'D'
      else
        select case ( edges(i)%note )
        case ( 0 )
          note = '---'
        case ( 1:9 )
          write ( note, '("-*",i1)' ) edges(i)%note
        case ( 10:99 )
          write ( note, '("*",i2)' ) edges(i)%note
        end select
        if ( side == 1 ) then
          page(row)(l+1:l+14) = edges(i)%logic // '-' // note
        else
          page(row)(l:l+14) = note // '-' // edges(i)%logic
        end if
      end if
      if ( edges(i)%title(1) == '' ) cycle
      if ( edges(i)%title(2) == '' ) then
        if ( row < 2 ) then
          page(row)(k+2+side:k+2+side) = '^'
        else if ( page(row-1)(l:l+16) /= '' ) then
              page(row-1)(k:k) = 'D'
        else if ( side == 1 ) then
          page(row-1)(l:l+16) = edges(i)%title(1)
        else
          page(row-1)(l:l+16) = '  ' // edges(i)%title(1)
        end if
      else
        do j = 1, 2
          if ( edges(i)%title(j) /= '' ) then
            if ( row-j <= 0 ) then
              page(row)(k+2+side:k+2+side) = '^'
            else if ( page(row-3+j)(l:l+16) /= '' ) then
              page(row-3+j)(k:k) = 'D'
            else if ( side == 1 ) then
              page(row-3+j)(l:l+16) = edges(i)%title(j)
            else
              page(row-3+j)(l:l+16) = '  ' // edges(i)%title(j)
            end if
          end if
        end do
      end if
    end do

  end subroutine Draw_Edge

end module IO_m
