/*
Translate file names for sharefile
*/

package sharefile

import (
	"regexp"
	"strings"
)

// charMap holds replacements for characters
//
// Sharefile has a restricted set of characters compared to other
// cloud storage systems, so we to map these to the FULLWIDTH unicode
// equivalents
//
// http://unicode-search.net/unicode-namesearch.pl?term=SOLIDUS
var (
	charMap = map[rune]rune{
		'\\': '\', // FULLWIDTH REVERSE SOLIDUS
		'*':  '*', // FULLWIDTH ASTERISK
		'<':  '<', // FULLWIDTH LESS-THAN SIGN
		'>':  '>', // FULLWIDTH GREATER-THAN SIGN
		'?':  '?', // FULLWIDTH QUESTION MARK
		':':  ':', // FULLWIDTH COLON
		'|':  '|', // FULLWIDTH VERTICAL LINE
		'"':  '"', // FULLWIDTH QUOTATION MARK
		'.':  '.', // FULLWIDTH FULL STOP
		' ':  '␠', // SYMBOL FOR SPACE
	}
	invCharMap            map[rune]rune
	fixStartingWithPeriod = regexp.MustCompile(`(/|^)\.`)
	fixEndingWithPeriod   = regexp.MustCompile(`\.(/|$)`)
	fixStartingWithSpace  = regexp.MustCompile(`(/|^) `)
	fixEndingWithSpace    = regexp.MustCompile(` (/|$)`)
)

func init() {
	// Create inverse charMap
	invCharMap = make(map[rune]rune, len(charMap))
	for k, v := range charMap {
		invCharMap[v] = k
	}
}

// replaceReservedChars takes a path and substitutes any reserved
// characters in it
func replaceReservedChars(in string) string {
	// Names can't start with a period '.'
	in = fixStartingWithPeriod.ReplaceAllString(in, "$1"+string(charMap['.']))
	// Names can't end with a period '.'
	in = fixEndingWithPeriod.ReplaceAllString(in, string(charMap['.'])+"$1")
	// Names can't start with space
	in = fixStartingWithSpace.ReplaceAllString(in, "$1"+string(charMap[' ']))
	// Names can't end with space
	in = fixEndingWithSpace.ReplaceAllString(in, string(charMap[' '])+"$1")
	// Replace reserved characters
	return strings.Map(func(c rune) rune {
		if replacement, ok := charMap[c]; ok && c != '.' && c != '~' && c != ' ' {
			return replacement
		}
		return c
	}, in)
}

// restoreReservedChars takes a path and undoes any substitutions
// made by replaceReservedChars
func restoreReservedChars(in string) string {
	return strings.Map(func(c rune) rune {
		if replacement, ok := invCharMap[c]; ok {
			return replacement
		}
		return c
	}, in)
}