package org.xmlsh.types.xtypes;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.xmlsh.core.InvalidArgumentException;
import org.xmlsh.core.XValue;
import org.xmlsh.sh.shell.SerializeOpts;
import org.xmlsh.sh.shell.ShellConstants;
import org.xmlsh.types.TypeFamily;
import org.xmlsh.util.Util;
/*
* A "Sequence" of XValues which is analogous to an XdmValue which is 0 or more XdmItems
* Sequences are "flat" that is if other sequences are added to them as children the the children are added instead
*
* Since an XValue is a sequence itself then
* only lists of > 1 XValues need be implemented
*/
public class XValueSequence implements Iterable<XValue> , IXValueSequence<XValueSequence>
{
private List<XValue> mList;
public XValueSequence( XValue... values ){
mList = new ArrayList<XValue>();
for(XValue v : values )
addValue(v);
}
public XValueSequence( Collection<XValue> values ){
// Flatten sequence - dont let them stack
mList = new ArrayList<XValue>();
for( XValue v : values ) {
addValue(v);
}
}
public static IXValueSequence<XValueSequence> emptySequence() {
return new XValueSequence();
}
/* (non-Javadoc)
* @see org.xmlsh.core.IXValueSequence#addValue(org.xmlsh.core.XValue)
*/
@Override
public void addValue(XValue v)
{
for( XValue v2 : v ) {
assert( ! (v2.asObject() instanceof XValueSequence ));
mList.add( v2 );
}
}
XValueSequence( XValueSequence that ){
mList = new ArrayList<XValue>( that.mList );
}
@Override
public Iterator<XValue> iterator()
{
return mList.iterator();
}
@Override
public int size()
{
return mList.size();
}
@Override
public boolean isAtomic()
{
return mList.size() == 1 && mList.get(0).isAtomic() ;
}
@Override
public boolean isEmpty()
{
return mList.isEmpty();
}
@Override
public boolean isMap()
{
// TODO Auto-generated method stub
return false;
}
@Override
public boolean isList()
{
return true;
}
/* (non-Javadoc)
* @see org.xmlsh.core.IXValueSequence#getAt(int)
*/
@Override
public XValue getAt(int index)
{
if( index < 0 || index >= size() )
return null ;
return mList.get(index);
}
@Override
public void removeAll()
{
throw new UnsupportedOperationException("removeAll is not implemented for XValueSequence");
}
@Override
public Collection<XValue> values()
{
return Collections.unmodifiableCollection(mList);
}
@Override
public void serialize(OutputStream out, SerializeOpts opts) throws IOException, InvalidArgumentException
{
// @TODO - serialization needs an overhaul
if( isEmpty() )
return ;
try ( OutputStreamWriter ps = new OutputStreamWriter(out, opts.getInputTextEncoding() ) ){
String sep = "";
for( XValue value : mList ) {
ps.write( sep );
ps.flush();
value.serialize(out, opts);
sep = ",";
}
}
}
@Override
public XValue append(XValue item) throws InvalidArgumentException
{
IXValueSequence<?> s = new XValueSequence(this);
s.addValue(item);
return XValue.newXValue( TypeFamily.XTYPE , s );
}
/* (non-Javadoc)
* @see org.xmlsh.core.IXValueSequence#setAt(int, org.xmlsh.core.XValue)
*/
@Override
public XValue setAt(int index, XValue value)
{
throw new UnsupportedOperationException("setAt is not implemented for XValueSequence");
}
@Override
public String toString() {
// TODO: Shouldnt be called !
if( mList.isEmpty() )
return "";
if( mList.size() == 1 )
return mList.get(0).toString();
return Util.joinValues(mList,ShellConstants.ARG_SEPARATOR );
}
@Override
public XValue asXValue() throws InvalidArgumentException
{
return XValue.newXValue( TypeFamily.XTYPE , this );
}
@Override
public boolean isContainer()
{
return true;
}
@Override
public boolean isSequence()
{
return true;
}
@Override
public IXValueContainer asXContainer()
{
return this;
}
@Override
public IXValueMap asXMap()
{
return null;
}
@Override
public IXValueList asXList()
{
return new XValueList(mList);
}
@Override
public IXValueSequence<? extends IXValueSequence<?>> asXSequence()
{
return this;
}
@Override
public IXValueSequence subSequence(int begin)
{
return new XValueSequence( mList.subList(begin, mList.size() ));
}
}