main :: IO ()
main = run $ do
    mv pathToTmpExecutable pathToExecutable
    lookPIDOfCurrentProcess >>= \case
        Nothing  -> startNewServerOn defaultPort
        Just pid -> updateServer pid
  where
    lookPIDOfCurrentProcess :: Segment (Maybe PID)
    lookPIDOfCurrentProcess = strings (   pgrep "-l" executableName <|> return ()
                                       $| awk "{print $1}")
                              >>= \output -> return $ case output of
                                                          []      -> Nothing
                                                          (pid:_) -> Just pid

    updateServer :: PID -> Segment ()
    updateServer pidOfCurrentProcess = 
        strings (   sudo "netstat" "-antulp"  -- There's no operator to combine 'sudo' with command... :-(
                 $| grep executableName
                 $| awk "{split($4,a,\":\"); print a[2]}")
        >>= \output -> case output of
            [] -> do
                -- It's really strange: there's no port, but it must be here!
                startNewServerOn defaultPort
                switchNginxToNewServer (From alternativePort) (To defaultPort)
                stopOldServerBy pidOfCurrentProcess
            (currentPort:_) -> do
                if currentPort == defaultPort
                    then do
                        startNewServerOn alternativePort
                        switchNginxToNewServer (From defaultPort) (To alternativePort)
                    else do
                        startNewServerOn defaultPort
                        switchNginxToNewServer (From alternativePort) (To defaultPort)
                stopOldServerBy pidOfCurrentProcess
 
    startNewServerOn :: Port -> Segment ()
    startNewServerOn port = startStopDaemon "--start" "-b" "-q" "-x" pathToExecutable "--" "-p" port "-f" pathToCommonFood
        
    stopOldServerBy :: PID -> Segment ()
    stopOldServerBy pid = startStopDaemon "--stop" "-o" "-q" "--pid" pid

    switchNginxToNewServer :: FromPort -> ToPort -> Segment ()
    switchNginxToNewServer (From currentPort) (To newPort) = do
        sudo "sed" "-i" replaceProxyPass pathToNginxConfig
        sudo "nginx" "-s" "reload"
      where
        replaceProxyPass = mconcat ["s#", proxyPass <> currentPort, "#", proxyPass <> newPort, "#g"]
        proxyPass        = "proxy_pass http://127.0.0.1:"

    -- Main constants.
    executableName      = "breadu-exe"                       
    rootDirectory       = "/home/dshevchenko/breadu-root"
    pathToCommonFood    = rootDirectory </> "food/common"
    pathToExecutable    = rootDirectory </> executableName
    pathToTmpExecutable = "/tmp" </> executableName
    pathToNginxConfig   = "/etc/nginx/sites-enabled/default"
    defaultPort         = "3000"
    alternativePort     = "3010"
