!Linked list of particles
MODULE moduleList
  USE moduleSpecies
  IMPLICIT NONE

  TYPE lNode 
    TYPE(particle), POINTER:: part => NULL()
    TYPE(lNode), POINTER::    next => NULL()

  END TYPE lNode

  TYPE listNode
    INTEGER:: amount = 0
    TYPE(lNode),POINTER:: head => NULL()
    TYPE(lNode),POINTER:: tail => NULL()
    INTEGER(KIND=OMP_LOCK_KIND):: lock
    CONTAINS
      PROCEDURE,PASS:: add => addToList
      PROCEDURE,PASS:: convert2Array
      PROCEDURE,PASS:: erase => eraseList
      PROCEDURE,PASS:: setLock
      PROCEDURE,PASS:: unsetLock

  END TYPE listNode

  TYPE(listNode):: partInj !Particles comming from injections
  TYPE(listNode):: partWScheme !Particles comming from the nonAnalogue scheme
  TYPE(listNode):: partCollisions !Particles created in collisional process
  TYPE(listNode):: partSurfaces !Particles created in surface interactions
  TYPE(listNode):: partInitial !Initial distribution of particles

  TYPE pointerArray
    TYPE(particle), POINTER:: part

  END TYPE

  CONTAINS
    !Adds element to list
    SUBROUTINE addToList(self,part)
      USE moduleSpecies
      CLASS(listNode), INTENT(inout):: self
      TYPE(particle),INTENT(in), TARGET:: part
      TYPE(lNode),POINTER:: temp

      ALLOCATE(temp)
      temp%part => part
      temp%next => NULL()
      self%amount = self%amount + 1
      IF (.NOT. ASSOCIATED(self%head)) THEN
        !First element
        self%head => temp
        self%tail => temp
      ELSE
        !Append element
        self%tail%next => temp
        self%tail      => temp
      END IF

    END SUBROUTINE addToList

    !converts list to array
    FUNCTION convert2Array(self) RESULT(partArray)
      IMPLICIT NONE

      CLASS(listNode), INTENT(in):: self
      TYPE(pointerArray), ALLOCATABLE:: partArray(:)
      TYPE(lNode), POINTER:: tempNode
      INTEGER:: n

      ALLOCATE(partArray(1:self%amount))
      tempNode => self%head
      DO n=1, self%amount
        !Point element in array to element in list
        partArray(n)%part => tempNode%part

        !Go to next element
        tempNode => tempNode%next

      END DO

    END FUNCTION convert2Array

    !Erase list
    PURE SUBROUTINE eraseList(self)
      IMPLICIT NONE

      CLASS(listNode), INTENT(inout):: self
      TYPE(lNode),POINTER:: current, next
      
      current => self%head
      DO WHILE (ASSOCIATED(current))
        next => current%next
        DEALLOCATE(current)
        current => next
      END DO

      IF (ASSOCIATED(self%head)) NULLIFY(self%head)
      IF (ASSOCIATED(self%tail)) NULLIFY(self%tail)

      self%amount = 0

    END SUBROUTINE eraseList

    SUBROUTINE setLock(self)
      USE OMP_LIB
      IMPLICIT NONE

      CLASS(listNode):: self
      CALL OMP_SET_LOCK(self%lock)

    END SUBROUTINE setLock

    SUBROUTINE unsetLock(self)
      USE OMP_LIB
      IMPLICIT NONE

      CLASS(listNode):: self
      CALL OMP_UNSET_LOCK(self%lock)

    END SUBROUTINE unsetLock

END MODULE moduleList
