#' Shiny Version of TryCatch
#'
#' Use in reactive context, i.e. inside a server function only.
#' 
#' @param session the app session object
#' @param expr R expression to evaluate safely
#' @return NULL
#' @export
exec_safely <- function(session, expr) {

	tryCatch(
		withCallingHandlers(
			warning=function(cnd) {
				msg <- paste(conditionMessage(cnd), sep="\n")
				shiny::showNotification(
					ui=msg,
					duration=10,
					closeButton=TRUE,
					type="warning"
				)
			},
			message=function(cnd) {
				msg <- paste(conditionMessage(cnd), sep="\n")
				shiny::showNotification(
					ui=msg,
					duration=5,
					closeButton=TRUE,
					type="message"
				)
			},
			expr
		),

		error=function(cnd) {
			msg <- paste(conditionMessage(cnd), sep="\n")
			shiny::showNotification(
				ui=msg,
				duration=10,
				closeButton=TRUE,
				type="error"
			)
		}
	)
}

demo_exec_safely <- function() {
	stopifnot(
		require(shiny),
		require(shinydashboard)
	)
	
	nm <- "Demo: exec_safely"
	
	ui <- shinydashboard::dashboardPage(
		header=shinydashboard::dashboardHeader(title=nm),
		sidebar=shinydashboard::dashboardSidebar(),
		body=shinydashboard::dashboardBody(
			shiny::fluidRow(
				shiny::column(3, shiny::textInput("x", label="x:")),
				shiny::column(1, shiny::actionButton("btn","Click me", style = "margin-top:25px;")), # vertically aligned
				shiny::column(2, shiny::h2(shiny::textOutput("log_x_formatted")))
			)
		),
		title=nm
	)

	server <- function(input, output, session) {
		rv <- shiny::reactiveValues()
		
		shiny::observeEvent(input$btn, exec_safely(session,{ # redirect warnings etc. to ShowNotification
			x <- suppressWarnings(as.numeric(input$x))
			stopifnot(is.numeric(x) && !is.na(x))
			rv[["log_x"]] <- log(x)
		}))
		
		output$log_x_formatted <- shiny::renderText(sprintf("%.3f", rv[["log_x"]]))
	}

	shiny::runApp(shiny::shinyApp(ui, server))
}
