module CManifolds
    use CStack
    use CArrangement
    use SimulationVariables
    
    implicit none  
    
    public    
    integer, parameter :: ValveCount = 128
    integer, parameter :: MinSource = 71  
    integer, parameter :: MaxSource = 90  
    integer, parameter :: MinRelation = 91  
    integer, parameter :: MaxRelation = 128

    Type::ManifoldType
        type(Arrangement) :: Valve(ValveCount)
        type(Path), allocatable :: OpenPaths(:)
        type(Stack) :: Fringe
        logical :: IsRepititveOutput
        
        logical :: IsSafetyValveInstalled
        logical :: IsSafetyValveInstalled_KellyMode
        logical :: IsSafetyValveInstalled_TripMode
        logical :: IsSafetyValveInstalled_TopDrive
        logical :: SafetyValve
        logical :: IsIBopInstalled
        logical :: IBop
        logical :: IsKellyCockInstalled
        logical :: KellyCock
        logical :: IsTopDriveIBopInstalled
        logical :: TopDriveIBop
        logical :: IsFloatValveInstalled
        logical :: FloatValve
        logical :: IsPathsDirty = .false.
        logical :: IsTraverse = .false.
    End type ManifoldType
    type(ManifoldType)::Manifold
    contains    
    
    subroutine PathFinding_Setup()
        ! use CSimulationVariables
        implicit none
		Manifold%IsTraverse = .false.
        call Setup()
        !call OnSimulationInitialization%Add(PathFinding_Init)
        !call OnSimulationStop%Add(PathFinding_Init)
        !!**call OnpPathFindingStep%Add(PathFinding_Step)
        !!**call OnpPathFindingOutput%Add(PathFinding_Output)
        ! !**call OnpPathFindingMain%Add(PathFindingMainBody)
    end subroutine
    
    subroutine PathFinding_Init
        implicit none
		Manifold%IsTraverse = .false.
        call Setup()
    end subroutine PathFinding_Init
    
    subroutine PathFinding_Step
        if (Manifold%IsPathsDirty) then
            Manifold%IsPathsDirty = .false.
            call Traverse()
        endif
end subroutine PathFinding_Step
    
    ! subroutine PathFinding_Output
    !     implicit none
    ! end subroutine PathFinding_Output
    
    ! subroutine PathFindingMainBody
    !     ! use CSimulationVariables
    !     implicit none
    !     loop : do
    !         if(IsStopped) call Quit() 
    !         call sleepqq(50) 
    !         if (Manifold%IsPathsDirty) then
    !             Manifold%IsPathsDirty = .false.
    !             call Traverse()
    !         endif
    !     end do loop 
    ! end subroutine PathFindingMainBody
    
    subroutine Traverse()
        use CLog5
        implicit none
        integer :: i, Duration
        integer, dimension(8) :: StartTime,EndTime !TODO: clean up
        call DATE_AND_TIME(values=StartTime) !TODO: clean up
        
        !**call BeforeTraverse%RunAll()
        
        
        if(allocated(Manifold%OpenPaths)) deallocate(Manifold%OpenPaths)
        do i=MinSource, MaxSource 
            if(IsValveOpen(i)) then
                call AddRootNode(i)
                call AddChildren(Manifold%Valve(i))
            endif
        enddo
        
        call PostProcess(Manifold%OpenPaths)
        
        !**call AfterTraverse%RunAll()
		
        Manifold%IsTraverse = .true.
		
        !TODO: clean up
#ifdef Log5
        CALL DATE_AND_TIME(values=EndTime)
        Duration= EndTime(8) - StartTime(8)
        !if(print_log) print*, 'Duration= ', Duration, 'ms'
        call Log_5('Duration= ', Duration)
        call DisplayOpenPaths()
        
        call Log_5('==========================================')
