package com.github.kubatatami.judonetworking.internals.streams;

import com.github.kubatatami.judonetworking.utils.FileUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;

public class RequestMultipartEntity implements StreamEntity {

    private static final byte[] CRLF = {'\r', '\n'};

    public static final String BOUNDARY = "-----------------------------735323031399963166993862150";

    private static Charset charset = Charset.forName("UTF-8");

    private List<PartFormData> parts;

    public RequestMultipartEntity(List<PartFormData> parts) {
        this.parts = parts;
    }

    @Override
    public long getContentLength() {
        return -1;
    }

    @Override
    public void writeTo(OutputStream outstream) throws IOException {
        write(null, outstream);
    }

    @Override
    public String getLog() throws IOException {
        StringBuilder sb = new StringBuilder();
        write(sb, null);
        return sb.toString();
    }

    private void write(StringBuilder sb, OutputStream outStream) throws IOException {
        for (PartFormData part : parts) {
            writeLine(sb, outStream, BOUNDARY);
            writeLine(sb, outStream, "Content-Disposition: form-data; name=\"" + part.getName() + "\"; " + "filename=\"" + part.getFileName() + "\"");
            if (part.getMimeType() != null && !part.getMimeType().isEmpty()) {
                writeLine(sb, outStream, "Content-Type: " + part.getMimeType());
            }
            if (part.getSize() >= 0) {
                writeLine(sb, outStream, "Content-Length: " + part.getSize());
            }
            writeLine(sb, outStream, "");
            write(sb, outStream, part.getInputStream(), part.getSize());
            writeLine(sb, outStream, "");
        }
        writeLine(sb, outStream, BOUNDARY + "--");
    }

    private void write(StringBuilder sb, OutputStream outStream, InputStream inputStream, long size) throws IOException {
        if (sb != null) {
            sb.append("[Binary body size: +\"" + size + "\"]");
        } else if (outStream != null) {
            FileUtils.copyStream(outStream, inputStream, size);
        }
    }

    private void writeLine(StringBuilder sb, OutputStream outStream, String line) throws IOException {
        if (sb != null) {
            sb.append(line);
            sb.append('\n');
        }
        if (outStream != null) {
            outStream.write(line.getBytes(charset));
            outStream.write(CRLF);
        }
    }

    @Override
    public void close() throws IOException {
        for (PartFormData part : parts) {
            part.getInputStream().close();
        }
    }

    public static String getMimeType() {
        return "multipart/form-data;boundary=" + BOUNDARY;
    }

    public static class PartFormData {

        private String name;

        private InputStream inputStream;

        private String mimeType;

        private String fileName;

        private final long size;

        public PartFormData(String name, InputStream inputStream, String mimeType, String fileName, long size) {
            this.name = name;
            this.inputStream = inputStream;
            this.mimeType = mimeType;
            this.fileName = fileName;
            this.size = size;
        }

        public String getName() {
            return name;
        }

        public InputStream getInputStream() {
            return inputStream;
        }

        public String getMimeType() {
            return mimeType;
        }

        public String getFileName() {
            return fileName;
        }

        public long getSize() {
            return size;
        }
    }
}

@@ -260,16 +260,39 @@
 il.List;
+%0Aimport java.util.UUID;
 %0A%0Apublic
@@ -448,66 +448,36 @@
 Y = 
-%22-----------------------------735323031399963166993862150%22
+UUID.randomUUID().toString()
 ;%0A%0A 
@@ -1166,32 +1166,72 @@
 part : parts) %7B%0A
+            write(sb, outStream, %22--%22);%0A
             writ
@@ -1369,13 +1369,8 @@
 %5C%22; 
-%22 + %22
 file
@@ -1723,32 +1723,35 @@
            write
+New
 Line(sb, outStre
@@ -1744,36 +1744,32 @@
 ne(sb, outStream
-, %22%22
 );%0A            w
@@ -1837,32 +1837,35 @@
            write
+New
 Line(sb, outStre
@@ -1870,12 +1870,8 @@
 ream
-, %22%22
 );%0A 
@@ -1884,32 +1884,147 @@
  %7D%0A        write
+(sb, outStream, %22--%22);%0A        write(sb, outStream, BOUNDARY);%0A        write(sb, outStream, %22--%22);%0A        writeNew
 Line(sb, outStre
@@ -2029,25 +2029,8 @@
 ream
-, BOUNDARY + %22--%22
 );%0A 
@@ -2229,24 +2229,63 @@
 ze: 
-+%5C%22%22 + size + %22%5C
+%22);%0A            sb.append(size);%0A            sb.append(
 %22%5D%22)
@@ -2299,13 +2299,16 @@
    %7D
- else
+%0A       
  if 
@@ -2564,24 +2564,560 @@
 pend(line);%0A
+        %7D%0A        if (outStream != null) %7B%0A            outStream.write(line.getBytes(charset));%0A        %7D%0A        writeNewLine(sb, outStream);%0A    %7D%0A%0A    private void write(StringBuilder sb, OutputStream outStream, String line) throws IOException %7B%0A        if (sb != null) %7B%0A            sb.append(line);%0A        %7D%0A        if (outStream != null) %7B%0A            outStream.write(line.getBytes(charset));%0A        %7D%0A    %7D%0A%0A    private void writeNewLine(StringBuilder sb, OutputStream outStream) throws IOException %7B%0A        if (sb != null) %7B%0A
             
@@ -3180,61 +3180,8 @@
 ) %7B%0A
-            outStream.write(line.getBytes(charset));%0A
     
@@ -3466,16 +3466,17 @@
 rm-data;
+ 
 boundary

support multipart form data