package org.basex.query.up.primitives;

import static org.basex.query.util.Err.*;

import org.basex.data.Data;
import org.basex.data.MemData;
import org.basex.query.QueryException;
import org.basex.util.InputInfo;
import org.basex.util.Util;

/**
 * Replace element content primitive.
 *
 * @author BaseX Team 2005-11, BSD License
 * @author Lukas Kircher
 */
public final class ReplaceElementContent extends StructuralUpdate {
  /** New value. */
  private final byte[] value;

  /**
   * Constructor.
   * @param p pre
   * @param d data
   * @param i input info
   * @param val new value
   */
  public ReplaceElementContent(final int p, final Data d, final InputInfo i,
      final byte[] val) {
    super(PrimitiveType.REPLACEELEMCONT, p, d, i);
    value = val;
  }

  @Override
  public void apply() {
    /*
     * Kind is hard coded because the target of a replace element content
     * expression can only be an element node.
     */
    final int kind = Data.ELEM;
    final int loc = pre + data.attSize(pre, kind);

    /*
     * Attributes are not affected by this expression.
     *
     * As a result of this expression all child nodes are deleted and replaced
     * by either a single text node or no node at all (depends on wheter the
     * replacing value is an empty string or not).
     */
    shifts = data.size(pre, kind) - data.attSize(pre, kind) - 1 +
      value.length == 0 ? 0 : 1;

    if(pre + data.size(pre, kind) == loc + 1 &&
        data.kind(loc) == Data.TEXT) {
      // overwrite existing text node
      data.update(loc, Data.TEXT, value);
    } else {
      while(pre + data.size(pre, kind) > loc) data.delete(loc);
      if(value.length > 0) {
        final MemData md = new MemData(data);
        md.text(0, loc - pre, value, Data.TEXT);
        md.insert(0);
        data.insert(loc, pre, md);
      }
    }
  }

  @Override
  public void merge(final UpdatePrimitive p) throws QueryException {
    UPMULTREPV.thrw(input, targetNode());
  }

  @Override
  public boolean adjacentTexts(final int c) {
    return false;
  }

  @Override
  public String toString() {
    return Util.info("%[%, %]", Util.name(this), targetNode(), value);
  }
}