#endif
        
    endsubroutine
    
    subroutine PostProcess(pathArr)
        implicit none
        type(Path), allocatable, intent(inout) :: pathArr(:)
        integer :: i
        
        if(.not.allocated(pathArr)) return
        
        i = 1
        do
            call pathArr(i)%Purge(MinRelation, MaxRelation)
            
            if(pathArr(i)%Length() <= 2) then
                call RemovePath(pathArr, i)
            else
                i = i + 1
            endif
            
            if(i > size(pathArr)) exit      
        enddo
        
    end subroutine
        
    subroutine AddRootNode(valve)
        implicit none
        integer, intent(in) :: valve
        call Manifold%Fringe%Push(valve)
    end subroutine
    
    recursive subroutine AddChildren(node)
        implicit none
        type(Arrangement), intent(inout) :: node
        integer :: i,t 
        
        do i=1, Manifold%Valve(node%Number)%Length()
            t = Manifold%Valve(node%Number)%Adjacent(i)
            
            if(IsValveOpen(t)) then
                
                if(Manifold%Fringe%DoesHave(t)) cycle
                
                call Manifold%Fringe%Push(t)
                
                if(Manifold%Valve(t)%IsSource()) then
                    call AddPath(Manifold%OpenPaths, Manifold%Fringe%List)
                    call Manifold%Fringe%Pop()
                    cycle
                endif
                
                call AddChildren(Manifold%Valve(node%Adjacent(i)))
                
            end if
        enddo
        call Manifold%Fringe%Pop()
    end subroutine
    
    logical function IsValveOpen(no)
        implicit none
        integer, intent(in) :: no
        
        IsValveOpen = Manifold%Valve(no)%Status
        
    end function
    
    subroutine AddPath(pathArr, p)
        implicit none
        type(Path), intent(in) :: p
        type(Path), allocatable, intent(inout) :: pathArr(:)
        type(Path), allocatable :: tempArr(:)
        integer :: i, isize
        
        if(p%IsNull()) return
        if(p%Length()<=1) return
        
        !**call OnpPathOpen%RunAll(p%Valves)
        
        if(allocated(pathArr)) then
            isize = size(pathArr)
            
            
            ! check to see if already have a path same as p
            do i=1,isize          
                if(pathArr(i)%First()==p%First() .and. pathArr(i)%Last()==p%Last()) then
                    ! if there is then
                    ! check to see if both have exacly a same length
                    if(pathArr(i)%Length()==p%Length())then
                        ! now they are the same so ignore adding this one
                        return
                    else
                        !if they have different lengths then choose the shorter one
                        if(pathArr(i)%Length()>p%Length())pathArr(i) = p
                        return
                    endif
                    
                endif
            end do
            
            
            
            !TODO: if p last valve is input source then ignore adding it
            !TODO: if p start valve is output source then ignore adding it
            
            
            
            ! if p is a new entry then add it to the collections of found paths
            allocate(tempArr(isize+1))
            do i=1,isize          
                tempArr(i) = pathArr(i)
            end do
            tempArr(isize+1) = p
            deallocate(pathArr)
            call move_alloc(tempArr, pathArr)
        else
            allocate(pathArr(1))
            pathArr(1) = p
        end if
        
    endsubroutine
    
    subroutine RemovePath(pathArr, index)
        implicit none
        integer, intent(in) :: index
        type(Path), allocatable, intent(inout) :: pathArr(:)
        type(Path), allocatable :: tempArr(:)
        integer :: i
        logical :: found
        
        if(index <= 0 .or. index > size(pathArr)) return
        if(.not.allocated(pathArr))return
        allocate(tempArr(size(pathArr)-1))
        found = .false.
        do i=1, size(pathArr)
            if(i==index) then
                found = .true.
                cycle
            end if
            if(found) then
                tempArr(i-1) = pathArr(i)
                !!**call OnpPathClose%RunAll(pathArr(i)%Valves)
            else 
                tempArr(i) = pathArr(i)
            endif
        end do
        deallocate(pathArr)
        call move_alloc(tempArr, pathArr)
        
    endsubroutine
    
    subroutine Setup()
        implicit none
        integer :: i
        
        ! initialize all valves
        do i = 1, ValveCount
            call Manifold%Valve(i)%init(i)
        end do
        
        ! open source valves
        do i = MinSource , MaxSource
            Manifold%Valve(i)%Status = .true.
            Manifold%Valve(i)%ValveType = InputOutput
        end do
        
        do i = MinRelation , MaxRelation
            Manifold%Valve(i)%Status = .true.
            Manifold%Valve(i)%ValveType = Relation
        end do
        
        
        
        ! make adjustments
        call Manifold%Valve(1)%AdjacentTo(91)
        
        call Manifold%Valve(2)%AdjacentTo(92)
        call Manifold%Valve(2)%AdjacentTo(117)
        
        call Manifold%Valve(3)%AdjacentTo(93)
        call Manifold%Valve(3)%AdjacentTo(118)
        
        call Manifold%Valve(4)%AdjacentTo(94)
        
        call Manifold%Valve(5)%AdjacentTo(95)
        
        call Manifold%Valve(6)%AdjacentTo(91)
        call Manifold%Valve(6)%AdjacentTo(92)
        
        call Manifold%Valve(7)%AdjacentTo(92)
        call Manifold%Valve(7)%AdjacentTo(93)
        
        call Manifold%Valve(8)%AdjacentTo(93)
        call Manifold%Valve(8)%AdjacentTo(94)
        
        call Manifold%Valve(9)%AdjacentTo(91)
        call Manifold%Valve(9)%AdjacentTo(96)
        
        call Manifold%Valve(10)%AdjacentTo(94)
        call Manifold%Valve(10)%AdjacentTo(98)
        
        call Manifold%Valve(11)%AdjacentTo(96)
        call Manifold%Valve(11)%AdjacentTo(97)
        
        call Manifold%Valve(12)%AdjacentTo(97)
        call Manifold%Valve(12)%AdjacentTo(98)
        
        call Manifold%Valve(13)%AdjacentTo(96)
        call Manifold%Valve(13)%AdjacentTo(99) 
        
        call Manifold%Valve(14)%AdjacentTo(78)
        call Manifold%Valve(14)%AdjacentTo(97)
        !call Valve(14)%AdjacentTo(126)
        
        call Manifold%Valve(15)%AdjacentTo(98)
        call Manifold%Valve(15)%AdjacentTo(99)
        
        call Manifold%Valve(16)%AdjacentTo(121)
        !call Valve(16)%AdjacentTo()
        
        call Manifold%Valve(17)%AdjacentTo(122)
        !call Valve(17)%AdjacentTo()
        
        call Manifold%Valve(18)%AdjacentTo(123)
        !call Valve(18)%AdjacentTo()
        
        call Manifold%Valve(19)%AdjacentTo(101)
        call Manifold%Valve(19)%AdjacentTo(102)
        
        call Manifold%Valve(20)%AdjacentTo(100)
        
        call Manifold%Valve(21)%AdjacentTo(101)
        
        call Manifold%Valve(22)%AdjacentTo(102)
        
        call Manifold%Valve(23)%AdjacentTo(71)
        
        call Manifold%Valve(24)%AdjacentTo(71)
        
        call Manifold%Valve(25)%AdjacentTo(108)
        call Manifold%Valve(25)%AdjacentTo(118)
        
        call Manifold%Valve(26)%AdjacentTo(109)
        call Manifold%Valve(26)%AdjacentTo(117)
        
        call Manifold%Valve(27)%AdjacentTo(32)
        call Manifold%Valve(27)%AdjacentTo(108)
        
        call Manifold%Valve(28)%AdjacentTo(33)
        call Manifold%Valve(28)%AdjacentTo(108)
        
        call Manifold%Valve(29)%AdjacentTo(110)
        call Manifold%Valve(29)%AdjacentTo(113)
        
        call Manifold%Valve(30)%AdjacentTo(34)
        call Manifold%Valve(30)%AdjacentTo(109)
        
        call Manifold%Valve(31)%AdjacentTo(35)
        call Manifold%Valve(31)%AdjacentTo(109)
        
        call Manifold%Valve(32)%AdjacentTo(27)
        call Manifold%Valve(32)%AdjacentTo(61)
        
        call Manifold%Valve(33)%AdjacentTo(28)
        call Manifold%Valve(33)%AdjacentTo(62)
        
        call Manifold%Valve(34)%AdjacentTo(30)
        call Manifold%Valve(34)%AdjacentTo(63)
        
        call Manifold%Valve(35)%AdjacentTo(31)
        call Manifold%Valve(35)%AdjacentTo(64)
        
        call Manifold%Valve(36)%AdjacentTo(116)
        
        call Manifold%Valve(37)%AdjacentTo(78)
        
        call Manifold%Valve(38)%AdjacentTo(71)
        
        call Manifold%Valve(39)%AdjacentTo(77)
        
        !call Valve(40)%AdjacentTo(105)
        call Manifold%Valve(40)%AdjacentTo(80)
        
        call Manifold%Valve(41)%AdjacentTo(77)
        
        call Manifold%Valve(42)%AdjacentTo(71)
        
        call Manifold%Valve(43)%AdjacentTo(106)
        
        call Manifold%Valve(44)%AdjacentTo(77)
        
        call Manifold%Valve(45)%AdjacentTo(71)
        
        call Manifold%Valve(46)%AdjacentTo(104)
        
        call Manifold%Valve(47)%AdjacentTo(104)
        call Manifold%Valve(47)%AdjacentTo(117)
        
        call Manifold%Valve(48)%AdjacentTo(69)
        call Manifold%Valve(48)%AdjacentTo(79)
        
        call Manifold%Valve(49)%AdjacentTo(104)
        call Manifold%Valve(49)%AdjacentTo(79)
        
        !call Valve(50)%AdjacentTo(48)
        call Manifold%Valve(50)%AdjacentTo(51)
        !call Valve(50)%AdjacentTo(54)
        call Manifold%Valve(50)%AdjacentTo(104)
        
        call Manifold%Valve(51)%AdjacentTo(50)
        call Manifold%Valve(51)%AdjacentTo(52)
        
        call Manifold%Valve(52)%AdjacentTo(51)
        !call Valve(52)%AdjacentTo(127)
        call Manifold%Valve(52)%AdjacentTo(80)
        
        !call Valve(53)%AdjacentTo(103)
        !call Valve(53)%AdjacentTo(105)
        call Manifold%Valve(53)%AdjacentTo(80)
        
        !call Valve(54)%AdjacentTo(69)
        !call Valve(54)%AdjacentTo(124)
        
        !call Valve(55)%AdjacentTo(103)
        !call Valve(55)%AdjacentTo(124)
        
        call Manifold%Valve(56)%AdjacentTo(128)
        call Manifold%Valve(56)%AdjacentTo(127)
        
        !call Valve(57)%AdjacentTo(14)
        !call Valve(57)%AdjacentTo(103)
        !call Valve(57)%AdjacentTo(126)
        
        call Manifold%Valve(58)%AdjacentTo(78)
        
        call Manifold%Valve(59)%AdjacentTo(78)
        
        call Manifold%Valve(60)%AdjacentTo(78)
        
        call Manifold%Valve(61)%AdjacentTo(32)
        call Manifold%Valve(61)%AdjacentTo(115)
        
        call Manifold%Valve(62)%AdjacentTo(33)
        call Manifold%Valve(62)%AdjacentTo(114)
        
        call Manifold%Valve(63)%AdjacentTo(112)
        call Manifold%Valve(63)%AdjacentTo(34)
        
        call Manifold%Valve(64)%AdjacentTo(35)
        call Manifold%Valve(64)%AdjacentTo(111)
        
        call Manifold%Valve(65)%AdjacentTo(120)
        
        call Manifold%Valve(66)%AdjacentTo(120)
        
        call Manifold%Valve(67)%AdjacentTo(73)
        
        call Manifold%Valve(68)%AdjacentTo(125)
        call Manifold%Valve(68)%AdjacentTo(126)
        
        call Manifold%Valve(69)%AdjacentTo(48)
        call Manifold%Valve(69)%AdjacentTo(124)
        
        !call Valve(70)%AdjacentTo()
        !call Valve(70)%AdjacentTo()
        
        call Manifold%Valve(71)%AdjacentTo(20)
        call Manifold%Valve(71)%AdjacentTo(44)
        call Manifold%Valve(71)%AdjacentTo(59)
        
        call Manifold%Valve(72)%AdjacentTo(21)
        call Manifold%Valve(72)%AdjacentTo(23)
        
        call Manifold%Valve(73)%AdjacentTo(22)
        
        call Manifold%Valve(74)%AdjacentTo(24)
        
        !call Valve(75)%AdjacentTo()
        
        !call Valve(76)%AdjacentTo()
        
        call Manifold%Valve(77)%AdjacentTo(43)
        call Manifold%Valve(77)%AdjacentTo(58)
        
        !call Valve(78)%AdjacentTo()
        
        call Manifold%Valve(79)%AdjacentTo(48)
        call Manifold%Valve(79)%AdjacentTo(49)
        
        call Manifold%Valve(80)%AdjacentTo(52)
        call Manifold%Valve(80)%AdjacentTo(107)
        
        call Manifold%Valve(81)%AdjacentTo(53)
        
        call Manifold%Valve(82)%AdjacentTo(16)
        
        call Manifold%Valve(83)%AdjacentTo(17)
        
        call Manifold%Valve(84)%AdjacentTo(18)
        
        !call Valve(85)%AdjacentTo()
        
        !call Valve(86)%AdjacentTo()
        
        !call Valve(87)%AdjacentTo()
        
        !call Valve(88)%AdjacentTo()
        
        !!call Valve(89)%AdjacentTo()
        
        !call Valve(90)%AdjacentTo()
        
        call Manifold%Valve(91)%AdjacentTo(6)
        call Manifold%Valve(91)%AdjacentTo(9)
        call Manifold%Valve(91)%AdjacentTo(75)
        
        call Manifold%Valve(92)%AdjacentTo(6)
        call Manifold%Valve(92)%AdjacentTo(7)
        call Manifold%Valve(92)%AdjacentTo(2)
        
        call Manifold%Valve(93)%AdjacentTo(3)
        call Manifold%Valve(93)%AdjacentTo(7)
        call Manifold%Valve(93)%AdjacentTo(8)
        
        call Manifold%Valve(94)%AdjacentTo(8)
        call Manifold%Valve(94)%AdjacentTo(10)
        call Manifold%Valve(94)%AdjacentTo(95)  
        
        call Manifold%Valve(95)%AdjacentTo(76)
        call Manifold%Valve(95)%AdjacentTo(94)
        
        call Manifold%Valve(96)%AdjacentTo(9)
        call Manifold%Valve(96)%AdjacentTo(11)
        call Manifold%Valve(96)%AdjacentTo(13)
        
        call Manifold%Valve(97)%AdjacentTo(11)
        call Manifold%Valve(97)%AdjacentTo(12)
        call Manifold%Valve(97)%AdjacentTo(14)
        
        call Manifold%Valve(98)%AdjacentTo(10)
        call Manifold%Valve(98)%AdjacentTo(12)
        call Manifold%Valve(98)%AdjacentTo(15)
        
        call Manifold%Valve(99)%AdjacentTo(13)
        call Manifold%Valve(99)%AdjacentTo(15)
        call Manifold%Valve(99)%AdjacentTo(125)
        
        !call Valve(100)%AdjacentTo(16)
        call Manifold%Valve(100)%AdjacentTo(82)
        call Manifold%Valve(100)%AdjacentTo(101)
        
        !call Valve(101)%AdjacentTo(17)
        call Manifold%Valve(101)%AdjacentTo(19)
        call Manifold%Valve(101)%AdjacentTo(83)
        call Manifold%Valve(101)%AdjacentTo(100)
        
        !call Valve(102)%AdjacentTo(18)
        call Manifold%Valve(102)%AdjacentTo(19)
        call Manifold%Valve(102)%AdjacentTo(84)
        
        !call Valve(103)%AdjacentTo(53)
        !call Valve(103)%AdjacentTo(56)
        call Manifold%Valve(103)%AdjacentTo(124)
        !call Valve(103)%AdjacentTo(56)
        !call Valve(103)%AdjacentTo(78)
        
        call Manifold%Valve(104)%AdjacentTo(46)
        call Manifold%Valve(104)%AdjacentTo(47)
        call Manifold%Valve(104)%AdjacentTo(49)
        call Manifold%Valve(104)%AdjacentTo(50)
        
        !call Valve(105)%AdjacentTo(53)
        !call Valve(105)%AdjacentTo(107)
        !call Valve(105)%AdjacentTo(127)
        
        call Manifold%Valve(106)%AdjacentTo(40)
        call Manifold%Valve(106)%AdjacentTo(45)
        
        
        call Manifold%Valve(107)%AdjacentTo(41)
        !call Valve(107)%AdjacentTo(105)
        call Manifold%Valve(107)%AdjacentTo(119)
        !call Valve(107)%AdjacentTo(42)
        
        call Manifold%Valve(108)%AdjacentTo(25)
        call Manifold%Valve(108)%AdjacentTo(27)
        call Manifold%Valve(108)%AdjacentTo(28)
        call Manifold%Valve(108)%AdjacentTo(110)
        
        call Manifold%Valve(109)%AdjacentTo(26)
        call Manifold%Valve(109)%AdjacentTo(30)
        call Manifold%Valve(109)%AdjacentTo(31)
        call Manifold%Valve(109)%AdjacentTo(110)
        
        call Manifold%Valve(110)%AdjacentTo(29)
        call Manifold%Valve(110)%AdjacentTo(85)
        call Manifold%Valve(110)%AdjacentTo(108)
        call Manifold%Valve(110)%AdjacentTo(109)
        
        call Manifold%Valve(111)%AdjacentTo(37)
        call Manifold%Valve(111)%AdjacentTo(64)
        call Manifold%Valve(111)%AdjacentTo(112)
        
        call Manifold%Valve(112)%AdjacentTo(63)
        call Manifold%Valve(112)%AdjacentTo(111)
        call Manifold%Valve(112)%AdjacentTo(113)
        
        call Manifold%Valve(113)%AdjacentTo(29)
        call Manifold%Valve(113)%AdjacentTo(112)
        call Manifold%Valve(113)%AdjacentTo(114)
        
        call Manifold%Valve(114)%AdjacentTo(62)
        call Manifold%Valve(114)%AdjacentTo(113)
        call Manifold%Valve(114)%AdjacentTo(115)
        
        call Manifold%Valve(115)%AdjacentTo(36)
        call Manifold%Valve(115)%AdjacentTo(61)
        call Manifold%Valve(115)%AdjacentTo(114)
        
        call Manifold%Valve(116)%AdjacentTo(38)
        call Manifold%Valve(116)%AdjacentTo(39)
        
        call Manifold%Valve(117)%AdjacentTo(2)
        call Manifold%Valve(117)%AdjacentTo(26)
        call Manifold%Valve(117)%AdjacentTo(47)
        
        call Manifold%Valve(118)%AdjacentTo(3)
        call Manifold%Valve(118)%AdjacentTo(25)
        call Manifold%Valve(118)%AdjacentTo(46)
        
        call Manifold%Valve(119)%AdjacentTo(42)
        call Manifold%Valve(119)%AdjacentTo(60)
        call Manifold%Valve(119)%AdjacentTo(107)
        
        call Manifold%Valve(120)%AdjacentTo(71)
        
        !call Valve(121)%AdjacentTo(16)
        call Manifold%Valve(121)%AdjacentTo(1)
        call Manifold%Valve(121)%AdjacentTo(65)
        
        !call Valve(122)%AdjacentTo(17)
        call Manifold%Valve(122)%AdjacentTo(4)
        call Manifold%Valve(122)%AdjacentTo(66)
        
        !call Valve(123)%AdjacentTo(18)
        call Manifold%Valve(123)%AdjacentTo(5)
        call Manifold%Valve(123)%AdjacentTo(67)
        
        !call Valve(124)%AdjacentTo(54)
        !call Valve(124)%AdjacentTo(55)
        call Manifold%Valve(124)%AdjacentTo(69)
        call Manifold%Valve(124)%AdjacentTo(103)
        
        call Manifold%Valve(125)%AdjacentTo(68)
        call Manifold%Valve(125)%AdjacentTo(99)
       ! call Valve(125)%AdjacentTo(126)
        
        call Manifold%Valve(126)%AdjacentTo(128)
        call Manifold%Valve(126)%AdjacentTo(68)        
        !call Valve(126)%AdjacentTo(125) 
        
        call Manifold%Valve(127)%AdjacentTo(56)
        call Manifold%Valve(127)%AdjacentTo(78)
        !call Valve(127)%AdjacentTo(105) 
        
        call Manifold%Valve(128)%AdjacentTo(56)
        call Manifold%Valve(128)%AdjacentTo(126)
        
        
        ! initialization
        call ChangeValve(60, .true.)
        call RemoveIBop()
        call ToggleFillupHead(.false.)
        call ToggleMudBox(.false.)
        call RemoveTopDriveIBop()
        call InstallSafetyValve_KellyMode()
        call KellyDisconnected()
    end subroutine
    
    
    
    subroutine KellyConnected()
    !use CLog3
        implicit none
        
        call Manifold%Valve(127)%RemoveAdjacent(78)
        
        call Manifold%Valve(127)%AdjacentTo(103)
        call Manifold%Valve(103)%AdjacentTo(127)
        
