func pinyinifyLookupHandler(writer http.ResponseWriter, request *http.Request) {
	text := getLastPathComponent(request)

	charSet := cedict.DetermineCharSet(text)
	splitText, err := chinese.SplitChineseTextIntoWords(text, charSet)
	if err != nil {
		fmt.Fprint(writer, `{"error": "`+err.Error()+`}`)
		return
	}

	output := ""

	for _, word := range splitText {
		records, _ := cedict.FindRecords(word, charSet)

		if len(records) > 0 {
			output += records[0].Pinyin
		} else {
			output += word
		}

		output += " "
	}

	j, err := json.Marshal(map[string]interface{}{
		"error":  "nil",
		"result": output,
	})
	if err != nil {
		fmt.Fprint(writer, `{"error": "`+err.Error()+`}`)
		return
	}

	fmt.Fprint(writer, string(j))
}
func mcdsLookupHandler(writer http.ResponseWriter, request *http.Request) {
	text := getLastPathComponent(request)
	text = strings.Replace(text, "@SLASH@", "/", -1)
	text = strings.Replace(text, "\n", "<br />", -1)
	text = strings.Replace(text, "\t", "&nbsp;&nbsp;&nbsp;&nbsp;", -1)

	notes := request.FormValue("notes")
	notes = strings.Replace(notes, "@SLASH@", "/", -1)
	notes = strings.Replace(notes, "\n", "<br />", -1)
	notes = strings.Replace(notes, "\t", "&nbsp;&nbsp;&nbsp;&nbsp;", -1)

	charsRaw := request.FormValue("chars")
	charsArrayRaw := strings.Split(charsRaw, " ")
	// Construct new slice without empty strings
	chars := make([]string, 0)
	for _, char := range charsArrayRaw {
		if char != "" {
			chars = append(chars, char)
		}
	}

	colors := getColors(request)

	charSet := cedict.DetermineCharSet(text)
	splitText, err := chinese.SplitChineseTextIntoWords(text, charSet)
	if err != nil {
		fmt.Fprint(writer, `{"error": "`+err.Error()+`}`)
		return
	}

	var output string

	// Go through all chars to be clozed. Every iteration adds one line to the output var (i.e. one card)
	for _, char := range chars {
		var front, back string
		wordsToBeLookedUp := make([]string, 0)

		// This loop goes through all words in the text. This could be optimised by only going
		// through the text once and constructing all cards simultaneously
		for _, wordInText := range splitText {
			indexOfChar := strings.Index(wordInText, char)
			if indexOfChar == -1 {
				front += wordInText
				back += wordInText
			} else {
				front += strings.Replace(wordInText, char, clozeBegin+clozeChar+clozeEnd, -1)
				back += strings.Replace(wordInText, char, clozeBegin+char+clozeEnd, -1)

				wordsToBeLookedUp = append(wordsToBeLookedUp, wordInText)
			}
		}

		// Fine unique words to be looked up in moedict
		wordsToBeLookedUnique := make([]string, 0)
		for _, word := range wordsToBeLookedUp {
			alreadyInWordsToBeLookedUpUnique := false
			for _, wordUnique := range wordsToBeLookedUnique {
				if word == wordUnique {
					alreadyInWordsToBeLookedUpUnique = true
				}
			}
			if !alreadyInWordsToBeLookedUpUnique {
				wordsToBeLookedUnique = append(wordsToBeLookedUnique, word)
			}
		}

		cedictRecords := make([]cedict.Record, 0)
		for _, wordToBeLookedUpInCedict := range wordsToBeLookedUnique {
			records, _ := cedict.FindRecords(wordToBeLookedUpInCedict, charSet)
			for _, record := range records {
				cedictRecords = append(cedictRecords, record)
			}
		}

		moeEntries, err := findMoeEntriesForWords(wordsToBeLookedUnique, charSet)
		if err != nil {
			fmt.Fprint(writer, `{"error": "`+err.Error()+`}`)
			return
		}

		output += front
		output += "\t"
		output += back
		output += "\t"
		output += notes
		output += "\t"

		for _, moeEntry := range moeEntries {
			output += moeEntry.ToHTML(colors)
			output += "<br>"
		}

		output += "\t"

		for _, cr := range cedictRecords {
			output += cr.ToHTML(colors)
			output += "<br>"
		}

		output += "\n"
	}

	// TODO turn this into a function

	// use json.Marshal with an anonymous variable to escape the \t and " characters
	// in the response
	j, err := json.Marshal(map[string]interface{}{
		"error":  "nil",
		"result": output,
	})
	if err != nil {
		fmt.Fprint(writer, `{"error": "`+err.Error()+`}`)
		return
	}

	fmt.Fprint(writer, string(j))

}
func sentencesLookupHandler(writer http.ResponseWriter, request *http.Request) {
	sentence := getLastPathComponent(request)
	colors := getColors(request)

	fmt.Println("sentencesLookupHandler: " + string([]rune(sentence)[0:10]) + "。。。")

	// get words in sentence
	wordsRaw := findWordsInSentencesRegexp.FindAllStringSubmatch(sentence, -1)
	words := make([]string, len(wordsRaw))
	for i, w := range wordsRaw {
		words[i] = w[1]
	}

	charSet := cedict.DetermineCharSet(sentence)

	moeEntries, err := findMoeEntriesForWords(words, charSet)
	if err != nil {
		fmt.Fprint(writer, `{"error": "`+err.Error()+`", "sentence": "`+sentence+`"}`)
		return
	}

	cedictRecords := make([]cedict.Record, 0)
	for _, word := range words {
		records, err := cedict.FindRecords(word, charSet)
		if err != nil {
			fmt.Fprint(writer, `{"error": "`+err.Error()+`", "sentence": "`+sentence+`"}`)
			return
		}
		for _, record := range records {
			cedictRecords = append(cedictRecords, record)
		}
	}

	// construct csv row
	var output string

	var outputSentence string
	outputSentence = strings.Replace(sentence, "[", "", -1)
	outputSentence = strings.Replace(outputSentence, "]", "", -1)

	output += outputSentence
	output += "\t"

	for _, moeEntry := range moeEntries {
		output += moeEntry.ToHTML(colors)
		output += "<br>"
	}

	output += "\t"

	for _, cedictRecord := range cedictRecords {
		output += cedictRecord.ToHTML(colors)
		output += "<br>"
	}

	// This adds an additional field for the audio file
	output += "\t"
	// This is necessary for Anki to recognise all fields
	output += "&nbsp;"

	// TODO turn this into a function

	// use json.Marshal with an anonymous variable to escape the \t and " characters
	// in the response
	j, err := json.Marshal(map[string]interface{}{
		"error": "nil",
		"csv":   output,
	})
	if err != nil {
		fmt.Fprint(writer, `{"error": "`+err.Error()+`", "sentence": "`+sentence+`"}`)
		return
	}

	fmt.Fprint(writer, string(j))
}