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

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;


public class AsyncExample{

	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 + "/mymagic/mymagic?mode=async&client="+clientId);
			
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
            //Set Content-Type to protobuf.
            urlConnection.setRequestProperty("Content-Type", CONTENT_TYPE);

            // Make the initial POST request body with MATLABParams class.
            MATLABParams mlMakeBody = MATLABParams.newInstance(1, double[][].class, 2);

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

            // Parse the response body of the above HTTP request with methods from the MATLABResult class
            // to retrieve the request URL, lastModified value and state of the request.
            MATLABRequestHandle mlInitialResponse = MATLABRequestHandle.newInstance(urlConnection.getInputStream());
            System.out.println("First Request has been Sent. Initial response is below");
            System.out.println("State: "+ mlInitialResponse.getState() + " " + "Request URL: "+mlInitialResponse.getRequestURL() + " Last modified sequence: " + mlInitialResponse.getLastModifiedSeq());

            // 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 using methods from MATLABRequest class.
            requestInfoTmp = MATLABRequest.newInstance(urlConnection.getInputStream());
            System.out.println("State: "+requestInfoTmp.getState() + " Last modified sequence: " + requestInfoTmp.getLastModifiedSeq());

			// Looop to check if the state of the request is READY_STATE.
            for (int i = 0; i < 30; i++) {
                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 using methods from MATLABRequest class.
                requestInfoTmp = MATLABRequest.newInstance(urlConnection.getInputStream());
                System.out.println("State: "+requestInfoTmp.getState() + " Last modified sequence: " + requestInfoTmp.getLastModifiedSeq());

				// Break if the current state turns to READY or ERROR_STATE, please see g2654039.
				if (requestInfoTmp.getState().compareTo(MATLABRequestState.READY_STATE) == 0 || requestInfoTmp.getState().compareTo(MATLABRequestState.ERROR_STATE) == 0) {
                    break;
                }

                Thread.sleep(1000);
            }
			
            // Once the state changes to READY_STATE, query for the result.
            url = new URL(mpsBaseUrl + mlInitialResponse.getRequestURL() + "/result?" + "format=protobuf");
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestProperty("Content-Type", CONTENT_TYPE);
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();


            // Parse the response body of the above HTTP request using methods from MATLABResult class. 
			// The MATLABParams object created earlier is an input argument to the newInstance method.
            // If there is any error in MATLAB, call to getResult() throws a MATLABException which contains the error message
            // displayed in MATLAB.
            MATLABResult mlFinalResult1 = MATLABResult.newInstance(mlMakeBody, urlConnection.getInputStream());
            try{
                double[][] magicSq1 = (double[][]) mlFinalResult1.getResult();
                printResult(magicSq1);
            }catch(MATLABException e){
                e.printStackTrace();
            }
        } catch(Exception e){
            e.printStackTrace();
        } 

    }

    // Helper method to print out the magic square generated by MATLAB based on the input.
    private static void printResult(double[][] result) {
        for (double[] row : result) {
            for (double element : row) {
                System.out.print(element + " ");
            }
            System.out.println();
        }
    }


}