#ifdef deb
        if(print_log) print*, 'KellyConnected()'
        !call Log_3( 'KellyConnected()')
#endif
        Manifold%IsPathsDirty = .true.
    end subroutine
    
    subroutine KellyDisconnected()
    !use CLog3
        implicit none
        
        call Manifold%Valve(127)%RemoveAdjacent(103)
        call Manifold%Valve(103)%RemoveAdjacent(127)
        
        call Manifold%Valve(127)%AdjacentTo(78)
        
#ifdef deb
        if(print_log) print*, 'KellyDisconnected()'
        !call Log_3( 'KellyDisconnected()')
#endif

        Manifold%IsPathsDirty = .true.
        
    end subroutine
    
    
    
    
    
    
    
    
    
    subroutine InstallSafetyValve_KellyMode()
        implicit none
        Manifold%IsSafetyValveInstalled_KellyMode = .true.
        
        call RemoveTopDriveIBop()
        
        ! Remove Safey Valve (54)
        call Manifold%Valve(124)%RemoveAdjacent(54)
        call Manifold%Valve(54)%RemoveAdjacent(124)
        
        call Manifold%Valve(69)%RemoveAdjacent(54)
        call Manifold%Valve(54)%RemoveAdjacent(69)
        
        ! Remove 126-103 cnn
        call Manifold%Valve(128)%RemoveAdjacent(127)
        call Manifold%Valve(127)%RemoveAdjacent(128)
                
        ! now make cnn
        call Manifold%Valve(124)%AdjacentTo(69)
        call Manifold%Valve(69)%AdjacentTo(124)
        
        call Manifold%Valve(128)%AdjacentTo(56)
        
        call Manifold%Valve(56)%AdjacentTo(128)
        call Manifold%Valve(56)%AdjacentTo(127)
        
        call Manifold%Valve(127)%AdjacentTo(56)
        
