package railo.runtime.type.scope;
import java.io.UnsupportedEncodingException;
import railo.commons.lang.StringList;
import railo.commons.lang.StringUtil;
import railo.commons.net.URLDecoder;
import railo.commons.net.URLItem;
import railo.runtime.PageContext;
import railo.runtime.dump.DumpData;
import railo.runtime.dump.DumpProperties;
import railo.runtime.exp.ExpressionException;
import railo.runtime.op.Caster;
import railo.runtime.security.ScriptProtect;
import railo.runtime.type.Array;
import railo.runtime.type.ArrayImpl;
import railo.runtime.type.CastableStruct;
import railo.runtime.type.Collection;
import railo.runtime.type.KeyImpl;
import railo.runtime.type.Sizeable;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.util.ListUtil;
import railo.runtime.type.util.StructUtil;
/**
* Simple standart implementation of a Scope, for standart use.
*/
public abstract class ScopeSupport extends StructImpl implements Scope,Sizeable {
private static final long serialVersionUID = -4185219623238374574L;
private String name;
private String dspName;
private static int _id=0;
private int id=0;
private static final byte[] EMPTY="".getBytes();
/**
* Field <code>isInit</code>
*/
protected boolean isInit;
private int type;
/**
* constructor for the Simple class
* @param name name of the scope
* @param type scope type (SCOPE_APPLICATION,SCOPE_COOKIE use)
*/
public ScopeSupport(boolean sync,String name, int type) {
super(sync?StructImpl.TYPE_SYNC:StructImpl.TYPE_REGULAR);
this.name=name;
this.type=type;
id=++_id;
}
/**
* constructor for ScopeSupport
* @param name name of the scope
* @param type scope type (SCOPE_APPLICATION,SCOPE_COOKIE use)
* @param doubleLinked mean that the struct has predictable iteration order this make the input order fix
*/
public ScopeSupport(String name, int type, int mapType) {
super(mapType);
this.name=name;
this.type=type;
id=++_id;
}
@Override
public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
return toDumpData(pageContext, maxlevel, dp, this, dspName);
}
public static DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp, Struct sct,String dspName) {
if(StringUtil.isEmpty(dspName))dspName="Scope";
return StructUtil.toDumpTable(sct, dspName, pageContext, maxlevel, dp);
}
protected ExpressionException invalidKey(String key) {
return new ExpressionException("variable ["+key+"] doesn't exist in "+StringUtil.ucFirst(name)+" Scope (keys:"+ListUtil.arrayToList(keys(), ",")+")");
}
/**
* write parameter defined in a query string (name1=value1&name2=value2) to the scope
* @param qs Query String
* @return parsed name value pair
*/
protected static URLItem[] setFromQueryString(String str) {
return setFrom___(str, '&');
}
protected static URLItem[] setFromTextPlain(String str) {
return setFrom___(str, '\n');
}
protected static URLItem[] setFrom___(String tp,char delimiter) {
if(tp==null) return new URLItem[0];
Array arr=ListUtil.listToArrayRemoveEmpty(tp,delimiter);
URLItem[] pairs=new URLItem[arr.size()];
//Array item;
int index;
String name;
for(int i=1;i<=pairs.length;i++) {
name=Caster.toString(arr.get(i,""),"");
//if(name.length()==0) continue;
index=name.indexOf('=');
if(index!=-1) pairs[i-1]=new URLItem(name.substring(0,index),name.substring(index+1),true);
else pairs[i-1]=new URLItem(name,"",true);
}
return pairs;
}
protected static byte[] getBytes(String str) {
return str.getBytes();
}
protected static byte[] getBytes(String str,String encoding) {
try {
return str.getBytes(encoding);
} catch (UnsupportedEncodingException e) {
return EMPTY;
}
}
protected void fillDecodedEL(URLItem[] raw, String encoding, boolean scriptProteced, boolean sameAsArray) {
try {
fillDecoded(raw, encoding,scriptProteced,sameAsArray);
} catch (UnsupportedEncodingException e) {
try {
fillDecoded(raw, "iso-8859-1",scriptProteced,sameAsArray);
} catch (UnsupportedEncodingException e1) {}
}
}
/**
* fill th data from given strut and decode it
* @param raw
* @param encoding
* @throws UnsupportedEncodingException
*/
protected void fillDecoded(URLItem[] raw, String encoding, boolean scriptProteced, boolean sameAsArray) throws UnsupportedEncodingException {
clear();
String name,value;
//Object curr;
for(int i=0;i<raw.length;i++) {
name=raw[i].getName();
value=raw[i].getValue();
if(raw[i].isUrlEncoded()) {
name=URLDecoder.decode(name,encoding,true);
value=URLDecoder.decode(value,encoding,true);
}
// MUST valueStruct
if(name.indexOf('.')!=-1) {
StringList list=ListUtil.listToStringListRemoveEmpty(name,'.');
Struct parent=this;
while(list.hasNextNext()) {
parent=_fill(parent,list.next(),new CastableStruct(),false,scriptProteced,sameAsArray);
}
_fill(parent,list.next(),value,true,scriptProteced,sameAsArray);
}
//else
_fill(this,name,value,true,scriptProteced,sameAsArray);
}
}
private Struct _fill(Struct parent, String name, Object value, boolean isLast, boolean scriptProteced, boolean sameAsArray) {
Object curr;
boolean isArrayDef=sameAsArray;
Collection.Key key=KeyImpl.init(name);
// script protect
if(scriptProteced && value instanceof String) {
value=ScriptProtect.translate((String)value);
}
if(name.length() >2 && name.endsWith("[]")) {
isArrayDef=true;
name=name.substring(0,name.length()-2);
key=KeyImpl.getInstance(name);
curr=parent.get(key,null);
}
else {
curr=parent.get(key,null);
}
if(curr==null) {
if(isArrayDef) {
Array arr = new ArrayImpl();
arr.appendEL(value);
parent.setEL(key,arr);
}
else parent.setEL(key,value);
}
else if(curr instanceof Array){
((Array) curr).appendEL(value);
}
else if(curr instanceof CastableStruct){
if(isLast) ((CastableStruct)curr).setValue(value);
else return (Struct) curr;
}
else if(curr instanceof Struct){
if(isLast) parent.setEL(key,value);
else return (Struct) curr;
}
else if(curr instanceof String){
if(isArrayDef) {
Array arr = new ArrayImpl();
arr.appendEL(curr);
arr.appendEL(value);
parent.setEL(key,arr);
}
else if(value instanceof Struct) {
parent.setEL(key,value);
}
else {
if(!StringUtil.isEmpty(value)) {
String existing=Caster.toString(curr,"");
if(StringUtil.isEmpty(existing))
parent.setEL(key,value);
else
parent.setEL(key,Caster.toString(curr,"")+','+value);
}
}
}
if(!isLast) {
return (Struct)value;
}
return null;
}
/*
private String decode(Object value,String encoding) throws UnsupportedEncodingException {
return URLDecoder.decode(new String(Caster.toString(value,"").getBytes("ISO-8859-1"),encoding),encoding);
}*/
@Override
public boolean isInitalized() {
return isInit;
}
@Override
public void initialize(PageContext pc) {
isInit=true;
}
@Override
public void release() {
clear();
isInit=false;
}
@Override
public void release(PageContext pc) {
clear();
isInit=false;
}
/**
* @return Returns the id.
*/
public int _getId() {
return id;
}
/**
* display name for dump
* @param dspName
*/
protected void setDisplayName(String dspName) {
this.dspName=dspName;
}
@Override
public int getType() {
return type;
}
@Override
public String getTypeAsString() {
return name;
}
public long sizeOf() {
return StructUtil.sizeOf(this);
}
}