package com.neverwinterdp.registry.zk;

import java.util.List;

import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.OpResult;

import com.neverwinterdp.registry.Node;
import com.neverwinterdp.registry.NodeCreateMode;
import com.neverwinterdp.registry.PathFilter;
import com.neverwinterdp.registry.RegistryException;
import com.neverwinterdp.registry.Transaction;
import com.neverwinterdp.util.JSONSerializer;

public class TransactionImpl implements Transaction {
  private RegistryImpl registry;
  private org.apache.zookeeper.Transaction zkTransaction ;
  
  public TransactionImpl(RegistryImpl registry, org.apache.zookeeper.Transaction zkTransaction) {
    this.zkTransaction = zkTransaction;
    this.registry = registry;
  }
  
  @Override
  public Transaction create(String path, byte[] data, NodeCreateMode mode) {
    zkTransaction.create(registry.realPath(path), data, RegistryImpl.DEFAULT_ACL, RegistryImpl.toCreateMode(mode));
    return this;
  }

  @Override
  public <T> Transaction create(String path, T obj, NodeCreateMode mode) {
    byte[] data = null; ;
    if(obj != null) {
      data = JSONSerializer.INSTANCE.toBytes(obj);
    } else {
      data = new byte[0] ;
    }
    zkTransaction.create(registry.realPath(path), data, RegistryImpl.DEFAULT_ACL, RegistryImpl.toCreateMode(mode));
    return this;
  }
  
  @Override
  public <T> Transaction create(Node node, T obj, NodeCreateMode mode) {
    return create(node.getPath(), obj, mode) ;
  }
  
  @Override
  public Transaction createChild(Node node, String name, NodeCreateMode mode) {
    return createChild(node, name, new byte[0], mode);
  }
  
  @Override
  public Transaction createChild(Node node, String name, byte data[], NodeCreateMode mode) {
    return create(node.getPath() + "/" + name, data, mode);
  }
  
  @Override
  public <T> Transaction createChild(Node node, String name, T obj, NodeCreateMode mode) {
    return createChild(node, name, JSONSerializer.INSTANCE.toBytes(obj), mode);
  }
  
  @Override
  public Transaction createDescendant(Node node, String relativePath, NodeCreateMode mode) {
    return createDescendant(node, relativePath, new byte[0], mode);
  }
  @Override
  public Transaction createDescendant(Node node, String relativePath, byte data[], NodeCreateMode mode) {
    return create(node.getPath() + "/" + relativePath, data, mode);
  }

  @Override
  public <T> Transaction createDescendant(Node node, String relativePath, T obj , NodeCreateMode mode) {
    return createDescendant(node, relativePath, JSONSerializer.INSTANCE.toBytes(obj), mode);
  }
  
  @Override
  public Transaction delete(String path) {
    zkTransaction.delete(registry.realPath(path), -1);
    return this;
  }

  @Override
  public Transaction rdelete(String path) throws RegistryException {
    List<String> tree = registry.findDencendantRealPaths(path, null);
    for (int i = tree.size() - 1; i >= 0 ; --i) {
      //Delete the leaves first and eventually get rid of the root
      zkTransaction.delete(tree.get(i), -1);
    }
    return this;
  }
  
  public void rcopy(String path, String toPath) throws RegistryException {
    rcopy(path, toPath, null);
  }
  
  public void rcopy(String path, String toPath, PathFilter filter) throws RegistryException {
    List<String> tree = registry.findDencendantPaths(path, filter);
    for (int i = 0; i < tree.size(); i++) {
      String selPath = tree.get(i);
      String selToPath = selPath.replace(path, toPath);
      byte[] data = registry.getData(selPath) ;
      create(selToPath, data, NodeCreateMode.PERSISTENT) ;
    }
  }
  
  @Override
  public Transaction check(String path) {
    zkTransaction.check(registry.realPath(path), -1);
    return this;
  }

  @Override
  public Transaction setData(String path, byte[] data) {
    zkTransaction.setData(registry.realPath(path), data, -1);
    return this;
  }
  
  @Override
  public <T> Transaction setData(final String path, T obj) {
    zkTransaction.setData(registry.realPath(path), JSONSerializer.INSTANCE.toBytes(obj), -1);
    return this ;
  }
  
  @Override
  public <T> Transaction setData(Node node, byte[] data) {
    setData(node.getPath(), data);
    return this;
  }
  
  @Override
  public <T> Transaction setData(Node node, T obj) {
    setData(node.getPath(), obj);
    return this;
  }

  public Transaction deleteChild(Node node, String name) {
    delete(node.getPath() + "/" + name) ;
    return this ;
  }
  
  public Transaction deleteDescendant(Node node, String relativePath) {
    delete(node.getPath() + "/" + relativePath) ;
    return this ;
  }
  
  @Override
  public void commit() throws RegistryException {
    try {
      List<OpResult> results = zkTransaction.commit();
    } catch (InterruptedException  | KeeperException e) {
      throw RegistryImpl.toRegistryException("Commit Error", e);
    }
  }
}

@@ -570,19 +570,43 @@
 ction ;%0A
+  private int opCount ;%0A
   %0A
-
   public
@@ -969,32 +969,47 @@
 ateMode(mode));%0A
+    opCount++;%0A
     return this;
@@ -1358,24 +1358,39 @@
 ode(mode));%0A
+    opCount++;%0A
     return t
@@ -2743,32 +2743,47 @@
 ath(path), -1);%0A
+    opCount++;%0A
     return this;
@@ -3097,24 +3097,41 @@
 et(i), -1);%0A
+      opCount++;%0A
     %7D%0A    re
@@ -3662,24 +3662,41 @@
 RSISTENT) ;%0A
+      opCount++;%0A
     %7D%0A  %7D%0A  
@@ -3796,32 +3796,47 @@
 ath(path), -1);%0A
+    opCount++;%0A
     return this;
@@ -3968,24 +3968,39 @@
  data, -1);%0A
+    opCount++;%0A
     return t
@@ -4174,24 +4174,39 @@
 (obj), -1);%0A
+    opCount++;%0A
     return t
@@ -4746,32 +4746,32 @@
 %0A  %0A  @Override%0A
-
   public void co
@@ -4800,24 +4800,54 @@
 Exception %7B%0A
+    if(opCount == 0) return ;%0A
     try %7B%0A  

check empty op for transaction