// Copyright 1984-2019 The MathWorks, Inc.
// All Rights Reserved.

using System;
using System.Net;
using System.IO;
using MathWorks.MATLAB.ProductionServer.Client;
using MathWorks.MATLAB.ProductionServer.Client.REST;
using System.Drawing;
using System.Collections.Generic;
using System.Threading;

namespace ImageExample
{
    public class ImageExample
    {
        static void Main(string[] args)
        {

            //URL of the MATLAB Production Server.
            String mpsBaseUrl = "http://localhost:9910";

            Console.WriteLine("Sending initial HTTP POST request to the URL " + mpsBaseUrl + "/imageExample/imageExample?mode=async.");
            MATLABParams mlParams = MATLABParams.Create(1, new List<Type> { typeof(sbyte[]) });
            var response = MakeHTTPRequest(mpsBaseUrl + "/imageExample/imageExample?mode=async", "POST", mlParams);
            Console.WriteLine("The HTTP status code of the request is " + response.StatusCode + ".\n\n");

            // Parse the response body using the MATLABRequestHandle class
            // to retrieve the request URL, last modified sequence value and state of the request.
            MATLABRequestHandle matlabRequestHandle = MATLABRequestHandle.Create(response.GetResponseStream());
            Console.WriteLine("The response body of initial POST request contains the following values after deserialization using MATLABRequestHandle class: ");
            Console.WriteLine(matlabRequestHandle.ToString() + ".\n\n");

            // Query for the state of the request.
            Console.WriteLine("Send GET status request every 1 second to look for state change of the request to either READY_STATE or ERROR_STATE.");
            Console.WriteLine("Sending GET request to the following URL to fetch the status of the request " + mpsBaseUrl + matlabRequestHandle.RequestURL + "/info?format=protobuf.");
            Console.WriteLine("The response body is parsed with MATLABRequest class.");
            MATLABRequest mlRequestStatus;
            do
            {
                var statusRequestResponse = MakeHTTPRequest(mpsBaseUrl + matlabRequestHandle.RequestURL + "/info?format=protobuf", "GET", null);
                mlRequestStatus = MATLABRequest.Create(statusRequestResponse.GetResponseStream());
                Console.WriteLine("State: " + mlRequestStatus.State + " Last modified sequence value: " + mlRequestStatus.LastModified + ".");
                Thread.Sleep(1000);
            } while (mlRequestStatus.State < MATLABRequestState.READY_STATE);

            Console.Write("\n\n");
            Console.WriteLine("Now send GET request to fetch the result using the URL " + mpsBaseUrl + matlabRequestHandle.RequestURL + "/result?format=protobuf.");
            response = MakeHTTPRequest(mpsBaseUrl + matlabRequestHandle.RequestURL + "/result?format=protobuf", "GET", null);

            // 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 class to parse the response body.

            if (mlRequestStatus.State == MATLABRequestState.READY_STATE)
            {
                // Parse the response body with the help of MATLABResult class. The Create function
                // takes as input the MATLABParams object that was initially created.
                // If there is any error in MATLAB, call to Result<>() throws MATLABException which contains the error message
                // displayed in MATLAB.

                MATLABResult mlResult;
                try
                {
                    mlResult = MATLABResult.Create(mlParams, response.GetResponseStream());
                    sbyte[] result = mlResult.Result<sbyte[]>();
                    MemoryStream ms = null;
                    ms = new MemoryStream((byte[])(Array)result, 0, result.Length);
                    ms.Position = 0;
                    Image returnImage = Image.FromStream(ms, true);
                    Console.WriteLine("Saving the image...");
                    returnImage.Save("test.png");
                    Console.WriteLine("Image can be found here: " + Path.GetFullPath("test.png"));
                }
                catch (MATLABException e)
                {
                    Console.WriteLine(e.Message);
                }
            }
            else if (mlRequestStatus.State == MATLABRequestState.ERROR_STATE)
            {
                HTTPErrorInfo httpErrorInfo = HTTPErrorInfo.Create(response.GetResponseStream());
                Console.WriteLine("Error occured during MATLAB function execution: ");
                Console.WriteLine(httpErrorInfo.HttpErrorCode);
                Console.WriteLine(httpErrorInfo.HttpErrorMessage);
            }
            Console.ReadKey();
        }

        //This function takes URL and HTTP request type as input and sends the HTTP request
        static HttpWebResponse MakeHTTPRequest(String url, String requestType, MATLABParams mlParams)
        {
            var httpRequest = (HttpWebRequest)WebRequest.Create(url);
            httpRequest.Method = requestType;
            httpRequest.ContentType = "application/x-google-protobuf";
            if (requestType.Equals("POST"))
            {
                mlParams.WriteTo(httpRequest.GetRequestStream());

            }
            return (HttpWebResponse)httpRequest.GetResponse();
        }

    }
}
