package goPress

//
// Library:           Shortcodes
//
// Description:    This library gives the functionality of shortcodes in the CMS. A
//                         shortcode runs a function with specified argument and a
//                         surrounded contents. The function should process the contents
//                         according to the arguments and return a string for placement into the page.
//                         Shortcodes are recursively processed, therfore you can have different shortcodes
//                         inside of other shortcodes.  You can not have the same shortcode instide of itself.
//
import (
	"bytes"
	"log"
	"regexp"
)

//
// Type:                  ShortcodeFunction
//
// Description:       This type defines a function that implements a shortcode. The function
//			    should receive two strings and return a string.
//
type ShortcodeFunction func(string, string) string

//
// Library Variables:
//
// 			shortcodeStack 		This array of functions holds all of the shortcodes usable
//							by the CMS. You add shortcodes using the AddShortCode
//			 				function.
//
var (
	shortcodeStack map[string]ShortcodeFunction
)

//
// Library Function:
//
//				init 			This function is called upon library use to initialize
//							any variables used for the library before anyone'
// 							can make a call to a library function.
//

func init() {
	shortcodeStack = make(map[string]ShortcodeFunction)
}

//
// Function:		 AddShortCode
//
// Description:	 This function adds a new shortcode to be used.
//
// Inputs
//					 		name           Name of the shortcode
//                   funct          function to process the shortcode
//
func AddShortCode(name string, funct ShortcodeFunction) {
	shortcodeStack[name] = funct
}

//
// Function:		ProcessShortCodes
//
// Description:		This function takes in a string, searches for shortcodes,
//                  		process the shortcode, put the results into the string, and
//                   		then return the fully processed string.
//
// Inputs
//				page            String with possible shortcodes
//
func ProcessShortCodes(page string) string {
	//
	// Create a work buffer.
	//
	var buff bytes.Buffer

	//
	// Search for shortcodes. We first capture a shortcode.
	//
	r, err := regexp.Compile(`\-\[([^\]]*)\]\-`)
	if err == nil {
		match := r.FindString(page)
		if match != "" {
			//
			// Get the indexes to the matching area.
			//
			index := r.FindStringIndex(page)

			//
			// Save all the text before the shortcode into the buffer.
			//
			buff.WriteString(page[0:index[0]])

			//
			// Get everything that is left after the shortcode.
			//
			remander := page[index[1]:]

			//
			// Separate the strings out and setup variables for their contents.
			//
			submatch := r.FindStringSubmatch(match)
			name := ""
			contents := ""
			args := ""

			//
			// Get the name of the shortcode and separate the extra arguments.
			//
			r3, err3 := regexp.Compile(`(\w+)(.*)`)
			if err3 == nil {
				submatch2 := r3.FindStringSubmatch(submatch[1])

				//
				// The first submatch is the name of the shortcode.
				//
				name = submatch2[1]

				//
				// The second submatch, if any, are the arguments for the shortcode.
				//
				args = submatch2[2]
			} else {
				//
				// Something happened to the internal matching. Just
				name = submatch[1]
				args = ""
			}

			//
			// Find the end of the shortcode.
			//
			final := "\\-\\[\\/" + name + "\\]\\-"
			r2, err2 := regexp.Compile(final)
			if err2 == nil {
				index2 := r2.FindStringIndex(remander)
				if index2 != nil {
					//
					// Get the contents and what is left over after the closing of the shortcode.
					//
					contents = remander[:index2[0]]
					remander2 := remander[index2[1]:]

					//
					// If it is a real shortcode, then run it!
					//
					if shortcodeStack[name] != nil {
						//
						// See if there is any shortcodes inside the contents area.
						//
						contents = ProcessShortCodes(contents)

						//
						// Run the shortcode and add it's result to the buffer.
						//
						buff.WriteString(shortcodeStack[name](args, contents))
					}

					//
					// Process any remaining shortcodes.
					//
					buff.WriteString(ProcessShortCodes(remander2))

				} else {
					//
					// We have a bad shortcode definition.  All shortcodes have to be closed. Therefore,
					// simply do not process anything and tell the logs.
					//
					log.Println("Bad Shortcode definition. It was not closed.  Name:  " + name)
					buff.WriteString(page[index[0]:index[1]])
					buff.WriteString(ProcessShortCodes(remander))
				}
			} else {
				//
				// There was an error in the regular expression for closing the shortcode.
				//
				log.Println("The closing shortcode's regexp did not work!")
			}
		} else {
			//
			// No shortcodes, just copy the page to the buffer.
			//
			buff.WriteString(page)
		}
	} else {
		//
		// If the Regular Expression is invalid, tell the world!
		//
		log.Println("RegEx: Invalid expression.")
	}

	//
	// Return the resulting buffer.
	//
	return buff.String()
}