main :: IO ()
main = run $ do
    mv pathToTmpExecutable pathToExecutable
    lookPIDOfCurrentProcess >>= \case
        Nothing  -> startNewServerOn defaultPort
        Just pid -> updateServer pid
  where
    lookPIDOfCurrentProcess :: Segment (Maybe PID)
    lookPIDOfCurrentProcess = strings (   pgrep "-l" executableName <|> return ()
                                       $| awk "{print $1}")
                              >>= \output -> return $ case output of
                                                          []      -> Nothing
                                                          (pid:_) -> Just pid

    updateServer :: PID -> Segment ()
    updateServer pidOfCurrentProcess = 
        strings (   sudo "netstat" "-antulp"  -- There's no operator to combine 'sudo' with command... :-(
                 $| grep executableName
                 $| awk "{split($4,a,\":\"); print a[2]}")
        >>= \output -> case output of
            [] -> do
                -- It's really strange: there's no port, but it must be here!
                startNewServerOn defaultPort
                switchNginxToNewServer (From alternativePort) (To defaultPort)
                stopOldServerBy pidOfCurrentProcess
            (currentPort:_) -> do
                if currentPort == defaultPort
                    then do
                        startNewServerOn alternativePort
                        switchNginxToNewServer (From defaultPort) (To alternativePort)
                    else do
                        startNewServerOn defaultPort
                        switchNginxToNewServer (From alternativePort) (To defaultPort)
                stopOldServerBy pidOfCurrentProcess
 
    startNewServerOn :: Port -> Segment ()
    startNewServerOn port = startStopDaemon "--start" "-b" "-q" "-x" pathToExecutable "--" "-p" port "-f" pathToCommonFood
        
    stopOldServerBy :: PID -> Segment ()
    stopOldServerBy pid = startStopDaemon "--stop" "-o" "-q" "--pid" pid

    switchNginxToNewServer :: FromPort -> ToPort -> Segment ()
    switchNginxToNewServer (From currentPort) (To newPort) = do
        sudo "sed" "-i" replaceProxyPass pathToNginxConfig
        sudo "nginx" "-s" "reload"
      where
        replaceProxyPass = mconcat ["s#", proxyPass <> currentPort, "#", proxyPass <> newPort, "#g"]
        proxyPass        = "proxy_pass http://127.0.0.1:"

    -- Main constants.
    executableName      = "breadu-exe"                       
    rootDirectory       = "/home/dshevchenko/breadu-root"
    pathToCommonFood    = rootDirectory </> "food/common"
    pathToExecutable    = rootDirectory </> executableName
    pathToTmpExecutable = "/tmp" </> executableName
    pathToNginxConfig   = "/etc/nginx/sites-enabled/default"
    defaultPort         = "3000"
    alternativePort     = "3010"
main = run $ do
    mv pathToTmpExecutable pathToExecutable
    lookPIDOfCurrentProcess >>= \case
        Nothing  -> startNewServerOn defaultPort
        Just pid -> updateServer pid
  where
    lookPIDOfCurrentProcess :: Segment (Maybe PID)
    lookPIDOfCurrentProcess = strings (   pgrep "-l" executableName <|> return ()
                                       $| awk "{print $1}")
                              >>= \output -> return $ case output of
                                                          []      -> Nothing
                                                          (pid:_) -> Just pid

    updateServer :: PID -> Segment ()
    updateServer pidOfCurrentProcess = 
        strings (   sudo "netstat" "-antulp"  -- There's no operator to combine 'sudo' with command... :-(
                 $| grep executableName
                 $| awk "{split($4,a,\":\"); print a[2]}")
        >>= \output -> case output of
            [] -> do
                -- It's really strange: there's no port, but it must be here!
                startNewServerOn defaultPort
                switchNginxToNewServer (From alternativePort) (To defaultPort)
                stopOldServerBy pidOfCurrentProcess
            (currentPort:_) -> do
                if currentPort == defaultPort
                    then do
                        startNewServerOn alternativePort
                        switchNginxToNewServer (From defaultPort) (To alternativePort)
                    else do
                        startNewServerOn defaultPort
                        switchNginxToNewServer (From alternativePort) (To defaultPort)
                stopOldServerBy pidOfCurrentProcess
 
    startNewServerOn :: Port -> Segment ()
    startNewServerOn port = startStopDaemon "--start" "-b" "-q" "-x" pathToExecutable "--" "-p" port "-f" pathToCommonFood
        
    stopOldServerBy :: PID -> Segment ()
    stopOldServerBy pid = startStopDaemon "--stop" "-o" "-q" "--pid" pid

    switchNginxToNewServer :: FromPort -> ToPort -> Segment ()
    switchNginxToNewServer (From currentPort) (To newPort) = do
        sudo "sed" "-i" replaceProxyPass pathToNginxConfig
        sudo "nginx" "-s" "reload"
      where
        replaceProxyPass = mconcat ["s#", proxyPass <> currentPort, "#", proxyPass <> newPort, "#g"]
        proxyPass        = "proxy_pass http://127.0.0.1:"

    -- Main constants.
    executableName      = "breadu-exe"                       
    rootDirectory       = "/home/dshevchenko/breadu-root"
    pathToCommonFood    = rootDirectory </> "food/common"
    pathToExecutable    = rootDirectory </> executableName
    pathToTmpExecutable = "/tmp" </> executableName
    pathToNginxConfig   = "/etc/nginx/sites-enabled/default"
    defaultPort         = "3000"
    alternativePort     = "3010"