package org.basex.query.up.expr;
import static org.basex.query.QueryText.*;
import static org.basex.query.util.Err.*;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.expr.Constr;
import org.basex.query.expr.Expr;
import org.basex.query.item.ANode;
import org.basex.query.item.DBNode;
import org.basex.query.item.Item;
import org.basex.query.item.NodeType;
import org.basex.query.iter.Iter;
import org.basex.query.iter.NodeCache;
import org.basex.query.up.primitives.InsertAfter;
import org.basex.query.up.primitives.InsertAttribute;
import org.basex.query.up.primitives.InsertBefore;
import org.basex.query.up.primitives.InsertInto;
import org.basex.query.up.primitives.InsertIntoFirst;
import org.basex.query.up.primitives.UpdatePrimitive;
import org.basex.util.InputInfo;
import org.basex.util.Util;
/**
* Insert expression.
*
* @author BaseX Team 2005-12, BSD License
* @author Lukas Kircher
*/
public final class Insert extends Update {
/** First flag. */
private final boolean first;
/** Last flag. */
private final boolean last;
/** Before flag. */
private final boolean before;
/** After flag. */
private final boolean after;
/**
* Constructor.
* @param ii input info
* @param src source expression
* @param f first flag
* @param l last
* @param b before
* @param a after
* @param trg target expression
*/
public Insert(final InputInfo ii, final Expr src, final boolean f,
final boolean l, final boolean b, final boolean a, final Expr trg) {
super(ii, trg, src);
first = f;
last = l;
before = b;
after = a;
}
@Override
public Item item(final QueryContext ctx, final InputInfo ii)
throws QueryException {
final Constr c = new Constr(ii, ctx).add(expr[1]);
final NodeCache cList = c.children;
final NodeCache aList = c.atts;
if(c.errAtt) UPNOATTRPER.thrw(input);
if(c.duplAtt != null) UPATTDUPL.thrw(input, c.duplAtt);
// check target constraints
final Iter t = ctx.iter(expr[0]);
final Item i = t.next();
if(i == null) UPSEQEMP.thrw(input, Util.name(this));
if(!(i instanceof ANode) || t.next() != null)
(before || after ? UPTRGTYP2 : UPTRGTYP).thrw(input);
final ANode n = (ANode) i;
final ANode par = n.parent();
if(before || after) {
if(n.type == NodeType.ATT || n.type == NodeType.DOC)
UPTRGTYP2.thrw(input);
if(par == null) UPPAREMPTY.thrw(input);
} else {
if(n.type != NodeType.ELM && n.type != NodeType.DOC)
UPTRGTYP.thrw(input);
}
UpdatePrimitive up;
DBNode dbn;
// no update primitive is created if node list is empty
if(aList.size() > 0) {
final ANode targ = before || after ? par : n;
if(targ.type != NodeType.ELM)
(before || after ? UPATTELM : UPATTELM2).thrw(input);
dbn = ctx.updates.determineDataRef(targ, ctx);
up = new InsertAttribute(dbn.pre, dbn.data, input,
checkNS(aList, targ, ctx));
ctx.updates.add(up, ctx);
}
// no update primitive is created if node list is empty
if(cList.size() > 0) {
dbn = ctx.updates.determineDataRef(n, ctx);
if(before) up = new InsertBefore(dbn.pre, dbn.data, input, cList);
else if(after) up = new InsertAfter(dbn.pre, dbn.data, input, cList);
else if(first) up = new InsertIntoFirst(dbn.pre, dbn.data, input, cList);
else up = new InsertInto(dbn.pre, dbn.data, input, cList, last);
ctx.updates.add(up, ctx);
}
return null;
}
@Override
public String toString() {
return INSERT + ' ' + NODE + ' ' + expr[1] + ' ' + INTO + ' ' + expr[0];
}
}