#ifdef deb
            if(print_log) print*, 'InstallSafetyValve_KellyMode()'
#endif
        
        data%Equipments%DrillingConsole%IRSafetyValveLed = 1
        call OpenSafetyValve_KellyMode()
    end subroutine
    
    subroutine RemoveSafetyValve_KellyMode()
        implicit none
        Manifold%IsSafetyValveInstalled_KellyMode = .false.
        
        call Manifold%Valve(128)%RemoveAdjacent(56)
        call Manifold%Valve(56)%RemoveAdjacent(128)
        
        call Manifold%Valve(127)%RemoveAdjacent(56)
        call Manifold%Valve(56)%RemoveAdjacent(127)
        
        call Manifold%Valve(127)%AdjacentTo(128)
        call Manifold%Valve(128)%AdjacentTo(127)
        
        data%Equipments%DrillingConsole%IRSafetyValveLed = 0
        call CloseSafetyValve_KellyMode()
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 0
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 0
        
#ifdef deb
            if(print_log) print*, 'RemoveSafetyValve_KellyMode()'
#endif
        
    end subroutine
    
    subroutine OpenSafetyValve_KellyMode()
        implicit none
        if(.not.Manifold%IsSafetyValveInstalled_KellyMode) return
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 1
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 0
        Manifold%SafetyValve = .true.
        call ChangeValve(56, Manifold%SafetyValve)
        
