MODULE input
    USE definitions
    IMPLICIT NONE

CONTAINS    
  SUBROUTINE read_data(alpha, beta, x, obs)
    ! This subroutine reads the data.
    IMPLICIT NONE

    TYPE(variables_real), INTENT(INOUT) :: alpha
    TYPE(variables_int), INTENT(INOUT) :: beta

    TYPE(variables_int), INTENT(INOUT) :: x
    TYPE(variables_int), INTENT(INOUT) :: obs    

    INTEGER :: i, j, temp, next
    ! INTEGER :: space_index
    TYPE(variable_int) :: current
    ! HARD-CODED: the maximum line length that occurs in the data file
    !    CHARACTER(LEN=3000) :: buffer 
    
    !   CHARACTER(LEN=3000) :: temp
    ! HARD-CODED: the data file name(s)
    ! these have been generated: the observations_1 file has zeros on the
    ! places where the original had *-signs. This makes reading it easier.
    ! the observations_missing has the places of the missing variables
    ! in a matrix of boolean values (0, 1).
    CHARACTER(LEN=*), PARAMETER :: data_filename='observations_1.txt'
    CHARACTER(LEN=*), PARAMETER :: data_missing='observations_missing.txt'
    
    OPEN(UNIT=16, FILE=data_filename)
    OPEN(UNIT=17, FILE=data_missing)
    
    next = 1
    
    ! these loop lengths come from the generator. 
    ! These are the dimensions of the data array (obs), and should match
    ! the dimensions of the matrix in the file.

    ! HARD-CODED: the loop length
    DO i = 1, 300

       READ(16, *, ERR=13, END=17) obs % two_dim(i, :) % value

       DO j=1, 200

          READ(17, FMT='(I2)', ADVANCE='NO', ERR=13, END=17) temp
          IF (temp == 1) THEN
             obs % two_dim(i, j) % is_data = .FALSE.
             obs % two_dim_missing(next, 1) = i
             obs % two_dim_missing(next, 2) = j
             next = next + 1
          END IF
       END DO

       !       READ(16, FMT='(A)', ERR=13) buffer
       ! HARD-CODED: the loop length
       !      DO j=1, 200
       !        space_index = INDEX(buffer, ' ')
       !       temp = TRIM(buffer(1:space_index))
       !      buffer = buffer(space_index + 1:LEN_TRIM(buffer))
       !     
       !    IF (temp == '*') THEN
       !      ! HARD-CODED: we have a variable called obs and it is two-dimensional
       !     obs % two_dim(i, j) % is_data = .FALSE.
       !    obs % two_dim(i, j) % initial_value_set = .FALSE.
       !   CYCLE
       !  END IF
       !  READ (temp, *, ERR=17) obs % two_dim(i, j) % value
       !  obs % two_dim(i, j) % is_data = .TRUE.        
       
       !       END DO
    END DO
    
    CLOSE(16)
    CLOSE(17)
    RETURN
13  WRITE(*, *) 'Could not read ', data_filename
    STOP
17  WRITE(*, *) 'Ran out of data in ', data_filename
    STOP
  END SUBROUTINE read_data

  SUBROUTINE set_initial_values(alpha, beta, x, obs)
    ! This subroutine reads the initial values of the parameters and sets them.
    IMPLICIT NONE

    TYPE(variables_real), INTENT(INOUT) :: alpha
    TYPE(variables_int), INTENT(INOUT) :: beta

    TYPE(variables_int), INTENT(INOUT) :: x
    TYPE(variables_int), INTENT(INOUT) :: obs

    CHARACTER(LEN=30) :: line, var_name
    ! HARD-CODED: the filename of the initial values file
    CHARACTER(LEN=*), PARAMETER :: initial_values_filename='initial_values.txt'
    INTEGER :: i, j, linenum
    INTEGER :: vertical_start, vertical_end, horizontal_start, horizontal_end
    INTEGER :: ind

    ! The format of the file is specified in the Design document 
    ! (section Simulation parameters input files)

    OPEN(UNIT=16, FILE=initial_values_filename)
    WRITE(*, *) 'Reading ', initial_values_filename

    READ (16, FMT='(A)', ERR=14, END=12) line
    linenum = 1

    IF (.NOT. line == '?? initial values') THEN
       WRITE(*, *) 'Expected initial values legend in ' , initial_values_filename
       WRITE(*, *) 'on line 1 not found. Quitting.'
       CLOSE(1)
       STOP
    END IF
    
    DO WHILE (.TRUE.)       
       READ (16, FMT='(A)', ERR=14, END=12) line
       linenum = linenum + 1

       line = TRIM(line)
   !    PRINT(*, *) line
       
       IF (LEN_TRIM(line) == 0) CYCLE
       IF (line(1:1) == '#') CYCLE
       
       ! now we have a "? alpha 1:something" at hand
       IF(line(1:1) /= '?')  THEN
          WRITE(*, *) 'Expected legend on line ', linenum, &
               ' not found, quitting.'
          STOP
       END IF
       line = line (3:LEN_TRIM(line))
       ind = INDEX(line, ' ')
       IF (ind <= 1) THEN 
          var_name = line
       ELSE
          var_name = TRIM(line(1:ind))
       END IF
