/* ************************************************************************
#
# DivConq
#
# http://divconq.com/
#
# Copyright:
# Copyright 2014 eTimeline, LLC. All rights reserved.
#
# License:
# See the license.txt file in the project's top-level directory for details.
#
# Authors:
# * Andy White
#
************************************************************************ */
package divconq.struct.scalar;
import java.text.DecimalFormat;
import org.joda.time.format.DateTimeFormat;
import divconq.lang.op.OperationContext;
import divconq.schema.DataType;
import divconq.schema.RootType;
import divconq.script.StackEntry;
import divconq.struct.ScalarStruct;
import divconq.struct.Struct;
import divconq.util.StringUtil;
import divconq.xml.XElement;
public class StringStruct extends ScalarStruct {
protected String value = null;
@Override
public DataType getType() {
if (this.explicitType != null)
return super.getType();
return OperationContext.get().getSchema().getType("String");
}
public StringStruct() {
}
public StringStruct(Object v) {
this.adaptValue(v);
}
@Override
public Object getGenericValue() {
return this.value;
}
@Override
public void adaptValue(Object v) {
this.value = Struct.objectToString(v);
}
public String getValue() {
return this.value;
}
public void setValue(String v) {
this.value = v;
}
@Override
public boolean isEmpty() {
return StringUtil.isEmpty(this.value);
}
@Override
public boolean isNull() {
return (this.value == null);
}
@Override
public void operation(StackEntry stack, XElement code) {
if ("Lower".equals(code.getName())) {
if (StringUtil.isNotEmpty(this.value))
this.value = this.value.toLowerCase();
stack.resume();
return;
}
else if ("Upper".equals(code.getName())) {
if (StringUtil.isNotEmpty(this.value))
this.value = this.value.toUpperCase();
stack.resume();
return;
}
else if ("Set".equals(code.getName())) {
Struct sref = code.hasAttribute("Value")
? stack.refFromElement(code, "Value")
: stack.resolveValue(code.getText());
this.adaptValue(sref);
stack.resume();
return;
}
else if ("Format".equals(code.getName())) {
Struct sref = code.hasAttribute("Value")
? stack.refFromElement(code, "Value")
: stack.resolveValue(code.getText());
String pat = stack.stringFromElement(code, "Pattern");
try {
if (sref instanceof DateTimeStruct)
this.value = DateTimeFormat.forPattern(pat).print(((DateTimeStruct)sref).getValue());
else if (sref instanceof DateStruct)
this.value = DateTimeFormat.forPattern(pat).print(((DateStruct)sref).getValue());
else if (sref instanceof TimeStruct)
this.value = DateTimeFormat.forPattern(pat).print(((TimeStruct)sref).getValue());
else if (sref instanceof DecimalStruct)
this.value = new DecimalFormat(pat).format(((DecimalStruct)sref).getValue());
else if (sref instanceof IntegerStruct || sref instanceof BigIntegerStruct)
this.value = String.format(pat, ((ScalarStruct)sref).getGenericValue());
}
catch (Exception x) {
OperationContext.get().error("Error doing " + code.getName() + ": " + x);
}
stack.resume();
return;
}
else if ("Append".equals(code.getName())) {
String me = (this.value == null) ? "" : this.value;
String it = "";
Struct sref = code.hasAttribute("Value")
? stack.refFromElement(code, "Value")
: stack.resolveValue(code.getText());
String its = Struct.objectToString(sref);
if (its != null)
it = its;
this.value = me + it;
stack.resume();
return;
}
else if ("Replace".equals(code.getName())) {
if (StringUtil.isNotEmpty(this.value)) {
String from = stack.stringFromElement(code, "Old");
String to = stack.stringFromElement(code, "New");
String pattern = stack.stringFromElement(code, "Pattern");
if (StringUtil.isEmpty(pattern))
this.value = this.value.replace(from, to);
else
this.value = this.value.replaceAll(pattern, to);
}
stack.resume();
return;
}
else if ("Substring".equals(code.getName())) {
if (StringUtil.isNotEmpty(this.value)) {
int from = (int) stack.intFromElement(code, "From", 0);
int to = (int) stack.intFromElement(code, "To", 0);
int length = (int) stack.intFromElement(code, "Length", 0);
if (to > 0)
this.value = this.value.substring(from, to);
else if (length > 0)
this.value = this.value.substring(from, from + length);
else
this.value = this.value.substring(from);
}
stack.resume();
return;
}
else if ("FillCode".equals(code.getName())) {
int length = (int) stack.intFromElement(code, "Length", 12);
this.value = StringUtil.buildSecurityCode(length);
stack.resume();
return;
}
else if ("Trim".equals(code.getName())) {
if (StringUtil.isNotEmpty(this.value))
this.value = StringUtil.stripWhitespace(this.value.trim());
stack.resume();
return;
}
else if ("TrimStart".equals(code.getName())) {
if (StringUtil.isNotEmpty(this.value))
this.value = StringUtil.stripLeadingWhitespace(this.value);
stack.resume();
return;
}
else if ("TrimEnd".equals(code.getName())) {
if (StringUtil.isNotEmpty(this.value))
this.value = StringUtil.stripTrailingWhitespace(this.value);
stack.resume();
return;
}
else if ("LeftPad".equals(code.getName())) {
if (StringUtil.isEmpty(this.value))
this.value = "";
int size = (int) stack.intFromElement(code, "Size", 1);
String ch = code.hasAttribute("With") ? stack.stringFromElement(code, "With") : " ";
this.value = StringUtil.leftPad(this.value, size, ch);
stack.resume();
return;
}
else if ("RightPad".equals(code.getName())) {
if (StringUtil.isEmpty(this.value))
this.value = "";
int size = (int) stack.intFromElement(code, "Size", 1);
String ch = code.hasAttribute("With") ? stack.stringFromElement(code, "With") : " ";
this.value = StringUtil.rightPad(this.value, size, ch);
stack.resume();
return;
}
/*
// TODO also implement
* <Join List="$var" With="delim" />
// <Piece Delim="str" Index="num" />
// <Align Size="num" Pad="left|right" PadChar="c" />
*/
super.operation(stack, code);
}
@Override
protected void doCopy(Struct n) {
super.doCopy(n);
StringStruct nn = (StringStruct)n;
nn.value = this.value;
}
@Override
public Struct deepCopy() {
StringStruct cp = new StringStruct();
this.doCopy(cp);
return cp;
}
@Override
public boolean equals(Object obj) {
return (StringStruct.comparison(this, obj) == 0);
}
@Override
public int compare(Object y) {
return StringStruct.comparison(this, y);
}
@Override
public int hashCode() {
return (this.value == null) ? 0 : this.value.hashCode();
}
@Override
public String toString() {
return (this.value == null) ? "null" : this.value.toString();
}
@Override
public Object toInternalValue(RootType t) {
return this.value;
}
public static int comparison(Object x, Object y)
{
String xv = Struct.objectToString(x);
String yv = Struct.objectToString(y);
if ((yv == null) && (xv == null))
return 0;
if (yv == null)
return 1;
if (xv == null)
return -1;
return xv.compareTo(yv);
}
@Override
public boolean checkLogic(StackEntry stack, XElement source) {
boolean isok = true;
boolean condFound = false;
if (this.value != null) {
boolean caseinsensitive = stack.boolFromElement(source, "CaseInsensitive", false);
if (!condFound && source.hasAttribute("Contains")) {
String other = stack.stringFromElement(source, "Contains");
isok = caseinsensitive ? this.value.toLowerCase().contains(other.toLowerCase()) : this.value.contains(other);
condFound = true;
}
if (!condFound && source.hasAttribute("StartsWith")) {
String other = stack.stringFromElement(source, "StartsWith");
isok = caseinsensitive ? this.value.toLowerCase().startsWith(other.toLowerCase()) : this.value.startsWith(other);
condFound = true;
}
if (!condFound && source.hasAttribute("EndsWith")) {
String other = stack.stringFromElement(source, "EndsWith");
isok = caseinsensitive ? this.value.toLowerCase().endsWith(other.toLowerCase()) : this.value.endsWith(other);
condFound = true;
}
}
if (!condFound)
isok = Struct.objectToBooleanOrFalse(this.value);
return isok;
}
}