#ifdef deb
            if(print_log) print*, 'OpenSafetyValve_KellyMode()'
#endif
        
    end subroutine
    
    subroutine CloseSafetyValve_KellyMode()
        implicit none
        if(.not.Manifold%IsSafetyValveInstalled_KellyMode) return
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 1
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 0
        Manifold%SafetyValve = .false.
        call ChangeValve(56, Manifold%SafetyValve)
        
#ifdef deb
            if(print_log) print*, 'CloseSafetyValve_KellyMode()'
#endif
        
    end subroutine
    
    
    
    
    
    
    
    
    
    
    subroutine InstallSafetyValve_TripMode()
        implicit none
        Manifold%IsSafetyValveInstalled_TripMode = .true.
        
        call Manifold%Valve(128)%RemoveAdjacent(56)
        call Manifold%Valve(56)%RemoveAdjacent(128)
        
        call Manifold%Valve(127)%RemoveAdjacent(56)
        call Manifold%Valve(56)%RemoveAdjacent(127)
        
        call Manifold%Valve(69)%RemoveAdjacent(124)
        call Manifold%Valve(124)%RemoveAdjacent(69)
        
        
        call Manifold%Valve(127)%AdjacentTo(128)
        call Manifold%Valve(128)%AdjacentTo(127)
        
        call Manifold%Valve(124)%AdjacentTo(54)
        call Manifold%Valve(54)%AdjacentTo(124)
        
        call Manifold%Valve(54)%AdjacentTo(69)
        call Manifold%Valve(69)%AdjacentTo(54)
                
        data%Equipments%DrillingConsole%IRSafetyValveLed = 1
        call OpenSafetyValve_TripMode()
        
