package com.tomas.pcs_asi.lib.common;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;

import com.tomas.pcs_asi.R;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Map;

public abstract class AsyncHttpClientMultipart extends AsyncTask<Void,Void,Void> {

    Context context;
    String _url;
    Map<String, Object> parts;

    String response;
    int resp_code = 200;

    abstract protected void onFinished(String response, int resp_code);

    public AsyncHttpClientMultipart(Context context, String url, Map<String, Object> parts) {
        this.context = context;
        this._url = url;
        this.parts = parts;
    }

    @Override
    protected void onPostExecute(Void unused) {
        super.onPostExecute(unused);
        onFinished(response, resp_code);
    }

    @Override
    protected Void doInBackground(Void... voids) {
        Log.d(context.getString(R.string.tag), "url: " + _url);

        String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
        String CRLF = "\r\n"; // Line separator required by multipart/form-data.
        String charset = StandardCharsets.UTF_8.toString();

        try {
            URL url = new URL(_url);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            conn.setRequestProperty("Accept","application/json");
            conn.addRequestProperty("User-Agent", context.getString(R.string.user_agent));
            conn.addRequestProperty("X-Requested-With",context.getString(R.string.x_requested_with));
            conn.setDoOutput(true);
            conn.setDoInput(true);

            PrintWriter writer = null;
            try {
                OutputStream output = conn.getOutputStream();
                writer = new PrintWriter(new OutputStreamWriter(output, charset), true); // true = autoFlush, important!

                for(Iterator<Map.Entry<String, Object>> it = parts.entrySet().iterator(); it.hasNext(); ) {
                    Map.Entry<String, Object> entry = it.next();
                    if(entry.getKey().toLowerCase().contains("json")) {
                        writer.append("--" + boundary).append(CRLF);
                        writer.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"").append(CRLF);
                        writer.append("Content-Type: application/json; charset=" + charset).append(CRLF);
                        writer.append(CRLF);
                        writer.append((String)entry.getValue()).append(CRLF).flush();
                    } else if (entry.getKey().toLowerCase().contains("jpeg")) {
                        writer.append("--" + boundary).append(CRLF);
                        writer.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"").append(CRLF);
                        writer.append("Content-Type: image/jpeg; charset=" + charset).append(CRLF);
                        writer.append(CRLF).flush();

                        byte[] buffer = (byte[])entry.getValue();
                        output.write(buffer, 0, buffer.length);
                        output.flush();

                        writer.append(CRLF).flush(); // CRLF is important! It indicates end of binary boundary.
                    }
                }

                // Send text file.
//                writer.append("--" + boundary).append(CRLF);
//                writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
//                writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
//                writer.append(CRLF).flush();
//                BufferedReader reader = null;
//                try {
//                    reader = new BufferedReader(new InputStreamReader(new FileInputStream(textFile), charset));
//                    for (String line; (line = reader.readLine()) != null;) {
//                        writer.append(line).append(CRLF);
//                    }
//                } finally {
//                    if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
//                }
//                writer.flush();

                // Send binary file.
//                writer.append("--" + boundary).append(CRLF);
//                writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
//                writer.append("Content-Type: " +     URLconn.guessContentTypeFromName(binaryFile.getName()).append(CRLF);
//                writer.append("Content-Transfer-Encoding: binary").append(CRLF);
//                writer.append(CRLF).flush();
//                InputStream input = null;
//                try {
//                    input = new FileInputStream(binaryFile);
//                    byte[] buffer = new byte[1024];
//                    for (int length = 0; (length = input.read(buffer)) > 0;) {
//                        output.write(buffer, 0, length);
//                    }
//                    output.flush(); // Important! Output cannot be closed. Close of writer will close output as well.
//                } finally {
//                    if (input != null) try { input.close(); } catch (IOException logOrIgnore) {}
//                }
//                writer.append(CRLF).flush(); // CRLF is important! It indicates end of binary boundary.

                // End of multipart/form-data.
                writer.append("--" + boundary + "--").append(CRLF);
            } finally {
                if (writer != null) writer.close();
            }

            BufferedReader br = null;
            if (100 <= conn.getResponseCode() && conn.getResponseCode() <= 399) {
                br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
            } else {
                br = new BufferedReader(new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8));
            }
            String tmp;
            StringBuffer stringBuffer = new StringBuffer();
            while ((tmp = br.readLine()) != null) {
                stringBuffer.append(tmp);
                stringBuffer.append("\r");
            }

            response = stringBuffer.toString();
            resp_code = conn.getResponseCode();

            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

}