//
// Function:           ShortcodeBox
//
// Description:       This shortcode is used to put the surrounded HTML in a box div.
//
// Inputs:
//			parms 		The parameters used by the shortcode
//			context		The HTML enclosed by the opening and closing shortcodes.
//
func ShortcodeBox(parms string, context string) string {
	return ("<div class='box'>" + context + "</div>")
}

//
// Function:           ShortcodeColumn1
//
// Description:       This shortcode is used to put the surrounded HTML in the first column.
//
// Inputs:
//			parms 		The parameters used by the shortcode
//			context		The HTML enclosed by the opening and closing shortcodes.
//
func ShortcodeColumn1(parms string, context string) string {
	return ("<div class='col1'>" + context + "</div>")
}

//
// Function:           ShortcodeColumn2
//
// Description:       This shortcode is used to put the surrounded HTML in the second column.
//
// Inputs:
//			parms 		The parameters used by the shortcode
//			context		The HTML enclosed by the opening and closing shortcodes.
//
func ShortcodeColumn2(parms string, context string) string {
	return ("<div class='col2'>" + context + "</div>")
}

//
// Function:		ShortcodePHP
//
// Description:		This shortcode is for surrounding a code block
// 				and formatting it's look and feel properly. This
//				one is for a PHP code block.
//
// Inputs:
//			parms 		The parameters used by the shortcode
//			context		The HTML enclosed by the opening and closing shortcodes.
//
func ShortcodePHP(params string, context string) string {
	return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: php'>" + context + "</pre></div>")
}

//
// Function:		ShortcodeJS
//
// Description:		This shortcode is for surrounding a code block
// 				and formatting it's look and feel properly. This
//				one is for a JavaScript code block.
//
// Inputs:
//			parms 		The parameters used by the shortcode
//			context		The HTML enclosed by the opening and closing shortcodes.
//
func ShortcodeJS(params string, context string) string {
	return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: javascript'>" + context + "</pre></div>")
}

//
// Function:		ShortcodeHTML
//
// Description:		This shortcode is for surrounding a code block
// 				and formatting it's look and feel properly. This
//				one is for a HTML code block.
//
// Inputs:
//			parms 		The parameters used by the shortcode
//			context		The HTML enclosed by the opening and closing shortcodes.
//
func ShortcodeHTML(params string, context string) string {
	return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: html'>" + context + "</pre></div>")
}

//
// Function:		ShortcodeCSS
//
// Description:		This shortcode is for surrounding a code block
// 				and formatting it's look and feel properly. This
//				one is for a CSS code block.
//
// Inputs:
//			parms 		The parameters used by the shortcode
//			context		The HTML enclosed by the opening and closing shortcodes.
//
func ShortcodeCSS(params string, context string) string {
	return ("<div class='showcode'><pre type='syntaxhighlighter' class='brush: css'>" + context + "</pre></div>")
}

//
// Function:           LoadDefaultShortcodes
//
// Description:       This function is used to load in all the default shortcodes.
//
// Inputs:
//
func LoadDefaultShortcodes() {
	AddShortCode("Box", ShortcodeBox)
	AddShortCode("Column1", ShortcodeColumn1)
	AddShortCode("Column2", ShortcodeColumn2)
	AddShortCode("php", ShortcodePHP)
	AddShortCode("javascript", ShortcodeJS)
	AddShortCode("html", ShortcodeHTML)
	AddShortCode("css", ShortcodeCSS)
}
