/**
*
* Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
*
* 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/>.
*
**/
/**
* Implements the CFML Function dump
*/
package lucee.runtime.functions.other;
import java.util.Set;
import lucee.commons.digest.HashUtil;
import lucee.commons.lang.ExceptionUtil;
import lucee.commons.lang.StringUtil;
import lucee.commons.lang.types.RefBoolean;
import lucee.commons.lang.types.RefBooleanImpl;
import lucee.runtime.ComponentImpl;
import lucee.runtime.PageContext;
import lucee.runtime.dump.DumpData;
import lucee.runtime.dump.DumpProperties;
import lucee.runtime.dump.DumpRow;
import lucee.runtime.dump.DumpTable;
import lucee.runtime.dump.DumpUtil;
import lucee.runtime.dump.SimpleDumpData;
import lucee.runtime.ext.function.Function;
import lucee.runtime.functions.string.Len;
import lucee.runtime.op.Caster;
import lucee.runtime.op.Decision;
import lucee.runtime.type.Collection;
import lucee.runtime.type.Collection.Key;
import lucee.runtime.type.KeyImpl;
import lucee.runtime.type.Query;
import lucee.runtime.type.QueryImpl;
import lucee.runtime.type.Struct;
import lucee.runtime.type.StructImpl;
import lucee.runtime.type.scope.Scope;
import lucee.runtime.type.util.KeyConstants;
import lucee.runtime.type.util.ListUtil;
import lucee.runtime.type.util.StructUtil;
public final class DumpStruct implements Function {
public static Struct call(PageContext pc , Object object) {
return call(pc, object,9999,null,null,9999,true);
}
public static Struct call(PageContext pc , Object object, double maxLevel) {
return call(pc, object,maxLevel,null,null,9999,true,true,null);
}
public static Struct call(PageContext pc , Object object, double maxLevel, String show) {
return call(pc, object,maxLevel,show,null,9999,true,true,null);
}
public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide) {
return call(pc,object,maxLevel,show,hide,9999,true,true,null);
}
public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide,double keys) {
return call(pc , object, maxLevel, show, hide,keys,true,true,null);
}
public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide,double keys,boolean metainfo) {
return call(pc , object, maxLevel, show, hide,keys,metainfo,true,null);
}
public static Struct call(PageContext pc , Object object, double maxLevel, String show, String hide,double keys,boolean metainfo, boolean showUDFs) {
return call(pc , object, maxLevel, show, hide,keys,metainfo,showUDFs,null);
}
public static Struct call(PageContext pc,Object object,double maxLevel, String show, String hide,double keys,boolean metainfo, boolean showUDFs, String label) {
if(show!=null && "all".equalsIgnoreCase(show.trim()))show=null;
if(hide!=null && "all".equalsIgnoreCase(hide.trim()))hide=null;
Set<String> setShow=(show!=null)?ListUtil.listToSet(show.toLowerCase(),",",true):null;
Set<String> setHide=(hide!=null)?ListUtil.listToSet(hide.toLowerCase(),",",true):null;
DumpProperties properties=new DumpProperties((int)maxLevel,setShow,setHide,(int)keys,metainfo,showUDFs);
DumpData dd = DumpUtil.toDumpData(object, pc,(int)maxLevel,properties);
if(!StringUtil.isEmpty(label)) {
DumpTable table=new DumpTable("#ffffff","#cccccc","#000000");
table.appendRow(1,new SimpleDumpData(label));
table.appendRow(0,dd);
dd=table;
}
RefBoolean hasReference=new RefBooleanImpl(false);
Struct sct = toStruct(dd,object,hasReference);
sct.setEL("hasReference", hasReference.toBoolean());
addMetaData(sct, object);
return sct;
}
private static void addMetaData(Struct sct, Object o) {
String simpleType = "unknown"; // simpleType will replace colorId and colors
String simpleValue = "";
try {
if (o == null) {
simpleType = "null";
}
else if (o instanceof Scope) {
simpleType = "struct";
simpleValue = "Scope (" + getSize(o) + ")";
}
else if (Decision.isStruct(o)) {
simpleType = "struct";
simpleValue = "Struct (" + getSize(o) + ")";
}
else if (Decision.isArray(o)) {
simpleType = "array";
simpleValue = "Array (" + getSize(o) + ")";
}
else if (Decision.isQuery(o)) {
simpleType = "query";
simpleValue = "Query (" + getSize(o) + ")";
}
else if (Decision.isComponent(o)) {
simpleType = "component";
simpleValue = "Component: " + ((ComponentImpl)o).getDisplayName();
}
else if (Decision.isFunction(o) || Decision.isUserDefinedFunction(o) || Decision.isClosure(o)) {
simpleType = "function";
// simpleValue = "Function: " + ((Function)o).(); // TODO: add signature
}
else if (Decision.isDate(o, false)) {
simpleType = "date";
simpleValue = o.toString();
}
else if (Decision.isBoolean(o, false)) {
simpleType = "boolean";
simpleValue = o.toString();
}
else if (Decision.isInteger(o, false)) {
simpleType = "numeric";
simpleValue = Caster.toInteger(o).toString();
}
else if (Decision.isNumber(o, false)) {
simpleType = "numeric";
simpleValue = o.toString();
}
else if (Decision.isSimpleValue(o)) {
simpleType = "string";
simpleValue = Caster.toString(o);
if (simpleValue.length() > 64)
simpleValue = "String (" + simpleValue.length() + ")";
}
else {
simpleType = o.getClass().getSimpleName().toLowerCase();
}
}
catch(Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
simpleValue = "{error}";
}
sct.setEL("simpleType", simpleType);
sct.setEL("simpleValue", simpleValue);
}
private static String getSize(Object o) {
return Caster.toInteger( Len.invoke(o, 0) ).toString();
}
private static Struct toStruct(DumpData dd, Object object, RefBoolean hasReference) {
DumpTable table;
if(dd instanceof DumpTable) table=(DumpTable) dd;
else {
if(dd==null) dd= new SimpleDumpData("null");
table=new DumpTable("#ffffff","#cccccc","#000000");
table.appendRow(1,dd);
}
return toCFML(table,object,hasReference,null);
}
private static Object toCFML(DumpData dd, Object object, RefBoolean hasReference, Struct colors) {
if(dd instanceof DumpTable)return toCFML((DumpTable) dd,object,hasReference,colors);
if(dd==null) return new SimpleDumpData("null");
return dd.toString();
}
private static Struct toCFML(DumpTable dt, Object object, RefBoolean hasReference, Struct colors) {
Struct sct=new StructImpl();
if(colors==null) {
colors=new StructImpl();
sct.setEL("colors", colors);
}
Collection.Key type;
if(dt.getType()!=null) type=KeyImpl.init(dt.getType());
else if(object!=null) type=KeyImpl.init(object.getClass().getName());
else type=KeyConstants._null;
// colors
String borderColor = toShortColor(dt.getBorderColor());
String fontColor = toShortColor(dt.getFontColor());
String highLightColor = toShortColor(dt.getHighLightColor());
String normalColor = toShortColor(dt.getNormalColor());
// create color id
Key colorId = KeyImpl.init(Long.toString(HashUtil.create64BitHash(new StringBuilder(borderColor)
.append(':').append(fontColor)
.append(':').append(highLightColor)
.append(':').append(normalColor)),Character.MAX_RADIX));
if(!colors.containsKey(colorId)) {
Struct color=new StructImpl();
StructUtil.setELIgnoreWhenNull(color,"borderColor", borderColor);
StructUtil.setELIgnoreWhenNull(color,"fontColor", fontColor);
StructUtil.setELIgnoreWhenNull(color,"highLightColor", highLightColor);
StructUtil.setELIgnoreWhenNull(color,"normalColor", normalColor);
colors.setEL(colorId, color);
}
/*StructUtil.setELIgnoreWhenNull(sct,"borderColor", borderColor);
StructUtil.setELIgnoreWhenNull(sct,"fontColor", fontColor);
StructUtil.setELIgnoreWhenNull(sct,"highLightColor", highLightColor);
StructUtil.setELIgnoreWhenNull(sct,"normalColor", normalColor);
*/
StructUtil.setELIgnoreWhenNull(sct,"colorId", colorId.getString());
StructUtil.setELIgnoreWhenNull(sct,KeyConstants._comment, dt.getComment());
StructUtil.setELIgnoreWhenNull(sct,KeyConstants._height, dt.getHeight());
StructUtil.setELIgnoreWhenNull(sct,KeyConstants._width, dt.getWidth());
StructUtil.setELIgnoreWhenNull(sct,KeyConstants._title, dt.getTitle());
sct.setEL(KeyConstants._type, type.getString());
if(!StringUtil.isEmpty(dt.getId()))sct.setEL(KeyConstants._id, dt.getId());
if("ref".equals(dt.getType())){
hasReference.setValue(true);
sct.setEL(KeyConstants._ref, dt.getRef());
}
DumpRow[] drs = dt.getRows();
DumpRow dr;
Query qry=null;
DumpData[] items;
for(int r=0;r<drs.length;r++){
dr=drs[r];
items = dr.getItems();
if(qry==null)qry=new QueryImpl(toColumns(items),drs.length,"data");
for(int c=1;c<=items.length;c++){
qry.setAtEL("data"+c, r+1, toCFML(items[c-1],object,hasReference,colors));
}
qry.setAtEL("highlight", r+1, new Double(dr.getHighlightType()));
}
if(qry!=null)sct.setEL(KeyConstants._data, qry);
return sct;
}
private static String[] toColumns(DumpData[] items) {
String[] columns=new String[items.length+1];
columns[0]="highlight";
for(int i=1;i<columns.length;i++){
columns[i]="data"+i;
}
return columns;
}
/*public static String getContext() {
//Throwable cause = t.getCause();
StackTraceElement[] traces = Thread.currentThread().getStackTrace();
int line=0;
String template;
StackTraceElement trace=null;
for(int i=0;i<traces.length;i++) {
trace=traces[i];
template=trace.getFileName();
if((line=trace.getLineNumber())<=0 || template==null || ResourceUtil.getExtension(template,"").equals("java")) continue;
return template+":"+line;
}
return null;
}*/
private static String toShortColor(String color) {
if(color!=null && color.length()==7 && color.startsWith("#")) {
if(color.charAt(1)==color.charAt(2) && color.charAt(3)==color.charAt(4) && color.charAt(5)==color.charAt(6))
return "#"+color.charAt(1)+color.charAt(3)+color.charAt(5);
}
return color;
}
}