package com.jantvrdik.intellij.latte.psi;

import com.intellij.lang.Language;
import com.intellij.lang.LanguageParserDefinitions;
import com.intellij.lang.ParserDefinition;
import com.intellij.lang.html.HTMLLanguage;
import com.intellij.lang.xml.XMLLanguage;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.MultiplePsiFilesPerDocumentFileViewProvider;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.source.PsiFileImpl;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.psi.tree.IElementType;
import com.jantvrdik.intellij.latte.LatteLanguage;
import com.jantvrdik.intellij.latte.utils.LatteHtmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

public class LatteFileViewProvider extends MultiplePsiFilesPerDocumentFileViewProvider implements TemplateLanguageFileViewProvider {

	public static LatteElementType OUTER_LATTE = new LatteElementType("Outer latte");
	private static Pattern xmlContentType = Pattern.compile("^\\{contentType [^}]*xml[^}]*}.*");
	private static IElementType templateDataElement = new LatteTemplateDataElementType(
			"Outer HTML/XML in Latte",
			LatteLanguage.INSTANCE,
			LatteHtmlUtil.HTML_TOKENS,
			OUTER_LATTE
	);

	public LatteFileViewProvider(PsiManager manager, VirtualFile virtualFile, boolean eventSystemEnabled) {
		super(manager, virtualFile, eventSystemEnabled);
	}

	@NotNull
	@Override
	public Language getBaseLanguage() {
		return LatteLanguage.INSTANCE;
	}

	@NotNull
	public Set<Language> getLanguages() {
		Set<Language> languages = new HashSet<>(3);
		languages.add(LatteLanguage.INSTANCE);
		languages.add(getTemplateDataLanguage());

		return languages;
	}

	@Override
	protected MultiplePsiFilesPerDocumentFileViewProvider cloneInner(VirtualFile fileCopy) {
		return new LatteFileViewProvider(getManager(), fileCopy, false);
	}

	@NotNull
	@Override
	public Language getTemplateDataLanguage() {
		return isXml() ? XMLLanguage.INSTANCE : HTMLLanguage.INSTANCE;
	}

	@Nullable
	protected PsiFile createFile(@NotNull Language lang) {
		ParserDefinition parser = LanguageParserDefinitions.INSTANCE.forLanguage(lang);
		if (parser == null) {
			return null;
		} else if (lang == XMLLanguage.INSTANCE || lang == HTMLLanguage.INSTANCE) {
			PsiFileImpl file = (PsiFileImpl) parser.createFile(this);
			file.setContentElementType(templateDataElement);
			return file;
		} else {
			return lang == this.getBaseLanguage() ? parser.createFile(this) : null;
		}
	}

	private boolean isXml() {
		if (this.getDocument() == null) {
			return false;
		}
		String text = this.getDocument().getText();
		int pos = text.indexOf("\n");
		if (pos > 0) {
			text = text.substring(0, pos);
		}
		return xmlContentType.matcher(text).matches();
	}
}