/**
 * Copyright 2010 Bing Ran<bing_ran@hotmail.com>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at http://www.apache.org/licenses/LICENSE-2.0.
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package cn.bran.japid.classmeta;

import japa.parser.ast.body.Parameter;

import java.util.List;

import cn.bran.japid.compiler.JavaSyntaxTool;
import cn.bran.japid.tags.Each;


/**
 * used to wrapped the body of an invocation of a user defined tag based on tag template file
 * 
 * @author bran
 *
 */
public class InnerClassMeta {
	private static final String EXTRA_LOOP_ATTRS = ", final int _size, final int _index, final boolean _isOdd, final String _parity, final boolean _isFirst, final boolean _isLast";
	String tagName;
	// the sequence of the same tag called in a single template
	int counter;
	// like in a function call
	String renderParams;
	String renderBody;
//	private String interfaceName;
	public InnerClassMeta(String tagName, int counter, String callbackArgs, String renderBody) {
		this.tagName = tagName.replace('/', '.');
		this.counter = counter;
		this.renderParams = JavaSyntaxTool.boxPrimitiveTypesInParams(callbackArgs);
		this.renderBody = renderBody;
	}
//
//	/**
//	 * something like this: 	
//	 * <pre>
//	 * class Display1_Body implements DoBodyInterface{
//			void render(String title) {
//				pln ("The real title is: ", title);
//			}
//	 *	}
//	</pre>
//	 * @deprecated this method is the old way of declaring inner class. Now use the getAnonymous() in inline fashion. 
//	 */
//	@Override
//	public String toString() {
//		ExprParser ep = new ExprParser(this.renderArgs);
//		List<String> argTokens = ep.split();
//		// something String a Date b
//		assert(argTokens.size() % 2 == 0);
//		
//		String[] argTypes = new String[argTokens.size() /2];
//		
//		String classParams = "";
//		for (int i = 0; i < argTypes.length; i++) {
//			classParams += ", " + argTokens.get(i * 2);
//		}
//		
//		if (Each.class.getSimpleName().equals(tagName)) {
//			// append extra argument to the render method
//			renderArgs += EXTRA_LOOP_ATTRS;
//		}
//		
//		// remove the leading ,
//		
//		
//		if (classParams.startsWith(","))
//				classParams = "<" + classParams.substring(1) + ">";
//
//		StringBuilder sb = new StringBuilder();
//		line(sb, "class " + getVarRoot() + counter + "DoBody implements " + tagName + ".DoBody" +  classParams + "{");
//		line(sb, "\tpublic void render(" + renderArgs  + ") {");
//		line(sb, "\t\t" + renderBody);
//		line(sb, "\t}");
//		line(sb, "}");
//		
//		// bodyclass instance
//		String bodyClassName = getVarRoot() + counter +  "DoBody"; 
//		String bodyField = "private " + bodyClassName +" _" + bodyClassName + 
//			" = new " + bodyClassName + "();";
//		line(sb, "\t" + bodyField);
//
//		return sb.toString();
//	}
	
	private void line (StringBuilder sb, String line) {
		sb.append(line + "\n");
	}
	
	public String getVarRoot() {
		return tagName.replace('.', '_').replace('/', '_');
	}

	/**
	 * get something like this 
	 * <pre>
	 * 		new Display.DoBody<String>() {
	 *			public void render(String title) {
	 *				p(" The real title is: ");
	 *				p(title);
	 *			}
	 *		});
	 * </pre>
	 * @return
	 */
	public String getAnonymous() {
		List<Parameter> params = JavaSyntaxTool.parseParams(this.renderParams);
		
		String[] argTypes = new String[params.size()];
		
		String generics = "";
		for (int i = 0; i < argTypes.length; i++) {
			generics += ", " + params.get(i).getType();
		}
		if (generics.startsWith(","))
			generics = "<" + generics.substring(1).trim() + ">";
		
		if (Each.class.getSimpleName().equalsIgnoreCase(tagName)) {
			// append extra argument to the render method
			tagName = Each.class.getSimpleName();
			renderParams += EXTRA_LOOP_ATTRS;
		}
		
		String paramList = renderParams;
		String renderArgsWithFinal = JavaSyntaxTool.addFinalToAllParams(paramList);
		
		StringBuilder sb = new StringBuilder();
		line(sb, "new " + tagName + ".DoBody" +  generics + "(){");
		line(sb, "public void render(" + renderArgsWithFinal  + ") {");
		line(sb, renderBody);
		line(sb, "}");
		String bufferString = "\r\n" + 
				"StringBuilder oriBuffer;\r\n" + 
				"@Override\r\n" + 
				"public void setBuffer(StringBuilder sb) {\r\n" + 
				"	oriBuffer = getOut();\r\n" + 
				"	setOut(sb);\r\n" + 
				"}\r\n" + 
				"\r\n" + 
				"@Override\r\n" + 
				"public void resetBuffer() {\r\n" + 
				"	setOut(oriBuffer);\r\n" + 
				"}\r\n";
		line(sb, bufferString);
		line(sb, "}");
		
		return sb.toString();
	}
}
