package org.codiki.core.services;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringEscapeUtils;
import org.codiki.core.utils.StringUtils;
import org.springframework.stereotype.Service;

@Service
public class ParserService {

	private static final String REG_CODE = "\\[code lg=&quot;([a-z]+)&quot;\\](.*)\\[\\/code\\]\\n";
	private static final String REG_CODE_REPLACE = "<pre class=\"line-numbers\"><code class=\"language-\\1\">\\2</code></pre>";
	private static final String REG_IMAGES = "\\[img src=&quot;([^\"| ]+)&quot;( alt=&quot;([^\"| ]+)&quot;)? \\/\\]";
	private static final String REG_IMAGES_REPLACE = "<img src=\"\\1\" alt=\"\\3\" />";
	private static final String REG_LINKS = "\\[link href=&quot;([^\"| ]+)&quot; txt=&quot;([^\"| ]+)&quot; \\/\\]";
	private static final String REG_LINKS_REPLACE = "<a href=\"\\1\">\\2</a>";

	static final Pattern PATTERN_CODE;
	static final Pattern PATTERN_CODE_REPLACE;
	static final Pattern PATTERN_IMAGES;
	static final Pattern PATTERN_IMAGES_REPLACE;
	static final Pattern PATTERN_LINKS;
	static final Pattern PATTERN_LINKS_REPLACE;

	static {
		PATTERN_CODE = Pattern.compile(REG_CODE);
		PATTERN_CODE_REPLACE = Pattern.compile(REG_CODE_REPLACE);
		PATTERN_IMAGES = Pattern.compile(REG_IMAGES);
		PATTERN_IMAGES_REPLACE = Pattern.compile(REG_IMAGES_REPLACE);
		PATTERN_LINKS = Pattern.compile(REG_LINKS);
		PATTERN_LINKS_REPLACE = Pattern.compile(REG_LINKS_REPLACE);
	}
	
	public String parse(String pSource) {
		return unParseDolars(parseCode(parseHeaders(parseImages(parseLinks(parseBackSpaces(StringEscapeUtils.escapeHtml(parseDolars(pSource))))))));
	}
	
	private String parseDolars(final String pSource) {
		return pSource.replace("$", "£ø");
	}
	
	private String unParseDolars(final String pSource) {
		return pSource.replace("&pound;&oslash;", "$");
	}
	
	protected String parseHeaders(final String pSource) {
		String result = pSource;
		for(int i = 1 ; i <= 3 ; i++) {
			result = parseHeadersHX(result, i);
		}
		return result;
	}
	
	protected String parseHeadersHX(final String pSource, final int pNumHeader) {
		String result = pSource;
		
		// (.*)(\[hX\](.*)\[\/hX\])+(.*)
		final String regex = StringUtils.concat("(.*)(\\[h", pNumHeader, "\\](.*)\\[\\/h", pNumHeader, "\\])+(.*)");
		
		final Pattern pattern = Pattern.compile(regex);
		
		Matcher matcher = pattern.matcher(result);
		
		while(matcher.find()) {
			// \1<hX>\3</hX>\4
			result = matcher.replaceFirst(StringUtils.concat(matcher.group(1),
					"<h", pNumHeader, ">", matcher.group(3), "</h", pNumHeader, ">", matcher.group(4)));
			matcher = pattern.matcher(result);
		}
		
		return result;
	}
	
	protected String parseBackSpaces(final String pSource) {
		return pSource.replaceAll("\r?\n", "<br/>").replaceAll("\\[\\/code\\]<br\\/><br\\/>", "[/code]\n");
	}
	
	protected String parseImages(final String pSource) {
		String result = pSource;
		
		Matcher matcher = PATTERN_IMAGES.matcher(result);
		
		while(matcher.find()) {
			String altStr = matcher.group(3);
			
			if(altStr == null) {
				altStr = "";
			}
			
			result = matcher.replaceFirst(StringUtils.concat("<img src=\"", matcher.group(1), "\" alt=\"", altStr, "\" />"));
			matcher = PATTERN_IMAGES.matcher(result);
		}
		
		return result;
	}
	
	protected String parseLinks(final String pSource) {
		String result = pSource;
		
		Matcher matcher = PATTERN_LINKS.matcher(result);
		
		while(matcher.find()) {
			result = matcher.replaceFirst(StringUtils.concat("<a href=\"", matcher.group(1), "\">", matcher.group(2), "</a>"));
			matcher = PATTERN_LINKS.matcher(result);
		}
		
		return result;
	}
	
	protected String parseCode(final String pSource) {
		String result = pSource;
		
		Matcher matcher = PATTERN_CODE.matcher(result);
		
		while(matcher.find()) {
			// replace the '<br/>' in group by '\n'
			String codeContent = matcher.group(2).replaceAll("<br\\/>", "\n");
			if(codeContent.startsWith("\n")) {
				codeContent = codeContent.substring(1);
			}
			
			result = matcher.replaceFirst(StringUtils.concat("<pre class=\"line-numbers\"><code class=\"language-", matcher.group(1), "\">", codeContent, "</code></pre>"));
			matcher = PATTERN_CODE.matcher(result);
		}
		
		return result;
	}

}