package org.xmlsh.types;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.xmlsh.core.CoreException;
import org.xmlsh.core.InvalidArgumentException;
import org.xmlsh.core.XValue;
import org.xmlsh.sh.shell.SerializeOpts;
import org.xmlsh.types.xtypes.IXValue;
import org.xmlsh.types.xtypes.IXValueContainer;
import org.xmlsh.types.xtypes.IXValueList;
import org.xmlsh.types.xtypes.IXValueMap;
import org.xmlsh.types.xtypes.XValueList;
import org.xmlsh.util.JavaUtils;
import org.xmlsh.util.Util;
public class XTypeFamily extends AbstractTypeFamily implements ITypeFamily
{
private static final XTypeFamily _instance = new XTypeFamily();
private static final Object _nullValue = null;
static Logger mLogger = LogManager.getLogger();
@Override
public boolean isClassOfFamily(Class<?> cls)
{
return XValue.class.isAssignableFrom(cls) || IXValue.class.isAssignableFrom(cls);
}
@Override
public boolean isInstanceOfFamily(Object obj)
{
if( obj == null )
return true ; // OK for null objects
return obj instanceof XValue || obj instanceof IXValue;
}
@Override
public TypeFamily typeFamily()
{
return TypeFamily.XTYPE;
}
@Override
public XValue append(Object value, XValue v) throws InvalidArgumentException
{
return asXType(value).append(v);
}
@Override
public String asString(Object value)
{
if( value == null )
return "";
return value.toString();
}
@Override
public int getSize(Object obj) throws InvalidArgumentException
{
IXValue ic = asXType(obj);
assert( obj != null );
if( obj == null )
return 0;
return ic.isContainer() ? ic.asXContainer().size() :
0;
}
// Named index access
@Override
public XValue getXValue(Object obj, String ind) throws InvalidArgumentException
{
if(obj == null)
return nullXValue();
IXValue ic = asXType(obj);
if(Util.isBlank(ind))
return XValue.newXValue( this , obj , false );
// map first
if( ic.isMap() )
return ic.asXMap().get(ind);
if( ic.isList() )
return ic.asXList().get(Util.parseInt(ind, 1)-1);
return nullXValue() ;
}
@Override
public XValue getXValue(Object obj, int index) throws CoreException
{
IXValue ic = asXType(obj);
if(ic.isList())
return ic.asXList().getAt(index);
throw new InvalidArgumentException("Not an indexable type: " + describeClass(obj));
}
@Override
public void serialize(Object obj, OutputStream out, SerializeOpts opts) throws IOException,
InvalidArgumentException
{
if(obj == null)
return;
IXValue ic = asXType(obj);
ic.serialize(out, opts);
}
@Override
public String typeName(Object obj)
{
if( obj == null )
return "null";
return JavaUtils.getClassName(obj);
}
@Override
public boolean isEmpty(Object obj)
{
if(obj == null)
return true;
IXValue ic;
try {
ic = asXType(obj);
return ic.isEmpty();
} catch (InvalidArgumentException e) {
throw new IllegalArgumentException(e);
}
}
@Override
public XValue setXValue(XValue xobj, String ind, XValue value) throws CoreException
{
assert (xobj != null && !xobj.isNull());
if(xobj == null || xobj.isNull())
throw new CoreException("Cannot set indexed value to null object");
IXValue ic = asXType(xobj.asObject());
Object o = null;
// map first
if( ic.isMap() ){
IXValueMap map = ic.asXMap();
map.put(ind,value);
if( map != ic )
xobj = map.asXValue();
}
else
if( ic.isList() ) {
IXValueList list = ic.asXList();
list.setAt(Util.parseInt(ind, 0),value);
if( ic != list )
xobj = list.asXValue();
}
else
throw new CoreException("Cannot set non-indexed object");
return xobj ;
}
@Override
public List<XValue> getXValues(Object obj) throws InvalidArgumentException
{
if(obj == null)
return Collections.emptyList();
if((obj instanceof IXValueContainer)) {
if(obj instanceof IXValueList)
return ((IXValueList) obj).asList();
XValueList list = new XValueList();
list.addAll(((IXValueContainer) obj).values());
return list;
}
else if((obj instanceof XValue))
return Collections.singletonList((XValue) obj);
else return Collections.singletonList(XValue.newXValue(null, obj)); // may conatain any type - SNH
}
@Override
public XValue getXValue(Object obj) throws InvalidArgumentException
{
if(obj instanceof XValue)
return (XValue) obj;
if( isInstanceOfFamily( obj ) )
return XValue.newXValue( this , obj , false );
return XValue.newXValue(obj);
}
@Override
public boolean isAtomic(Object obj)
{
if((obj instanceof IXValue)) {
return ((IXValue) obj).isAtomic();
}
mLogger.warn("Unexpected type:{} " , describeClass(obj));
return false;
}
@Override
public XValue setXValue(XValue xobj, int index, XValue value) throws CoreException
{
assert (xobj != null && !xobj.isNull());
IXValue ic = asXType(xobj.asObject());
if(xobj == null || xobj.isNull())
throw new CoreException("Cannot set indexed value to null object");
if( ic.isList() ) {
IXValueList list = ic.asXList();
list.setAt(index,value);
if( ic != list )
xobj = list.asXValue();
}
else
if( ic.isMap() ){
IXValueMap map = ic.asXMap();
map.put(String.valueOf(index),value);
if( map != ic )
xobj = map.asXValue();
}
else
throw new CoreException("Cannot set non indexed value");
return xobj;
}
protected static IXValue asXType(Object obj) throws InvalidArgumentException
{
if((obj instanceof IXValue)) {
return ((IXValue) obj);
}
throw new InvalidArgumentException("Unexpected type: " + describeClass(obj));
}
@Override
public Object nullValue()
{
return _nullValue;
}
@Override
public XValue nullXValue()
{
try {
return XValue.newXValue(this , _nullValue, false );
} catch (InvalidArgumentException e) {
throw new IllegalArgumentException(e);
}
}
public static XTypeFamily getInstance()
{
return _instance;
}
@Override
public boolean hasKey(Object obj, String key) {
if( obj instanceof IXValueContainer ){
IXValueMap c = (IXValueMap) obj ;
return c.containsKey(key);
}
return false;
}
@Override
public boolean isContainer(Object obj) {
return obj instanceof IXValueContainer ;
}
}