import com.mathworks.mps.client.rest.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class ImageExample {

    final static protected String CONTENT_TYPE = "application/x-google-protobuf";

    public static void main(String[] args) {

        try {

            String clientId = "123";
			
			// URL of the MATLAB Production Server.			
            String mpsBaseUrl = "http://localhost:9910";
            // Use the java.net package's URLConnection as HTTP Client in this example.
            URL url;
            url = new URL(mpsBaseUrl + "/imageExample/imageExample?mode=async&client=" + clientId);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            //Content-Type needs to be set to protobuf.
            urlConnection.setRequestProperty("Content-Type", CONTENT_TYPE);
            urlConnection.setRequestProperty("Accept-Charset", "UTF-8");

            // This class makes the initial POST request body.
            MATLABParams mlMakeBody = MATLABParams.newInstance(1, byte[].class, null);

            // Write the MATLABParams object into the output stream of the HTTP request.
            OutputStream output = urlConnection.getOutputStream();
            mlMakeBody.writeTo(output);
            output.flush();

            System.out.println("POST call response code: " + urlConnection.getResponseCode() + " Response msg: " + urlConnection.getResponseMessage());

            // Parse the response body with the help of MATLABRequestHandle
            // to retrieve the requestUrl, lastModified value and state of the request.
            MATLABRequestHandle mlInitialResponse = MATLABRequestHandle.newInstance(urlConnection.getInputStream());
            System.out.println("State: " + mlInitialResponse.getState() + " Request URL: " + mlInitialResponse.getRequestURL() + " Last modified sequence: " + mlInitialResponse.getLastModifiedSeq());
            System.out.println();

            // Query for the state of the request.
            url = new URL(mpsBaseUrl + mlInitialResponse.getRequestURL() + "/info?" + "format=protobuf");
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestProperty("Content-Type", CONTENT_TYPE);
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            MATLABRequest requestInfoTmp = null;
            // Parse the response body with the help of MATLABRequest class.
            requestInfoTmp = MATLABRequest.newInstance(urlConnection.getInputStream());
            System.out.println("State: "+requestInfoTmp.getState() + " Last modified sequence: " + requestInfoTmp.getLastModifiedSeq());

			//Wait for the request state to either turn to READY or ERROR_STATE.
            while (requestInfoTmp.getState().toString().compareTo(MATLABRequestState.READY_STATE.toString()) != 0) {
                url = new URL(mpsBaseUrl + mlInitialResponse.getRequestURL() + "/info?" + "format=protobuf");
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestProperty("Content-Type", CONTENT_TYPE);
                urlConnection.setRequestMethod("GET");
                urlConnection.connect();

                // Parse the response body with the help of MATLABRequest class.
                requestInfoTmp = MATLABRequest.newInstance(urlConnection.getInputStream());
                System.out.println("State: "+requestInfoTmp.getState() + " Last modified sequence: " + requestInfoTmp.getLastModifiedSeq());
                if (requestInfoTmp.getState().toString().compareTo(MATLABRequestState.ERROR_STATE.toString()) == 0) {
                    break;
                }
                Thread.sleep(1000);
            }

            // Once the state changes to READY_STATE or ERROR_STATE, make a GET call to /result. If the state is ERROR_STATE, use HTTPErrorInfo class, else use MATLABResult to parse the response body.
            url = new URL(mpsBaseUrl + mlInitialResponse.getRequestURL() + "/result?" + "format=protobuf");
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestProperty("User-Agent", "CreateRequest");
            urlConnection.setRequestProperty("Content-Type", CONTENT_TYPE);
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();


            System.out.println("/result call response code: " + urlConnection.getResponseCode() + " and response message: " + urlConnection.getResponseMessage() + "response type: " + urlConnection.getContentType());

            if (requestInfoTmp.getState().compareTo(MATLABRequestState.ERROR_STATE) == 0) {
                HTTPErrorInfo httpErrorInfo = HTTPErrorInfo.newInstance(urlConnection.getInputStream());
                System.out.println("Error code: " + httpErrorInfo.getHttpErrorCode());
                System.out.println("Error message: " + httpErrorInfo.getHttpErrorMessage());
                System.out.println("Error body: " + httpErrorInfo.getHttpBody());
            } else {
                // Parse the response body of the above HTTP request with the help of MATLABResult. The newInstance method
                // here also takes MATLABParams object that was initially created.
                // If there is any error in MATLAB, call to getResult() will throw MATLABException which contains the error message
                // displayed in MATLAB.
                MATLABResult<byte[]> mlFinalResult = MATLABResult.newInstance(mlMakeBody, urlConnection.getInputStream());

                //Use BufferedImage and ImageIO Classes to write the returned byte array into a JFrame which displays the image.
                byte[] magicSq = mlFinalResult.getResult();
                final BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(magicSq));

                // Now create a frame, display it and display the image.
                JLabel label = new JLabel(new ImageIcon(bufferedImage));
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.getContentPane().add(label);
                f.pack();
                f.setLocation(200, 200);
                f.setVisible(true);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
