/*
 * Copyright 2018 The StartupOS Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.startupos.common.firestore;

import static java.net.HttpURLConnection.HTTP_OK;

import java.io.IOException;
import java.io.Reader;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.net.HttpURLConnection;
import java.net.URL;
import com.google.protobuf.Message;
import com.google.protobuf.MessageOrBuilder;
import com.google.protobuf.util.JsonFormat;

// TODO: Fix open Firestore rules
public class FirestoreClient {
  // Base path formatted by project name and path, that starts with a /.
  private static final String BASE_PATH =
          "https://firestore.googleapis.com/v1beta1" + "/projects/%s/databases/(default)/documents%s";

  private final String project;
  private final String token;

  public FirestoreClient(String project, String token){
    this.project = project;
    this.token = token;
  }

  private String getGetUrl(String path) {
    return String.format(BASE_PATH, project, path);
  }

  private String getCreateDocumentUrl(String user) {
    // GET and CreateDocument are the same if the server selects the ID.
    return getGetUrl(user);
  }

  public Message getDocument(String path, Message.Builder proto) {
    try {
      StringBuilder result = new StringBuilder();
      URL url = new URL(getGetUrl(path));
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.setRequestMethod("GET");
      BufferedReader reader =
          new BufferedReader(new InputStreamReader(connection.getInputStream()));
      String line;
      while ((line = reader.readLine()) != null) {
        result.append(line);
      }
      reader.close();
      if (connection.getResponseCode() != HTTP_OK) {
        throw new IllegalStateException("getDocument failed: " + connection.getResponseMessage());
      }
      FirestoreJsonFormat.parser().merge(result.toString(), proto);
      return proto.build();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public void createDocument(String path, MessageOrBuilder proto) {
    try {
      URL url = new URL(getCreateDocumentUrl(path));

      String prototxt = JsonFormat.printer().print(proto);
      String json = FirestoreJsonFormat.printer().print(proto);
      byte[] postDataBytes = json.getBytes("UTF-8");
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.setRequestMethod("POST");
      connection.setRequestProperty("Content-Type", "application/json");
      connection.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
      connection.setRequestProperty("Authorization", "Bearer " + token);
      connection.setDoOutput(true);
      connection.getOutputStream().write(postDataBytes);

      Reader in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));

      for (int c; (c = in.read()) >= 0; ) System.out.print((char) c);
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }
}
@@ -710,84 +710,124 @@
 ort 
-java.io.IOException;%0Aimport java.io.Reader;%0Aimport java.io.InputStreamReader
+com.google.protobuf.Message;%0Aimport com.google.protobuf.MessageOrBuilder;%0Aimport com.google.protobuf.util.JsonFormat
 ;%0Aim
@@ -867,33 +867,26 @@
 rt java.
-net.HttpURLConnec
+io.IOExcep
 tion;%0Aim
@@ -899,140 +899,107 @@
 ava.
-net.URL;%0Aimport com.google.protobuf.Message;%0Aimport com.google.protobuf.MessageOrBuilder;%0Aimport com.google.protobuf.util.JsonFormat
+io.InputStreamReader;%0Aimport java.io.Reader;%0Aimport java.net.HttpURLConnection;%0Aimport java.net.URL
 ;%0A%0A/
@@ -1183,20 +1183,16 @@
 =%0A      
-    
 %22https:/
@@ -1394,16 +1394,17 @@
 g token)
+ 
 %7B%0A    th
@@ -1602,16 +1602,35 @@
 ing user
+, String documentId
 ) %7B%0A    
@@ -1706,29 +1706,217 @@
     
-return getGetUrl(user
+if (documentId == null) %7B%0A      return getGetUrl(user);%0A    %7D%0A    return getGetUrl(user) + %22/%22 + documentId;%0A  %7D%0A%0A  private String getCreateDocumentUrl(String user) %7B%0A    return getCreateDocumentUrl(user, null
 );%0A 
@@ -2205,24 +2205,97 @@
 hod(%22GET%22);%0A
+      connection.setRequestProperty(%22Authorization%22, %22Bearer %22 + token);%0A
       Buffer
@@ -2917,32 +2917,163 @@
 uilder proto) %7B%0A
+    createDocument(path, null, proto);%0A  %7D%0A%0A  public void createDocument(String path, String documentId, MessageOrBuilder proto) %7B%0A
     try %7B%0A      
@@ -3111,24 +3111,36 @@
 mentUrl(path
+, documentId
 ));%0A%0A      S
@@ -3397,44 +3397,366 @@
     
-connection.setRequestMethod(%22POST%22);
+// PATCH method updates the document if if exists and creates otherwise%0A      // java.net.HttpURLConnection does not support PATCH natively%0A      // SOURCE: https://stackoverflow.com/a/32503192/4617642%0A      connection.setRequestMethod(%22POST%22);%0A      if (documentId != null) %7B%0A        connection.setRequestProperty(%22X-HTTP-Method-Override%22, %22PATCH%22);%0A      %7D
 %0A   
@@ -4333,8 +4333,9 @@
  %7D%0A  %7D%0A%7D
+%0A

create or update for createDocument (#73)