/**
* Copyright (c) 2014, the Railo Company Ltd.
* Copyright (c) 2015, Lucee Assosication Switzerland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.transformer.cfml.evaluator.impl;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import lucee.commons.io.res.util.ResourceUtil;
import lucee.loader.engine.CFMLEngine;
import lucee.runtime.PageSource;
import lucee.runtime.config.Constants;
import lucee.runtime.type.util.ComponentUtil;
import lucee.transformer.bytecode.Page;
import lucee.transformer.bytecode.Statement;
import lucee.transformer.bytecode.statement.tag.Attribute;
import lucee.transformer.bytecode.statement.tag.Tag;
import lucee.transformer.bytecode.statement.tag.TagCIObject;
import lucee.transformer.bytecode.util.ASMUtil;
import lucee.transformer.cfml.evaluator.EvaluatorException;
import lucee.transformer.cfml.evaluator.EvaluatorSupport;
import lucee.transformer.expression.Expression;
import lucee.transformer.expression.literal.LitBoolean;
import lucee.transformer.expression.literal.LitString;
import lucee.transformer.library.tag.TagLibTag;
import lucee.transformer.util.PageSourceCode;
import lucee.transformer.util.SourceCode;
/**
* Prueft den Kontext des Tag break.
* Das Tag <code>break</code> darf nur innerhalb des Tag <code>loop, while, foreach</code> liegen.
*/
public class Component extends EvaluatorSupport {
@Override
public void evaluate(Tag tag,TagLibTag tlt) throws EvaluatorException {
/*if(tag instanceof TagOther) {
print.e(((TagOther)tag).getFullname());
}*/
TagCIObject tc=(TagCIObject) tag;
Statement pPage = tag.getParent();
//String className=tag.getTagLibTag().getTagClassName();
Page page;
// move components inside script to root
if(pPage instanceof Page){
page=(Page) pPage;
}
else {
// is in script
Tag p = ASMUtil.getParentTag(tag);
if((pPage = p.getParent()) instanceof Page &&
p.getTagLibTag().getName().equalsIgnoreCase(((Page)pPage).getSourceCode().getDialect()==CFMLEngine.DIALECT_CFML?Constants.CFML_SCRIPT_TAG_NAME:Constants.LUCEE_SCRIPT_TAG_NAME)){ // chnaged order of the condition, not sure if this is ok
page=(Page) pPage;
// move imports from script to component body
List<Statement> children = p.getBody().getStatements();
Iterator<Statement> it = children.iterator();
Statement stat;
Tag t;
while(it.hasNext()){
stat=it.next();
if(!(stat instanceof Tag)) continue;
t=(Tag) stat;
if(t.getTagLibTag().getName().equals("import")){
tag.getBody().addStatement(t);
}
}
//move to page
ASMUtil.move(tag, page);
//if(!inline)ASMUtil.replace(p, tag, false);
}
else
throw new EvaluatorException("Wrong Context, tag "+tlt.getFullName()+" can't be inside other tags, tag is inside tag "+p.getFullname());
}
//Page page=(Page) pPage;
Boolean insideCITemplate=isInsideCITemplate(page);
boolean main=isMainComponent(page,tc);
// is a full grown component or a inline component
if(insideCITemplate==Boolean.FALSE) {
throw new EvaluatorException("Wrong Context, "+tlt.getFullName()+
" tag must be inside a file with the extension "+Constants.getCFMLComponentExtension()+" or "+Constants.getLuceeComponentExtension());
}
//if(count>1)
// throw new EvaluatorException("inside one cfc file only one tag "+tlt.getFullName()+" is allowed, now we have "+count);
boolean isComponent=tlt.getTagClassDefinition().isClassNameEqualTo("lucee.runtime.tag.Component");
/*boolean isInterface="lucee.runtime.tag.Interface".equals(tlt.getTagClassName());
if(main) {
if(isComponent) page.setIsComponent(true);
else if(isInterface) page.setIsInterface(true);
}*/
tc.setMain(main);
// Attributes
// Name
String name=null;
if(!main) {
Map<String, Attribute> attrs = tag.getAttributes();
if(attrs.size()>0) {
Attribute first = attrs.values().iterator().next();
if(first.isDefaultValue()) {
name=first.getName();
}
}
if(name==null) {
Attribute attr = tag.getAttribute("name");
if(attr!=null) {
Expression expr = tag.getFactory().toExprString(attr.getValue());
if(!(expr instanceof LitString)) throw new EvaluatorException("Name of the component "+tlt.getFullName()+", must be a literal string value");
name=((LitString)expr).getString();
}
else
throw new EvaluatorException("Missing name of the component "+tlt.getFullName()+"");
}
tc.setName(name);
}
// output
// "output=true" is handled in "lucee.transformer.cfml.attributes.impl.Function"
Attribute attr = tag.getAttribute("output");
if(attr!=null) {
Expression expr = tag.getFactory().toExprBoolean(attr.getValue());
if(!(expr instanceof LitBoolean))
throw new EvaluatorException("Attribute output of the Tag "+tlt.getFullName()+", must contain a static boolean value (true or false, yes or no)");
//boolean output = ((LitBoolean)expr).getBooleanValue();
//if(!output) ASMUtil.removeLiterlChildren(tag, true);
}
// extends
attr = tag.getAttribute("extends");
if(attr!=null) {
Expression expr = tag.getFactory().toExprString(attr.getValue());
if(!(expr instanceof LitString)) throw new EvaluatorException("Attribute extends of the Tag "+tlt.getFullName()+", must contain a literal string value");
}
// implements
if(isComponent){
attr = tag.getAttribute("implements");
if(attr!=null) {
Expression expr = tag.getFactory().toExprString(attr.getValue());
if(!(expr instanceof LitString)) throw new EvaluatorException("Attribute implements of the Tag "+tlt.getFullName()+", must contain a literal string value");
}
}
// modifier
if(isComponent){
attr = tag.getAttribute("modifier");
if(attr!=null) {
Expression expr = tag.getFactory().toExprString(attr.getValue());
if(!(expr instanceof LitString)) throw new EvaluatorException("Attribute modifier of the Tag "+tlt.getFullName()+", must contain a literal string value");
LitString ls=(LitString) expr;
int mod = ComponentUtil.toModifier(ls.getString(),lucee.runtime.Component.MODIFIER_NONE,-1);
if(mod==-1) throw new EvaluatorException("Value ["+ls.getString()+"] from attribute modifier of the Tag "+tlt.getFullName()+" is invalid,valid values are [none,abstract,final]");
}
}
}
private boolean isMainComponent(Page page, TagCIObject comp) {
// first is main
Iterator<Statement> it = page.getStatements().iterator();
while(it.hasNext()){
Statement s = it.next();
if(s instanceof TagCIObject) return s == comp;
}
return false;
}
/**
* is the template ending with a component extension?
* @param page
* @return return true if so false otherwse and null if the code is not depending on a template
*/
private Boolean isInsideCITemplate(Page page) {
SourceCode sc = page.getSourceCode();
if(!(sc instanceof PageSourceCode)) return null;
PageSource psc = ((PageSourceCode)sc).getPageSource();
String src=psc.getDisplayPath();
return Constants.isComponentExtension(ResourceUtil.getExtension(src, ""));
//int pos=src.lastIndexOf(".");
//return pos!=-1 && pos<src.length() && src.substring(pos+1).equals(Constants.COMPONENT_EXTENSION);
}
}