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

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;


public class SortStudentsAsyncREST{

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

    public static void main(String[] args){


        String clientId = "123";

        //Creating a Student Array
        Student[] students = new Student[]{new Student("Toni Miller", 90, "A"),
                new Student("Ed Plum", 80, "B+"),
                new Student("Mark Jones", 85, "A-")};

        // Use the java.net package's URLConnection as HTTP Client in this example.
        try {
            String mpsBaseUrl = "http://localhost:9910";
            URL url;
            url = new URL(mpsBaseUrl + "/sortstudents/sortstudents?mode=async&client="+clientId);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setDoOutput(true);
			
            //Set Content-Type needs to to protobuf.
            urlConnection.setRequestProperty("Content-Type", CONTENT_TYPE);


            // Make the initial POST request body with MATLABParams class.
            MATLABParams mlMakeBody = MATLABParams.newInstance(1, Student[].class, new StudentMarshaller(), new Object[]{students});

            // 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 using methods from MATLABRequestHandle
            // 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() + " InstanceId: " + mlInitialResponse.getInstanceId() + " Last modified sequence: " + mlInitialResponse.getLastModifiedSeq());
            System.out.println();


            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());
            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());

			//Wait for the state of the request to turn to READY or ERROR_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");
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestProperty("User-Agent", "CreateRequest");
            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.
			// If the state of the request is ERROR_STATE, use HTTPErrorInfo class to parse the response body.
			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 {
				MATLABResult mlFinalResult = MATLABResult.newInstance(mlMakeBody, urlConnection.getInputStream());
				Student[] magicSq = (Student[]) mlFinalResult.getResult();
				for (Student student :
						magicSq) {
					System.out.println(student);
				}
			}

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

}