!       WRITE(*, *) "variable name: ", var_name
       line = line(LEN_TRIM(var_name)+2:LEN_TRIM(line)) 
       ! trim the variable name out 
       ! and the trailing space
       
       vertical_start  = 0
       vertical_end    = 0
       horizontal_start = 0
       horizontal_end   = 0
       
       SELECT CASE (var_name)
          ! HARD-CODED: the name of the variable
       CASE ('alpha')
          !WRITE(*, *) 'Case alpha reached'
          ind = INDEX(line, ':')
          line(ind:ind) = ' '

          ! HARD-CODED: alpha is one-dimensional so we consider the format
          ! "alpha 4:6" for example

          !WRITE(*, *) line
          READ (line, FMT=*, ERR=14, END=12) vertical_start, vertical_end
          !WRITE(*, *) 'Vertical indices are: ', vertical_start, vertical_end
          DO i = vertical_start, vertical_end
             READ(16, *, ERR=14, END=12) alpha % one_dim (i) % value
             alpha % one_dim(i) % initial_value_set = .TRUE.
          END DO
          ! end of case alpha
          
          ! HARD-CODED: same things as in case alpha
       CASE ('beta') 
          ind = INDEX(line, ':')
          line(ind:ind) = ' '
          !WRITE(*, *) line
          READ (line, FMT=*, ERR=14, END=12) vertical_start, vertical_end
          !WRITE(*, *) 'Vertical indices are: ', vertical_start, vertical_end
          DO i = vertical_start, vertical_end
             READ(16, *, ERR=14, END=12) beta % one_dim (i) % value
             beta % one_dim(i) % initial_value_set = .TRUE.
          END DO
          ! end of case beta

          ! HARD-CODED: the name of the variable
       CASE ('x')

          ! HARD-CODED: x is two-dimensional so we consider the 
          ! format "x 1:20 5:400" for example
          DO i = 1, 2
             ind = INDEX(line, ':')
             line(ind:ind) = ' '
          END DO

          READ (line, FMT=*, ERR=14, END=12) vertical_start, vertical_end, horizontal_start, horizontal_end 
          DO i = vertical_start, vertical_end
             READ(16, *, ERR=14, END=12) x % two_dim (i, horizontal_start:horizontal_end) % value
             x % two_dim(i, horizontal_start:horizontal_end) % initial_value_set = .TRUE.
             
          END DO
          ! end of case x

          ! HARD-CODED: same things as in case x
       CASE ('obs')
          DO i = 1, 2
             ind = INDEX(line, ':')
             line(ind:ind) = ' '
          END DO
          
          READ (line, FMT=*, ERR=14, END=12) vertical_start, vertical_end, horizontal_start, horizontal_end 
          DO i = vertical_start, vertical_end
             READ(16, *, ERR=14, END=12) obs % two_dim (i, horizontal_start:horizontal_end) % value
             obs % two_dim(i, horizontal_start:horizontal_end) % initial_value_set = .TRUE.             
          END DO
          ! end of case obs

       CASE DEFAULT
       END SELECT

    END DO ! Ends the file-reading loop.
12  CLOSE(16)

    ! test printout
    !    DO i = vertical_start, vertical_end
    !       DO j = horizontal_start, horizontal_end
    !          WRITE (*, *) x % two_dim (i, j) % value
    !       END DO
    !    END DO

    RETURN
14  WRITE(*, *) 'Error on line ', linenum
    CLOSE(16)
    STOP
  END SUBROUTINE set_initial_values


  SUBROUTINE check_initial_values(alpha, beta, x, obs)
    IMPLICIT NONE

    TYPE(variables_real), INTENT(IN) :: alpha
    TYPE(variables_int), INTENT(IN) :: beta
    
    TYPE(variables_int), INTENT(IN) :: x
    TYPE(variables_int), INTENT(IN) :: obs    

    ! We must now ensure that all the variables not in data
    ! have an initial value.
    ! That is, for every array that holds data or variables
    ! the following condition must hold:
    ! array(:[,:]) % initial_value_set .OR. array(:[,:]) % is_data
   
    ! in this hardcoded case, every array = {alpha, beta, x, obs}.
    

    ! HARD-CODED: we have a variable group called alpha and it's one-dimensional
    IF(ANY((.NOT. alpha % one_dim(:) % initial_value_set .AND. .NOT. alpha % one_dim(:) % is_data))) THEN 
       WRITE(*, *) 'Insufficient initial values for group alpha'
       WRITE(*, *) 'Simulation cannot start.'
       STOP
    END IF

    ! HARD-CODED: we have a variable group called beta and it's one-dimensional
    IF(ANY((.NOT. beta % one_dim(:) % initial_value_set .AND. .NOT. beta % one_dim(:) % is_data))) THEN 
       WRITE(*, *) 'Insufficient initial values for variable group beta'
       WRITE(*, *) 'Simulation cannot start.'
       STOP
    END IF
    
    ! HARD-CODED: we have a variable group called x and it's two-dimensional
    IF(ANY((.NOT. x % two_dim(:, :) % initial_value_set .AND. .NOT. x % two_dim(:, :) % is_data))) THEN 
       WRITE(*, *) 'Insufficient initial values for variable group x'
       WRITE(*, *) 'Simulation cannot start.'
       STOP
    END IF

    ! HARD-CODED: we have a variable group called obs and it's two-dimensional
    IF(ANY((.NOT. obs % two_dim(:, :) % initial_value_set .AND. .NOT. obs % two_dim(:, :) % is_data))) THEN 
       WRITE(*, *) 'Insufficient initial values for variable group obs'
       WRITE(*, *) 'Simulation cannot start.'
       STOP
    END IF

  END SUBROUTINE check_initial_values

  SUBROUTINE set_spatial(spatial)
    IMPLICIT NONE
    
    ! HARD-CODED: the dimensions (see main)
    INTEGER, DIMENSION(300, 5), INTENT(OUT) :: spatial
    
    ! HARD-CODED: the name of the adjacency matrix file 

    ! this subroutine does nothing yet...


    

  END SUBROUTINE set_spatial
END MODULE input