#' Escape WikiWords in \special{MoinMoin} Markup
#'
#' Words with MoinMoin would convert to page links are escaped by adding a leading exclamation mark.
#' @param x a character vector.
#' @keywords internal
#' @return WikiWords in x are escaped as !WikiWords. WikiWords within markup such as `WikiWord`, [[WikiWord]] and [[ ParentPage/WikiWord | WikiWord ]] are not escaped.
#' @examples
#' escapeThese <- "WikiWord, WikiWikiWord and _ThisOneToo"
#' escWw(escapeThese)
#' notThese <- "`NotThisOne`, [[NotThisTwo]], [[ NorThese  |LabelMe ]]"
#' escWw(escapeThese)
#' # vector input
#' escWw(c(a="WikiWord", b="`NotThis`"))
escWw <- function(x) { # escape WikiWords with exclamation mark
	Ww <- "([[:upper:]]{1}([[:lower:][:digit:]]){1,}){2,}"
	pattern <- gsub("Ww", Ww,"(*UCP)(\\b|_)(Ww)(?>\\b|_)", perl = TRUE)
	x <- gsub(pattern, "\\1\1\\2", x, perl = TRUE) #insert marker before Ww
	x <- gsub("!\1", "!", x, perl = TRUE) # already escaped, remove marker
	pattern <- "(?<=`)(.*?)\1(?=.*?`)" # in literal, remove marker
	while (length(grep(pattern, x, perl = TRUE))) {
		x <- gsub(pattern, "\\1", x, perl = TRUE)
		}
	pattern <- "(?<=\\[\\[)(.*?)\1(?=.*?]])" # in link, remove marker
	while (length(grep(pattern, x, perl = TRUE))) {
		x <- gsub(pattern, "\\1", x, perl = TRUE)
		}
	gsub("\1", "!", x, perl = TRUE) # convert marker to escape
}


#' Obfuscate Email Addresses
#'
#' Obfuscate email address to be used in the \special{MoinMon} macro \code{<<MailTo()>>} as a spam minimisation strategy.
#' @param x a character vector.
#' @param reverse logical: if \code{TRUE} the obfuscation process is reversed.
#' @keywords internal
#' @return An email address of "user-name@host.net" is obfuscated as "u s e r DASH n a m e AT h o s t DOT n e t".
#' @examples
#' obfuscate("email.recipient@gmail.com")
#' # reversable
#' obfuscate(obfuscate("email.recipient@gmail.com"), reverse = TRUE)
#' # vector input
#' obfuscate(list(a="joe.blogs@bloggers.net", b="no-reply@localhost"))
obfuscate <- function(x, reverse = FALSE) {
	do <- function(x) {
			x <- paste0(unlist(strsplit(x, "")), collapse = "\u00a0")
			x <- gsub("@", "AT", x)
			x <- gsub('\\.', "DOT", x)
			gsub('-', "DASH", x)
	}
	undo <- function(x) {	
			x <- gsub("AT", "@", x)
			x <- gsub("DOT", '.', x)
			x <- gsub("DASH", '-', x)
			gsub(" |\u00a0", "", x)
	}
	USE.NAME <- !is.null(names(x))
	if (reverse) vapply(x, undo, "", USE.NAMES = USE.NAME)
	else vapply(x, do, "", USE.NAMES = USE.NAME)
}

# MoinMoin Markup constants
Objects0 <- ls(all.names = TRUE, pattern = "^[.]")
.space <- " "
.heading <- "="
.italic <- "''"
.bold <- "'''"
.monospace <- "`"
.underline <- "__"
.superscript <- "^"
.subscript <- ",,"
.smallerOpen <- "~-"
.smallerClose <- "-~"
.smaller <- c(.smallerOpen, .smallerClose)
.largerOpen <- "~+"
.largerClose <- "+~"
.larger <- c(.largerOpen, .largerClose)
.stroke <- "--"
.linkOpen <- "[["
.linkClose <- "]]"
.link <- c(.linkOpen, .linkClose)
.linkSep <- "|"
.linkEsc <- "!"
.linkAttachOpen <- "[[attachment:"
.linkAttach <- c(.linkAttachOpen, .linkClose)
.itemBullet <- " * "
.itemNumeric <- " 1. "
.itemNumberOpen <- .space
.itemNumberClose <- ". "
.itemNumber <- c(.space, .itemNumberClose)
.itemNone <- " . " 
.itemLabelOpen <- .space
.itemLabelClose <- ":: "
.itemLabel <- c(.space, .itemLabelClose)
.indent <- .space
.hozline <- "-"
.hozlineBase <- "---" 
.newline <- .break <- "<<BR>>"
.mailToOpen <- "<<MailTo("
.mailToClose <- ")>>"
.mailTo <- c(.mailToOpen, .mailToClose)
.rowOpen <- "|| "
.rowClose <- " ||\n"
.rowSep <- " || "
.tabRow <- c(.rowOpen, .rowClose)
.codeOpen <- "{{{"
.codeClose <- "}}}"
.code <- c(.codeOpen, .codeClose)
.commentOpen <- "/* "
.commentClose <- " */"
.comment <- c(.commentOpen, .commentClose)
.blockClose <- "\n}}}"
.codeBlockOpen <- "{{{#!highlight r\n"
.codeBlock <- c(.codeBlockOpen, .blockClose)
.verbBlockOpen <- "{{{\n"
.verbBlock <- c(.verbBlockOpen, .blockClose)
.commentBlockOpen <- "{{{#!wiki comment\n"
.commentBlock <- c(.commentBlockOpen, .blockClose)
Objects <- ls(all.names = TRUE, pattern = "^[.]")
markupConstants <- Objects[!Objects %in% Objects0]
remove(Objects0) ; remove(Objects)