#ifdef deb
            if(print_log) print*, 'InstallSafetyValve_TripMode()'
#endif
        
    end subroutine
    
    subroutine RemoveSafetyValve_TripMode()
        implicit none
        Manifold%IsSafetyValveInstalled_TripMode = .false.
        
        call Manifold%Valve(124)%RemoveAdjacent(54)
        call Manifold%Valve(54)%RemoveAdjacent(124)
        
        call Manifold%Valve(54)%RemoveAdjacent(69)
        call Manifold%Valve(69)%RemoveAdjacent(54)
        
        call Manifold%Valve(124)%AdjacentTo(69)
        call Manifold%Valve(69)%AdjacentTo(124)
        
        data%Equipments%DrillingConsole%IRSafetyValveLed = 0
        call CloseSafetyValve_TripMode()
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 0
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 0
        
#ifdef deb
            if(print_log) print*, 'RemoveSafetyValve_TripMode()'
#endif
        
    end subroutine
    
    subroutine OpenSafetyValve_TripMode()
        implicit none
        if(.not.Manifold%IsSafetyValveInstalled_TripMode) return
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 1
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 0
        Manifold%SafetyValve = .true.
        call ChangeValve(54, Manifold%SafetyValve)
        
#ifdef deb
            if(print_log) print*, 'OpenSafetyValve_TripMode()'
#endif
        
    end subroutine
    
    subroutine CloseSafetyValve_TripMode()
        implicit none
        if(.not.Manifold%IsSafetyValveInstalled_TripMode) return
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 1
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 0
        Manifold%SafetyValve = .false.
        call ChangeValve(54, Manifold%SafetyValve)
        
#ifdef deb
            if(print_log) print*, 'CloseSafetyValve_TripMode()'
#endif
        
    end subroutine
    
    
    
    
    
    
    
    
    subroutine InstallSafetyValve_TopDrive()
        implicit none
        Manifold%IsSafetyValveInstalled_TopDrive = .true.
        
        call Manifold%Valve(128)%RemoveAdjacent(56)
        call Manifold%Valve(56)%RemoveAdjacent(128)
        
        call Manifold%Valve(127)%RemoveAdjacent(56)
        call Manifold%Valve(56)%RemoveAdjacent(127)
        
        call Manifold%Valve(69)%RemoveAdjacent(124)
        call Manifold%Valve(124)%RemoveAdjacent(69)
        
        call Manifold%Valve(124)%AdjacentTo(54)
        call Manifold%Valve(54)%AdjacentTo(124)
        
        call Manifold%Valve(54)%AdjacentTo(69)
        call Manifold%Valve(69)%AdjacentTo(54)
        
        data%Equipments%DrillingConsole%IRSafetyValveLed = 1
        call OpenSafetyValve_TopDrive()
        
#ifdef deb
            if(print_log) print*, 'InstallSafetyValve_TopDrive()'
#endif
        
    end subroutine
    
    subroutine RemoveSafetyValve_TopDrive()
        implicit none
        Manifold%IsSafetyValveInstalled_TopDrive = .false.
        
        call Manifold%Valve(124)%RemoveAdjacent(54)
        call Manifold%Valve(54)%RemoveAdjacent(124)
        
        call Manifold%Valve(54)%RemoveAdjacent(69)
        call Manifold%Valve(69)%RemoveAdjacent(54)
        
        call Manifold%Valve(124)%AdjacentTo(69)
        call Manifold%Valve(69)%AdjacentTo(124)
        
        data%Equipments%DrillingConsole%IRSafetyValveLed = 0
        call CloseSafetyValve_TopDrive()
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 0
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 0
        
#ifdef deb
            if(print_log) print*, 'RemoveSafetyValve_TopDrive()'
#endif
        
    end subroutine
    
    subroutine OpenSafetyValve_TopDrive()
        implicit none
        if(.not.Manifold%IsSafetyValveInstalled_TopDrive) return
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 1
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 0
        Manifold%SafetyValve = .true.
        
#ifdef deb
            if(print_log) print*, 'OpenSafetyValve_TopDrive()'
#endif
        
        call ChangeValve(54, Manifold%SafetyValve)
    end subroutine
    
    subroutine CloseSafetyValve_TopDrive()
        implicit none
        if(.not.Manifold%IsSafetyValveInstalled_TopDrive) return
        data%Equipments%DrillingConsole%CloseSafetyValveLed = 1
        data%Equipments%DrillingConsole%OpenSafetyValveLed = 0
        Manifold%SafetyValve = .false.
        
#ifdef deb
            if(print_log) print*, 'CloseSafetyValve_TopDrive()'
