package com.google.sps.servlets;

import static com.google.appengine.api.datastore.TransactionOptions.Builder.*;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.api.datastore.Transaction;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.KeyFactory;

import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreFailureException;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;

import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/deletefolder")
public class DeleteFolderServlet extends HttpServlet {

  @Override
  public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
    UserService userService = UserServiceFactory.getUserService();

    if (userService.isUserLoggedIn()) {
      String folderKey = request.getParameter("folderKey");
      deleteAllCardsInsideFolder(folderKey);
      deleteFolder(folderKey);
    }
  }

  private void deleteFolder(String folderKey) throws IOException {
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    datastore.delete(KeyFactory.stringToKey(folderKey));
  }

  private void deleteAllCardsInsideFolder(String folderKey) throws IOException {
    Query cardQuery = new Query("Card").setAncestor(KeyFactory.stringToKey(folderKey));

    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    PreparedQuery results = datastore.prepare(cardQuery);

    // TODO(ngothomas): bug with testing local blobstore
    if (results != null) {
      for (Entity card : results.asIterable()) {
        String imageBlobKey = (String) card.getProperty("imageBlobKey");
        if (imageBlobKey != "null") {
          deleteBlob(imageBlobKey);
        }
        transactionalRetryForCardDeletion(datastore, card);
      }
    }
  }

  private void deleteBlob(String blobKey) throws IOException {
    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    BlobKey key = new BlobKey(blobKey);

    // BlobstoreService doesn't have its own transaction API
    // So we will try to delete the blobKey within 5 tries
    // If it doesn't happen successfully, we will just continue w/o deleting
    int retries = 5;
    while (true) {
      try {
        blobstoreService.delete(key);
        break;
      } catch (BlobstoreFailureException e) {
        if (retries == 0) {
          break;
        }
        --retries;
      }
    }
  }

  private void transactionalRetryForCardDeletion(DatastoreService datastore, Entity card) {
    int retries = 5;
    while (true) {
      try {
        deleteCard(datastore, card);
        break;
      } catch (Exception e) {
        if (retries == 0) {
          break;
        }
        --retries;
      }
    }
  }

  private void deleteCard(DatastoreService datastore, Entity card) {
    Transaction txn = datastore.beginTransaction(withXG(true));
    try {
      datastore.delete(card.getKey());
      txn.commit();
    } finally {
      if (txn.isActive()) {
        txn.rollback();
      }
    }
  }
}

@@ -1565,165 +1565,640 @@
 ey) 
-throws IOException %7B%0A    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();%0A    datastore.delete(KeyFactory.stringToKey(folderKey));
+%7B%0A    int retries = 5;%0A    while (true) %7B%0A      try %7B%0A        folderDeletionTransaction(folderKey);%0A        break;%0A      %7D catch (Exception e) %7B%0A        if (retries == 0) %7B%0A          break;%0A        %7D%0A        --retries;%0A      %7D%0A    %7D%0A  %7D%0A%0A  private void folderDeletionTransaction(String folderKey) throws IOException %7B%0A    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();%0A    Transaction txn = datastore.beginTransaction(withXG(true));%0A    try %7B%0A      datastore.delete(KeyFactory.stringToKey(folderKey));%0A      txn.commit();%0A    %7D finally %7B%0A      if (txn.isActive()) %7B%0A        txn.rollback();%0A      %7D%0A    %7D
 %0A  %7D
@@ -2810,41 +2810,18 @@
     
-transactionalRetryForCardDeletion
+deleteCard
 (dat
@@ -3505,41 +3505,18 @@
 oid 
-transactionalRetryForCardDeletion
+deleteCard
 (Dat
@@ -3611,34 +3611,47 @@
 y %7B%0A        
-deleteCard
+cardDeletionTransaction
 (datastore, 
@@ -3806,34 +3806,47 @@
 rivate void 
-deleteCard
+cardDeletionTransaction
 (DatastoreSe

Add Transaction for deleting Folder Entity