#' Apply \special{MoinMoin} Markup
#'
#' @param x a character vector to which markup is to be applied. For some markup types \code{x} may need to be named. For some markup, x is not not required, so it does not need to be provided, but if it is, then it is ignored (no error is generated).
#' @param type a string specifing the type of markup to be applied. Not specifying a recognised markup is ignored and \code{x} return unchanged.
#' @param level integer specifing heading level, list item number, depth of indenting, or horizontal line weight. If not needed, this paramater is ignored (no error is generated).
#' @keywords internal
#' @return \code{x} is return with selected markup applied.
#' @examples
#' markup("Introduction", "heading", 2)
#' markup(, "newline")
#' markup(, "hozline", 4)
#' link <- setNames("abc.net.au/news", "oz news")
#' markup(link, "linkNamed")
markup <- function(x = "", type = "", level = 1L) {
	
	if (is.null(x)) stop("markup cannot be applied to NULL")
	
	if (type %in% markupConstants) return(eval(as.name(type)))
	
	fcodes <- c(l = "", 
				c = "<style=\"text-align: center;\">",
				r = "<style=\"text-align: right;\">")
				
	# from 'local' package:
	# x %w% y wrap as y[1].x.y[2]; x %p% y paste as x.y
	
	if (type != "table") {
		x <- x[1] # no vectors
		if (is.null(names(x))) names(x) <- ""
		if (as.integer(level) <= 0L) level <- 1L
		switch(type,
			"heading" =
				x %w% .indent %w% strrep(.heading, level),
			"italic" = 
				x %w% .italic,
			"bold" = 
				x %w% .bold,
			"monospace" = 
				x %w% .monospace,
			"underline" = 
				x %w% .underline,
			"superscript" = 
				x %w% .superscript,
			"subscript" = 
				x %w% .subscript,
			"smaller" = 
				x %w% .smaller,
			"larger" = 
				x %w% .larger,
			"stroke" = 
				x %w% .stroke,
			"link" = 
				x %w% .link,
			"linkNamed" = 
				.linkSep %w% c(x, names(x)) %w% .link,
			"linkAttach" =
				x %w% .linkAttach,
			"linkAttachNamed" = 
				.linkSep %w% c(x, names(x)) %w% .linkAttach,
			"linkEsc" = 
				.linkEsc %p% x,
			"itemBullet" = 
				.itemBullet %p% x,
			"itemNumeric" =
				.itemNumeric %p% x,
			"itemNumber" = 
				as.integer(level) %w% .itemNumber %p% x,
			"itemNone" = 
				.itemNone %p% x ,
			"itemLabel" = 
				names(x) %w% .itemLabel %p% x,
			"indent" = 
				strrep(.indent, level) %p% x,
			"hozline" = 
				.hozlineBase %p% strrep(.hozline, level),
			"newline" = 
				.newline,
			"mailTo" = 
				obfuscate(x) %w% .mailTo,
			"code" = 
				x %w% .code,
			"comment" = 
				x %w% .comment,
			"codeBlock" = 
				x %w% .codeBlock,
			"verbBlock" = 
				x %w% .verbBlock,
			"commentBlock" = 
				x %w% .commentBlock,
			return(x) # if not recognised, do nothing
			)
	} else {
		local::as.object(dim(x), rows, cols, envir = environment())
		x <- vapply(2L:rows, function(r)
			fcodes[x[1L,]] %p% x[r,], x[1L,])
		rows <- rows - 1L
		x <- matrix(x, rows, cols, byrow = TRUE)
		vapply(1L:rows, function(r) 
			paste0(x[r,], collapse = .rowSep) %w% .tabRow, "")
	}
}