#endif
        
        call ChangeValve(54, Manifold%SafetyValve)
    end subroutine
    
    
    
    
    
    
    
    
    
    subroutine InstallIBop()
        implicit none
        Manifold%IsIBopInstalled = .true.
        
        call Manifold%Valve(103)%RemoveAdjacent(124)
        call Manifold%Valve(124)%RemoveAdjacent(103)
        
        call Manifold%Valve(55)%AdjacentTo(103)
        call Manifold%Valve(55)%AdjacentTo(124)
        
        call Manifold%Valve(103)%AdjacentTo(55)
        call Manifold%Valve(124)%AdjacentTo(55)
        
#ifdef deb
            if(print_log) print*, 'InstallIBop()'
#endif
        
        data%Equipments%DrillingConsole%IRIBopLed = 1
        call OpenIBop()
    end subroutine
    
    subroutine RemoveIBop()
        implicit none
        Manifold%IsIBopInstalled = .false.
        
        call Manifold%Valve(55)%RemoveAdjacent(103)
        call Manifold%Valve(55)%RemoveAdjacent(124)
        
        call Manifold%Valve(103)%RemoveAdjacent(55)
        call Manifold%Valve(124)%RemoveAdjacent(55)
        
        call Manifold%Valve(103)%AdjacentTo(124)
        call Manifold%Valve(124)%AdjacentTo(103)
        
#ifdef deb
            if(print_log) print*, 'RemoveIBop()'
#endif
        
        data%Equipments%DrillingConsole%IRIBopLed = 0
        Manifold%IBop = .false.
        call ChangeValve(55, Manifold%IBop)
    end subroutine
    
    subroutine OpenIBop()
        implicit none
        if(.not.Manifold%IsIBopInstalled) return
        Manifold%IBop = .true.
        
#ifdef deb
            if(print_log) print*, 'OpenIBop()'
#endif
        
        call ChangeValve(55, Manifold%IBop)
    end subroutine
    
    subroutine CloseIBop()
        implicit none
        if(.not.Manifold%IsIBopInstalled) return
        Manifold%IBop = .false.
        
#ifdef deb
            if(print_log) print*, 'CloseIBop()'
#endif
        
        call ChangeValve(55, Manifold%IBop)
    end subroutine
    
    
    
    
    
    
    subroutine InstallKellyCock()
        implicit none
        Manifold%IsKellyCockInstalled = .true.
        
        call Manifold%Valve(125)%RemoveAdjacent(126)
        call Manifold%Valve(126)%RemoveAdjacent(125)
        
        call Manifold%Valve(125)%AdjacentTo(68)
        
        call Manifold%Valve(68)%AdjacentTo(125)
        call Manifold%Valve(68)%AdjacentTo(126)
        
        call Manifold%Valve(126)%AdjacentTo(68)
        
#ifdef deb
            if(print_log) print*, 'InstallKellyCock()'
#endif
        
        call OpenKellyCock()
    end subroutine
    
    subroutine RemoveKellyCock()
        implicit none
        Manifold%IsKellyCockInstalled = .false.
        
        call Manifold%Valve(125)%RemoveAdjacent(68)
        call Manifold%Valve(126)%RemoveAdjacent(68)
        
        call Manifold%Valve(68)%RemoveAdjacent(125)
        call Manifold%Valve(68)%RemoveAdjacent(126)
        
        call Manifold%Valve(125)%AdjacentTo(126)
        call Manifold%Valve(126)%AdjacentTo(125)
        
        Manifold%KellyCock = .false.
        call ChangeValve(68, Manifold%KellyCock)
        data%Equipments%DrillingConsole%CloseKellyCockLed = 0
        data%Equipments%DrillingConsole%OpenKellyCockLed = 0
        
#ifdef deb
            if(print_log) print*, 'RemoveKellyCock()'
#endif
        
    end subroutine
    
    subroutine OpenKellyCock()
        implicit none
        if(.not.Manifold%IsKellyCockInstalled) return
        data%Equipments%DrillingConsole%OpenKellyCockLed = 1
        data%Equipments%DrillingConsole%CloseKellyCockLed = 0
        Manifold%KellyCock = .true.
        
#ifdef deb
            if(print_log) print*, 'OpenKellyCock()'
#endif
        
        call ChangeValve(68, Manifold%KellyCock)
    end subroutine
    
    subroutine CloseKellyCock()
        implicit none
        if(.not.Manifold%IsKellyCockInstalled) return
        data%Equipments%DrillingConsole%CloseKellyCockLed = 1
        data%Equipments%DrillingConsole%OpenKellyCockLed = 0
        Manifold%KellyCock = .false.

#ifdef deb
            if(print_log) print*, 'CloseKellyCock()'
#endif
        
        call ChangeValve(68, Manifold%KellyCock)
    end subroutine
    
    
    
    
    
    
    
    
    subroutine InstallTopDriveIBop()
        implicit none
        Manifold%IsTopDriveIBopInstalled = .true.
        
        call Manifold%Valve(126)%RemoveAdjacent(128)
        call Manifold%Valve(128)%RemoveAdjacent(126)
        
        
        call Manifold%Valve(126)%AdjacentTo(70)
        call Manifold%Valve(70)%AdjacentTo(126)
        
        call Manifold%Valve(128)%AdjacentTo(70)
        call Manifold%Valve(70)%AdjacentTo(128)
        
#ifdef deb
            if(print_log) print*, 'InstallTopDriveIBop()'
#endif
        call OpenTopDriveIBop()
    end subroutine
    
    subroutine RemoveTopDriveIBop()
        implicit none
        Manifold%IsTopDriveIBopInstalled = .false.
        
        call Manifold%Valve(126)%RemoveAdjacent(70)
        call Manifold%Valve(70)%RemoveAdjacent(126)
        
        call Manifold%Valve(128)%RemoveAdjacent(70)
        call Manifold%Valve(70)%RemoveAdjacent(128)
        
        call Manifold%Valve(126)%AdjacentTo(128)
        call Manifold%Valve(128)%AdjacentTo(126)
        
