package org.basex.query.up.primitives;

import static org.basex.core.Text.*;
import static org.basex.query.util.Err.*;
import java.io.IOException;

import org.basex.data.Data;
import org.basex.io.IOFile;
import org.basex.io.out.PrintOutput;
import org.basex.io.serial.Serializer;
import org.basex.io.serial.SerializerProp;
import org.basex.query.QueryContext;
import org.basex.query.QueryException;
import org.basex.query.item.DBNode;
import org.basex.query.item.Uri;
import org.basex.util.InputInfo;
import org.basex.util.Util;

/**
 * Update primitive for the fn:put() function.
 *
 * @author BaseX Team 2005-11, BSD License
 * @author Lukas Kircher
 */
public final class Put extends UpdatePrimitive {
  /** Put location. The same node can be stored in multiple locations. */
  private Uri[] uri = new Uri[1];
  /** Serializer properties. */
  private final QueryContext ctx;

  /**
   * Constructor.
   * @param i input info
   * @param p pre
   * @param d data
   * @param u uri
   * @param context query context
   */
  public Put(final InputInfo i, final int p, final Data d, final Uri u,
      final QueryContext context) {
    super(PrimitiveType.PUT, p, d, i);
    uri[0] = u;
    ctx = context;
  }

  @Override
  public void apply() throws QueryException {
    for(int i = 0; i < uri.length; i++) {
      PrintOutput po = null;
      final DBNode node = new DBNode(data, pre);
      try {
        po = new PrintOutput(path(i));
        final SerializerProp pr = ctx.serProp(false);
        // try to reproduce non-chopped documents correctly
        pr.set(SerializerProp.S_INDENT, node.data.meta.chop ? YES : NO);
        node.serialize(Serializer.get(po, pr));
      } catch(final IOException ex) {
        UPPUTERR.thrw(input, path(i));
      } finally {
        if(po != null) try { po.close(); } catch(final IOException ex) { }
      }
    }
  }

  /**
   * Returns uri as string.
   * @param p uri position
   * @return string uri
   */
  public String path(final int p) {
    return new IOFile(uri[p].toJava()).path();
  }

  @Override
  public void merge(final UpdatePrimitive p) throws QueryException {
    final int l = uri.length;
    final Uri[] t = new Uri[l + 1];
    System.arraycopy(uri, 0, t, 0, l);
    t[l] = ((Put) p).uri[0];
    uri = t;
  }

  @Override
  public String toString() {
    return Util.name(this) + "[" + targetNode() + ", " + uri[0] + "]";
  }
}
