package org.lilystudio.smarty4j;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.lilystudio.smarty4j.statement.Document;
import org.lilystudio.util.DynamicClassLoader;
import org.lilystudio.util.StringReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
public class Template {
public static final String NAME = Template.class.getName().replace('.', '/');
private static String[] INTERFACES = { IParser.NAME };
private Engine engine;
private String name;
private long lastModified;
private String path;
private File file;
private List<File> associatedFiles;
private List<INode> nodes;
private INode doc;
private Map<String, Boolean> variables;
private IParser parser;
public Template(Engine engine, String text) throws TemplateException {
this(engine, null, new StringReader(text), true);
}
public Template(Engine engine, String path, Reader reader, boolean parse) throws TemplateException {
this.variables = new HashMap();
this.engine = engine;
if (path != null) {
this.path = path.replace('\\', '/');
this.name = path.substring(engine.getTemplatePath().length());
}
TemplateReader in = new TemplateReader(reader);
this.doc = new Document(this, in);
in.checkStatus(this.name);
if (parse) this.parser = toParser(null);
}
Template(Engine engine, File file) throws IOException, TemplateException {
this(engine, file.getAbsolutePath(), new InputStreamReader(new FileInputStream(file), engine.getEncoding()), true);
this.file = file;
this.name = this.path.substring(engine.getTemplatePath().length());
this.lastModified = file.lastModified();
}
public Engine getEngine() {
return this.engine;
}
public String getName() {
return this.name;
}
public boolean isUpdated() {
if (this.file.lastModified() > this.lastModified) {
return true;
}
if (this.associatedFiles != null) {
for (File file : this.associatedFiles) {
if (file.lastModified() > this.lastModified) {
return true;
}
}
}
return false;
}
public String getPath() {
return this.path;
}
public String getPath(String path, boolean isTemplateName) {
if (this.name == null) return path;
if (path.charAt(0) != '/') {
String s = (isTemplateName) ? this.name : this.path;
int last = s.lastIndexOf(47);
if (last >= 0) path = s.substring(0, last + 1) + path;
} else if (!(isTemplateName)) {
return this.engine.getTemplatePath() + path;
}
return path;
}
public void associate(File file) {
if (this.associatedFiles == null) {
this.associatedFiles = new ArrayList();
}
this.lastModified = Math.max(file.lastModified(), this.lastModified);
this.associatedFiles.add(file);
}
public INode getNode(int index) {
return ((INode) this.nodes.get(index));
}
public int addNode(INode node) {
if (this.nodes == null) {
this.nodes = new ArrayList();
}
this.nodes.add(node);
return (this.nodes.size() - 1);
}
public void addUsedVariable(String name) {
if (this.variables != null) {
Boolean value = (Boolean) this.variables.get(name);
if (value == null) this.variables.put(name, Boolean.TRUE);
}
}
public void preventCacheVariable(String name) {
if (this.variables != null) this.variables.put(name, Boolean.FALSE);
}
public void preventAllCache() {
this.variables = null;
}
public void merge(Context context, OutputStream out) throws Exception {
Writer writer = new TemplateWriter(out, this.engine.getEncoding());
try {
merge(context, writer);
} finally {
writer.flush();
}
}
public void merge(Context context, Writer out) {
context.setTemplate(this);
this.parser.merge(context, out);
}
public IParser toParser(String name) {
ClassWriter cw = new ClassWriter(3);
if (name != null) {
cw.visitSource(name, null);
}
name = "template";
cw.visit(49, 1, name, null, "java/lang/Object", INTERFACES);
MethodVisitor mw = cw.visitMethod(1, "<init>", "()V", null, null);
mw.visitVarInsn(25, 0);
mw.visitMethodInsn(183, "java/lang/Object", "<init>", "()V");
mw.visitInsn(177);
mw.visitMaxs(0, 0);
mw.visitEnd();
mw = cw.visitMethod(1, "merge", "(L" + Context.NAME + ";Ljava/io/Writer;)V", null, null);
mw.visitVarInsn(25, 1);
mw.visitMethodInsn(182, Context.NAME, "getTemplate", "()L" + NAME + ";");
mw.visitVarInsn(58, 3);
this.doc.scan(this);
Map variableNames = null;
if (this.variables != null) {
variableNames = new HashMap();
for (Map.Entry variable : this.variables.entrySet()) {
if (((Boolean) variable.getValue()).booleanValue()) {
int value = 4 + variableNames.size();
String key = (String) variable.getKey();
mw.visitVarInsn(25, 1);
mw.visitLdcInsn(key);
mw.visitMethodInsn(182, Context.NAME, "get", "(Ljava/lang/String;)Ljava/lang/Object;");
mw.visitVarInsn(58, value);
variableNames.put(key, Integer.valueOf(value));
}
}
this.variables = null;
}
this.doc.parse(mw, 4 + ((variableNames != null) ? variableNames.size() : 0), variableNames);
mw.visitInsn(177);
mw.visitMaxs(0, 0);
mw.visitEnd();
cw.visitEnd();
byte[] code = cw.toByteArray();
try {
FileOutputStream fos = new FileOutputStream("tmp/smarty4j_" + name + ".class");
fos.write(code);
fos.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
try {
return ((IParser) DynamicClassLoader.getClass(name, code).newInstance());
} catch (Exception e) {
throw new RuntimeException("不能实例化Parser对象");
}
}
}