#ifdef deb
            if(print_log) print*, 'RemoveTopDriveIBop()'
#endif
        Manifold%TopDriveIBop = .false.
        call ChangeValve(70, Manifold%TopDriveIBop)
    end subroutine
    
    subroutine OpenTopDriveIBop()
        implicit none
        if(.not.Manifold%IsTopDriveIBopInstalled) return
        Manifold%TopDriveIBop = .true.
        call ChangeValve(70, Manifold%TopDriveIBop)
#ifdef deb
            if(print_log) print*, 'OpenTopDriveIBop()'
#endif
    end subroutine
    
    subroutine CloseTopDriveIBop()
        implicit none
        if(.not.Manifold%IsTopDriveIBopInstalled) return
        Manifold%TopDriveIBop = .false.
        call ChangeValve(70, Manifold%TopDriveIBop)
#ifdef deb
            if(print_log) print*, 'CloseTopDriveIBop()'
#endif
    end subroutine
    
    
    
    
    
    
    
    
    
    subroutine InstallFloatValve()
        implicit none
        Manifold%IsFloatValveInstalled = .true.
        
        call Manifold%Valve(69)%RemoveAdjacent(79)
        call Manifold%Valve(79)%RemoveAdjacent(69)
        
        call Manifold%Valve(48)%AdjacentTo(69)
        call Manifold%Valve(48)%AdjacentTo(79)
        
        call Manifold%Valve(69)%AdjacentTo(48)
        call Manifold%Valve(79)%AdjacentTo(48)
#ifdef deb
            if(print_log) print*, 'InstallFloatValve()'
#endif
        call OpenFloatValve()
    end subroutine
    
    subroutine RemoveFloatValve()
        implicit none
        Manifold%IsFloatValveInstalled = .false.
        
        call Manifold%Valve(48)%RemoveAdjacent(69)
        call Manifold%Valve(48)%RemoveAdjacent(79)
        
        call Manifold%Valve(69)%RemoveAdjacent(48)
        call Manifold%Valve(79)%RemoveAdjacent(48)
        
        call Manifold%Valve(69)%AdjacentTo(79)
        call Manifold%Valve(79)%AdjacentTo(69)
#ifdef deb
            if(print_log) print*, 'RemoveFloatValve()'
#endif
        Manifold%FloatValve = .false.
        call ChangeValve(48, Manifold%FloatValve)
    end subroutine
    
    subroutine OpenFloatValve()
        implicit none
        if(.not.Manifold%IsFloatValveInstalled) return
        Manifold%FloatValve = .true.
#ifdef deb
            if(print_log) print*, 'OpenFloatValve()'
#endif
        call ChangeValve(48, Manifold%FloatValve)
    end subroutine
    
    subroutine CloseFloatValve()
        implicit none
        if(.not.Manifold%IsFloatValveInstalled) return
        Manifold%FloatValve = .false.
#ifdef deb
            if(print_log) print*, 'CloseFloatValve()'
#endif
        call ChangeValve(48, Manifold%FloatValve)
    end subroutine
    
    
    
    
    
    
    
    subroutine ToggleFillupHead(v)
        implicit none
        logical, intent(in) :: v
        if(v) then
            call Manifold%Valve(14)%RemoveAdjacent(78)
            
            call Manifold%Valve(14)%AdjacentTo(57)
            call Manifold%Valve(57)%AdjacentTo(14)
            call Manifold%Valve(57)%AdjacentTo(103)
            call Manifold%Valve(103)%AdjacentTo(57)
            
        else
            call Manifold%Valve(14)%RemoveAdjacent(57)
            call Manifold%Valve(57)%RemoveAdjacent(14)
            call Manifold%Valve(57)%RemoveAdjacent(103)
            call Manifold%Valve(103)%RemoveAdjacent(57)
            
            call Manifold%Valve(14)%AdjacentTo(78)
        endif
        Manifold%IsPathsDirty = .true.
        call ChangeValve(57, .true.)
    end subroutine
    
    subroutine ToggleMudBox(v)
        implicit none
        logical, intent(in) :: v
        call ChangeValve(53, v)
    end subroutine   
    
    
    
    
    
    
    
    
    
    subroutine ToggleMiddleRams(v)
        implicit none
        logical, intent(in) :: v
        Manifold%Valve(50)%Status = v
        call ChangeValve(69, v)
    end subroutine
    
    
    
    
    
    
    
    
    subroutine ChangeValve(i, state)
        implicit none
        integer, intent(in) :: i
        logical, intent(in) :: state
        
        if(Manifold%Valve(i)%Status==state) return
        Manifold%Valve(i)%Status = state
        if(i == 41 .or. i == 42) then
            if(Manifold%Valve(41)%Status == .false. .and. Manifold%Valve(42)%Status == .false.) then
                Manifold%Valve(60)%Status = .true.
            else
                Manifold%Valve(60)%Status = .false.
            endif
        endif
#ifdef deb
        if(print_log) print*, 'Valve(', i, ') = ', state
#endif
        !call Traverse()
        Manifold%IsPathsDirty = .true.
    end subroutine
    
    
    
    
        
    subroutine DisplayOpenPaths()
        implicit none
        integer :: i
        if(allocated(Manifold%OpenPaths)) then
            do i = 1, size(Manifold%OpenPaths)
                call Manifold%OpenPaths(i)%Display()
            end do
        end if
    end subroutine
    
    subroutine DisplayOpenPathsWrite()
        implicit none
        integer :: i
        if(allocated(Manifold%OpenPaths)) then
            do i = 1, size(Manifold%OpenPaths)
                call Manifold%OpenPaths(i)%DisplayWrite()
            end do
        end if
    end subroutine
    
end module CManifolds