package foam.blob;

import foam.core.X;
import jdk.internal.jline.internal.InputStreamReader;

import java.net.URL;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.nio.ByteBuffer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class RestBlobService
    extends AbstractBlobService
{
  public static final int BUFFER_SIZE = 8192;

  protected String address_;

  public RestBlobService(String address) {
    this.address_ = address + "/httpBlobService";
  }

  public RestBlobService(foam.core.X x, String address) {
    setX(x);
    this.address_ = address + "/httpBlobService";
  }

  public String getAddress() {
    return address_;
  }

  @Override
  public Blob put_(X x, Blob blob) {
    if ( blob instanceof IdentifiedBlob ) {
      return blob;
    }
    HttpURLConnection connection = null;
    OutputStream os = null;
    InputStream is = null;
    IdentifiedBlob result = null;
    try {
      URL url = new URL(address_);
      connection = (HttpURLConnection) url.openConnection();
      
      //configure HttpURLConnection
      connection.setConnectTimeout(5 * 1000);
      connection.setReadTimeout(5 * 1000);
      connection.setDoOutput(true);
      connection.setUseCaches(false);

      //set request method
      connection.setRequestMethod("PUT");

      //configure http header
      connection.setRequestProperty("Accept", "*/*");
      connection.setRequestProperty("Connection", "keep-alive");
      connection.setRequestProperty("Content-Type", "application/octet-stream");

      //output blob into connection
      long chunk = 0;
      long size = blob.getSize();
      long chunks = (long) Math.ceil((double) size / (double) BUFFER_SIZE);
      Buffer buffer = new Buffer(BUFFER_SIZE, ByteBuffer.allocate(BUFFER_SIZE));
      os = connection.getOutputStream();

      while ( chunk < chunks ) {
        buffer = blob.read(buffer, chunkOffset(chunk));
        byte[] buf = buffer.getData().array();
        os.write(buf, 0, buf.length);
        buffer.getData().clear();
        chunk++;
      }

      os.flush();

      if ( connection.getResponseCode() != HttpURLConnection.HTTP_OK ) {
        //get respone from server id is in it
        is = connection.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        String id = "";
        String line = null;
        while ( (line = reader.readLine()) != null ) {
          id += line;
        }
        result = new IdentifiedBlob();
        result.setId(id);
        result.setX(getX());
      }
    } catch ( MalformedURLException e ) {
      e.printStackTrace();
    } catch ( IOException e ) {
      e.printStackTrace();
    } finally {
      if ( os != null ) {
        try {
          os.close();
        } catch ( IOException e ) {
          e.printStackTrace();
        }
      }

      if ( is != null ) {
        try {
          is.close();
        } catch ( IOException e ) {
          e.printStackTrace();
        }
      }
      return result;
    }
  }

  //retrive file from url
  @Override
  public Blob find_(X x, Object id) {
    InputStream is = null;
    HttpURLConnection connection = null;
    Blob blob = null;
    try {
      URL url = new URL(this.address_ + "/" + id.toString());
      connection = (HttpURLConnection) url.openConnection();

      connection.setRequestMethod("GET");
      connection.connect();

      if ( connection.getResponseCode() != HttpURLConnection.HTTP_OK ) {
        is = connection.getInputStream();
        blob = new InputStreamBlob(is);
      }
    } catch ( MalformedURLException e ) {
      e.printStackTrace();
    } catch ( IOException e ) {
      e.printStackTrace();
    } finally {
      if ( is != null ) {
        try {
          is.close();
        } catch ( IOException e ) {
          e.printStackTrace();
        }
      }
      return blob;
    }
  }

  @Override
  public String urlFor_(X x, Blob blob) {
    if ( ! (blob instanceof IdentifiedBlob) ) {
      return null;
    }
    return this.address_ + "/" + ((IdentifiedBlob) blob).getId();
  }

  private long chunkOffset(long i) {
    return i * BUFFER_SIZE;
  }
}
@@ -36,62 +36,8 @@
 e.X;
-%0Aimport jdk.internal.jline.internal.InputStreamReader;
 %0A%0Aim
@@ -272,16 +272,50 @@
 tStream;
+%0Aimport java.io.InputStreamReader;
 %0A%0Apublic
@@ -2047,18 +2047,32 @@
  0, 
-buf.l
+(int) buffer.getL
 ength
+()
 );%0A 
@@ -2226,54 +2226,8 @@
 ) %7B%0A
-        //get respone from server id is in it%0A
     
@@ -2358,18 +2358,20 @@
  String 
-id
+json
  = %22%22;%0A 
@@ -2462,18 +2462,20 @@
         
-id
+json
  += line
@@ -2482,24 +2482,25 @@
 ;%0A        %7D%0A
+%0A
         resu
@@ -2504,19 +2504,83 @@
 esult = 
-new
+(IdentifiedBlob) (new foam.lib.json.JSONParser()).parseString(json,
  Identif
@@ -2586,17 +2586,22 @@
 fiedBlob
-(
+.class
 );%0A     
@@ -2617,13 +2617,16 @@
 .set
-Id(id
+X(getX()
 );%0A 
@@ -2630,36 +2630,73 @@
 ;%0A      
-  result.setX(getX()
+%7D else %7B%0A        throw new RuntimeException(%22upload fail%22
 );%0A     
@@ -3691,24 +3691,92 @@
 amBlob(is);%0A
+      %7D else %7B%0A        throw new RuntimeException(%22download fail%22);%0A
       %7D%0A    

fix buffer bug