module Logic_m

  ! Logic boxes for ALD's

  implicit NONE
  public

  type :: Logic_T
    integer :: Row ! 1--10 for a-j input
    integer :: Col ! 2--6
    character(10) :: Title    = ''
    character(4) :: Type      = ''
    character(4) :: Symbol    = ''
    character :: EC           = ''
    character(3) :: Loc       = ''
    character(2) :: In, Out   = '' ! tags
    character(2) :: Sub       = ''
    character(3) :: Pins(8,2) = ''
  end type Logic_T

  ! Pin/Tie points, A-H on left, S-Z on right
  character(*), parameter :: PinTie = 'ABCDEFGHSTUVWXYZabcdefghstuvwxyz'

  ! Row labels for boxes
  character(*), parameter :: Rows = 'ABCDEFGHJabcdefghj'

contains

  subroutine Parse_Logic ( Line, N_Lines, Boxes )

    use Scan_m, only: Scan

    character(*), intent(inout) :: Line
    integer, intent(in) :: N_Lines
    type(logic_t), intent(inout) :: Boxes(9,2:6)

    type(logic_t) :: Empty_Box
    integer :: I, J ! Row, Col
    integer :: K    ! Pin label row
    integer :: Stat
    character(255) :: Token

    ! Get row/col
    call scanTest ( 'row/col', *9 )
    read ( token(1:1), '(i1)', iostat=stat ) j
    if ( stat /= 0 ) j = 0
    if ( j < 2 .or. j > 6 ) then
      print *, 'Column number must be in 2..6 at line', n_lines
      return
    end if
    i = rowNum(token(2:2))
    boxes(i,j)%row = i
    boxes(i,j)%col = j
    if ( boxes(i,j)%type /= '' ) then
      print *, 'Duplicate definition for logic at ' // token(1:2) // &
        & ' at line', n_lines
    end if
    ! Get type
    call scanTest ( 'type', *9 )
    ! Default values for %Pins
    boxes(i,j)%pins(:,1) = '  |'
    boxes(i,j)%pins(:,2) = '|  '
    boxes(i,j)%type = token
    ! Get symbol
    call scanTest ( 'symbol', *9 )
    boxes(i,j)%symbol = token
    ! Get input tag
    call scanTest ( 'input tag', *9 )
    boxes(i,j)%in = token
    if ( boxes(i,j)%in == '.' ) boxes(i,j)%in = ''
    ! Get output tag
    call scanTest ( 'output tag', *9 )
    boxes(i,j)%out = token
    if ( boxes(i,j)%out == '.' ) boxes(i,j)%out = ''
    boxes(i,j)%out = adjustr(boxes(i,j)%out)
    ! Get EC
    call scanTest ( 'EC', *9 )
    boxes(i,j)%ec = token
    ! Get loc
    call scanTest ( 'Loc', *9 )
    boxes(i,j)%loc = token
    ! Get sub
    call scanTest ( 'Sub', *9 )
    boxes(i,j)%sub = token
    ! Get title
    call scan ( line, token )
    if ( token(1:1) /= '*' ) then
      k = len_trim(token)
      boxes(i,j)%title = token(2:k-1) ! trim off quotes
      call scan ( line, token )
    end if
    ! Get pin/tie labels
    do
      if ( token == '' ) return
      k = index(pinTie,token(2:2))
      if ( k == 0 ) then
        print *, 'Invalid Pin/Tie for logic at line', n_lines
        go to 9
      end if
      if ( k > len(pinTie)/2 ) k = k - len(pinTie)/2
      if ( k <= len(pinTie)/4 ) then
        if ( token(3:3) == '*' ) then
          print *, 'Input Pin/Tie begins with * at line', n_lines
          go to 9
        end if
        boxes(i,j)%pins(k,1) = token(3:4) // '|'
      else
        if ( token(3:3) /= '*' ) token(3:5) = '|' // token(3:4)
        boxes(i,j)%pins(k - len(pinTie)/4,2) = token(3:5)
      end if
      call scan ( line, token )
    end do
  9 boxes(i,j) = empty_box

  contains

    subroutine ScanTest ( what, * )
      ! Scan for a token and test whether there is one
      character(len=*), intent(in) :: What
      call scan ( line, token )
      if ( token == '' ) then
        print *, 'Missing ', trim(adjustl(what)), &
          & ' for logic at line', n_lines
        return 1
      end if
    end subroutine ScanTest

  end subroutine Parse_Logic

  integer function RowNum ( Row )
    character, intent(in) :: Row
    rowNum = index(rows,row)
    if ( rowNum > len(rows)/2 ) rowNum = rowNum - len(rows)/2
  end function RowNum

  subroutine Draw_Logic ( Page, Box, MFI, FR_CH )
    character(*), intent(inout) :: Page(:)
    type(logic_t), intent(in) :: Box
    character(*), intent(in) :: MFI, FR_CH
    character(4), parameter :: B = '    '
    integer :: K, L, M
    if ( box%type /= '' ) then
      k = ( box%row -1 ) * 18
      l = ( box%col -1 ) * 17
      page(k+3)(l+5:l+14) = box%title
      do m = 1, size(box%pins,1)
        page(k+m+3)(l+5:l+7) = box%pins(m,1)
        page(k+m+3)(l+12:l+14) = box%pins(m,2)
      end do
      page(k+ 4)(l+7:l+12) = '------'
      page(k+ 5)(l+8:l+11) = b(1:min(2,4-len_trim(box%symbol))) // &
                           & box%symbol
      page(k+ 6)(l+8:l+11) = MFI
      page(k+ 7)(l+8:l+11) = box%in // box%out
      page(k+ 8)(l+8:l+11) = fr_ch(1:3) // box%ec
      page(k+ 9)(l+8:l+11) = fr_ch(4:4) // box%loc
      page(k+10)(l+8:l+11) = box%type
      page(k+11)(l+7:l+12) = '--' // box%sub // '--'
      write ( page(k+12)(l+9:l+9), '(i1)' ) box%col
      page(k+12)(l+10:l+10) = rows(box%row:box%row)
    end if
  end subroutine Draw_Logic

end module Logic_m
