package com.google.appengine.demos;

import com.google.appengine.tools.cloudstorage.GcsFileOptions;
import com.google.appengine.tools.cloudstorage.GcsFilename;
import com.google.appengine.tools.cloudstorage.GcsInputChannel;
import com.google.appengine.tools.cloudstorage.GcsOutputChannel;
import com.google.appengine.tools.cloudstorage.GcsService;
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
import com.google.appengine.tools.cloudstorage.RetryParams;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * A simple servlet that proxies reads and writes to its Google Cloud Storage bucket.
 */
@SuppressWarnings("serial")
public class GcsExampleServlet extends HttpServlet {

  /**
   * This is where backoff parameters are configured. Here it is aggressively retrying with
   * backoff, up to 10 times but taking no more that 15 seconds total to do so.
   */
  private final GcsService gcsService = GcsServiceFactory.createGcsService(new RetryParams.Builder()
      .initialRetryDelayMillis(10)
      .retryMaxAttempts(10)
      .totalRetryPeriodMillis(15000)
      .build());

  /**Used below to determine the size of chucks to read in. Should be > 1kb and < 10MB */
  private static final int BUFFER_SIZE = 2 * 1024 * 1024;

  /**
   * Retrieves a file from GCS and returns it in the http response.
   * If a get comes in for request path /gcs/Foo/Bar this will be interpreted as
   * a request to read the GCS file named Bar in the bucket Foo.
   */
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    GcsInputChannel readChannel =
      gcsService.openPrefetchingReadChannel(getFileName(req), 0, BUFFER_SIZE);
    copy(Channels.newInputStream(readChannel), resp.getOutputStream());
  }

  /**
   * Writes the payload of the incoming post as the contents of a file to GCS.
   * If the post is to request path is /gcs/Foo/Bar this will be interpreted as
   * a request to create a GCS file named Bar in bucket Foo.
   */
  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    GcsOutputChannel outputChannel =
        gcsService.createOrReplace(getFileName(req), GcsFileOptions.getDefaultInstance());
    copy(req.getInputStream(), Channels.newOutputStream(outputChannel));
  }

  private GcsFilename getFileName(HttpServletRequest req) {
    String[] splits = req.getRequestURI().split("/", 3);
    return new GcsFilename(splits[1], splits[2]);
  }

  /**
   * Transfer the data from the inputStream to the outputStream. Then close both streams.
   */
  private void copy(InputStream input, OutputStream output) throws IOException {
    try {
      byte[] buffer = new byte[BUFFER_SIZE];
      int bytesRead = input.read(buffer);
      while (bytesRead != -1) {
        output.write(buffer, 0, bytesRead);
        bytesRead = input.read(buffer);
      }
    } finally {
      input.close();
      output.close();
    }
  }


}

@@ -2629,11 +2629,206 @@
 /%22, 
-3);
+4);%0A    if (!splits%5B0%5D.equals(%22%22) %7C%7C !splits%5B1%5D.equals(%22gcs%22)) %7B%0A      throw new IllegalArgumentException(%22The URL is not formed as expected. %22 +%0A          %22Expecting /gcs/%3Cbucket%3E/%3Cobject%3E%22);%0A    %7D
 %0A   
@@ -2858,17 +2858,17 @@
 (splits%5B
-1
+2
 %5D, split
@@ -2869,17 +2869,17 @@
  splits%5B
-2
+3
 %5D);%0A  %7D%0A

Fix URL parsing