/*
 * Copyright (C) 2020 The Project Lombok Authors.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package lombok.eclipse.agent;

import static lombok.eclipse.EclipseAugments.CompilationUnit_javadoc;

import java.lang.reflect.Method;
import java.util.Map;

import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.core.CompilationUnit;
import org.eclipse.jdt.internal.core.SourceMethod;
import org.eclipse.jdt.internal.ui.text.javadoc.JavadocContentAccess2;

import lombok.eclipse.EclipseAugments;
import lombok.eclipse.handlers.EclipseHandlerUtil;
import lombok.permit.Permit;

public class PatchJavadoc {
	
	public static String getHTMLContentFromSource(String original, IJavaElement member) {
		if (original != null) {
			return original;
		}
		
		if (member instanceof SourceMethod) {
			SourceMethod sourceMethod = (SourceMethod) member;
			ICompilationUnit iCompilationUnit = sourceMethod.getCompilationUnit();
			if (iCompilationUnit instanceof CompilationUnit) {
				CompilationUnit compilationUnit = (CompilationUnit) iCompilationUnit;
				Map<String, String> docs = EclipseAugments.CompilationUnit_javadoc.get(compilationUnit);
				
				String signature = getSignature(sourceMethod);
				String rawJavadoc = docs.get(signature);
				if (rawJavadoc == null) return null;
				
				return Reflection.javadoc2HTML((IMember) member, member, rawJavadoc);
			}
		}
		
		return null;
	}
	
	public static StringBuffer printMethod(AbstractMethodDeclaration methodDeclaration, Integer tab, StringBuffer output, TypeDeclaration type) {
		if (methodDeclaration.compilationResult.compilationUnit instanceof CompilationUnit) {
			Map<String, String> docs = CompilationUnit_javadoc.get((CompilationUnit) methodDeclaration.compilationResult.compilationUnit);
			if (docs != null) {
				String signature = EclipseHandlerUtil.getSignature(type, methodDeclaration);
				String rawJavadoc = docs.get(signature);
				if (rawJavadoc != null) {
					for (String line : rawJavadoc.split("\r?\n")) {
						ASTNode.printIndent(tab, output).append(line).append("\n");
					}
				}
			}
		}
		return methodDeclaration.print(tab, output);
	}

	private static String getSignature(SourceMethod sourceMethod) {
		StringBuilder sb = new StringBuilder();
		sb.append(sourceMethod.getParent().getElementName());
		sb.append(".");
		sb.append(sourceMethod.getElementName());
		sb.append("(");
		for (String type : sourceMethod.getParameterTypes()) {
			sb.append(type);
		}
		sb.append(")");
		
		return sb.toString();
	}
	
	/**
	 * The method <code>javadoc2HTML</code> changed 2014-12 to accept an
	 * additional IJavaElement parameter. To support older versions, try to
	 * find that one too.
	 */
	private static class Reflection {
		private static final Method javadoc2HTML;
		private static final Method oldJavadoc2HTML;
		static {
			Method a = null, b = null;
			
			try {
				a = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, IJavaElement.class, String.class);
			} catch (Throwable t) {}
			try {
				b = Permit.getMethod(JavadocContentAccess2.class, "javadoc2HTML", IMember.class, String.class);
			} catch (Throwable t) {}
			
			javadoc2HTML = a;
			oldJavadoc2HTML = b;
		}
		
		private static String javadoc2HTML(IMember member, IJavaElement element, String rawJavadoc) {
			if (javadoc2HTML != null) {
				try {
					return (String) javadoc2HTML.invoke(null, member, element, rawJavadoc);
				} catch (Throwable t) {
					return null;
				}
			}
			if (oldJavadoc2HTML != null) {
				try {
					return (String) oldJavadoc2HTML.invoke(null, member, rawJavadoc);
				} catch (Throwable t) {
					return null;
				}
			}
			return null;
		}
	}
}

@@ -2455,16 +2455,51 @@
 nUnit);%0A
+%09%09%09%09if (docs == null) return null;%0A
 %09%09%09%09%0A%09%09%09

Add missing null check