private static async Task <WTPowerResultSet> getPredictedPower(WTPowerRequestInfo predictionInputs, Boolean allInfo = false)
        {
            DMResultInfo PredictionPowerDMSet = await MlApi.GetPowerAsync(predictionInputs.PowerInputs);

            float[] PredictionPowerPMSet = await PmAPI.GetPowerAsync(predictionInputs.PowerInputs);

            WTPowerResultSet results;
            int iterator = 0;

            if (allInfo)
            {
                results = new WTPowerResultSet {
                    powerForecastResults = new List <WTPowerForecastResult>()
                };
            }
            else
            {
                results = new WTPowerResultSet {
                    powerResults = new List <WTPowerResult>()
                };
            }

            foreach (WTInfo powerInfo in predictionInputs.PowerInputs)
            {
                if (allInfo)
                {
                    results.powerForecastResults.Add(new WTPowerForecastResult
                    {
                        OriginSysTime = powerInfo.OriginSysTime,
                        Power_DM      = (float)PredictionPowerDMSet.result[iterator],
                        Power_PM      = (float)PredictionPowerPMSet[iterator],
                        WindDir       = powerInfo.WindDir,
                        WindSpeed     = powerInfo.WindSpeed,
                        YawPosition   = powerInfo.YawPosition
                    });
                }
                else
                {
                    results.powerResults.Add(new WTPowerResult
                    {
                        OriginSysTime = powerInfo.OriginSysTime,
                        Power_DM      = (float)PredictionPowerDMSet.result[iterator],
                        Power_PM      = (float)PredictionPowerPMSet[iterator],
                    });
                }


                ++iterator;
            }

            return(results);
        }
        public static async Task <IActionResult> HttpTriggerPrediction(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)]
            HttpRequest req, ILogger log)
        {
            log.LogInformation("Power Prediction HTTP trigger function processed a request.");

            try
            {
                // We'll check if there's a body first - prioritize manual prediction
                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
                if (requestBody.Length > 0)
                {
                    // Manual request test, Example request body:

                    /*
                     * {
                     *  "PowerInputs": [{
                     *      "Blade1PitchPosition": 1.99,
                     *      "Blade2PitchPosition": 2.02,
                     *      "Blade3PitchPosition": 1.92,
                     *      "OriginSysTime": "7/29/2018 11:43:00",
                     *      "WindDir": -8.6,
                     *      "WindSpeed": 6.66,
                     *      "YawPosition": 5.05
                     *  },{
                     *      "Blade1PitchPosition": 3.1,
                     *      "Blade2PitchPosition": 2.1,
                     *      "Blade3PitchPosition": 1.2,
                     *      "OriginSysTime": "7/29/2018 11:43:01",
                     *      "WindDir": -8.6,
                     *      "WindSpeed": 6.66,
                     *      "YawPosition": 5.05
                     *  }]
                     * }
                     */
                    WTPowerRequestInfo data = JsonConvert.DeserializeObject <WTPowerRequestInfo>(requestBody);
                    WTPowerResultSet   manualPowerResults = await getPredictedPower(data);

                    return((ActionResult) new OkObjectResult(manualPowerResults));
                }
                // If no body is present, assume prediction for next day.
                else
                {
                    using (HttpClient client = new HttpClient())
                    {
                        HttpResponseMessage response = await client.GetAsync("http://iot-model-api.koreacentral.azurecontainer.io/api/predictiondata");

                        if (response.IsSuccessStatusCode)
                        {
                            IDictionary <string, string> urlParams = req.GetQueryParameterDictionary();
                            int steps = interpolationSteps;
                            if (urlParams.ContainsKey("steps"))
                            {
                                // Let's keep steps to a low number to avoid too much data.
                                if (steps > 0 && steps <= 50)
                                {
                                    steps = Int32.Parse(urlParams["steps"]);
                                }
                            }

                            string result = await response.Content.ReadAsStringAsync();

                            // Example data.

                            /*
                             * string predictionRequest = "[" +
                             *  " {'forecastDateTime':'" + tomorrow + "T00:00:00','windspeed':5.9,'winddirection':-1,'yawposition':-131.48,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}," +
                             *  " {'forecastDateTime':'" + tomorrow + "T03:00:00','windspeed':6.8,'winddirection':3,'yawposition':-109.37,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}," +
                             *  " {'forecastDateTime':'" + tomorrow + "T06:00:00','windspeed':6.3,'winddirection':5,'yawposition':-104.41,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}," +
                             *  " {'forecastDateTime':'" + tomorrow + "T09:00:00','windspeed':5.9,'winddirection':5,'yawposition':-104.41,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}," +
                             *  " {'forecastDateTime':'" + tomorrow + "T12:00:00','windspeed':6.9,'winddirection':2,'yawposition':-109.37,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}," +
                             *  " {'forecastDateTime':'" + tomorrow + "T15:00:00','windspeed':7.1,'winddirection':-4,'yawposition':-131.48,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}," +
                             *  " {'forecastDateTime':'" + tomorrow + "T18:00:00','windspeed':6.8,'winddirection':-4,'yawposition':-131.48,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}," +
                             *  " {'forecastDateTime':'" + tomorrow + "T21:00:00','windspeed':6.8,'winddirection':-3,'yawposition':-131.48,'bladepitch1':2,'bladepitch2':2,'bladepitch3':2}" +
                             * " ]";
                             */

                            dynamic forecastData = JsonConvert.DeserializeObject(result);

                            WTPowerRequestInfo predictionInput = new WTPowerRequestInfo {
                                PowerInputs = new List <WTInfo>()
                            };

                            for (int i = 0; i < forecastData.Count; ++i)
                            {
                                // Interpolation occurs here, we add *interpolationSteps* additional points between each data point.
                                for (int j = 0; j < steps; ++j)
                                {
                                    // We only do one step for last data point.
                                    if (j > 0 && i == forecastData.Count - 1)
                                    {
                                        break;
                                    }
                                    DateTime d1 = DateTime.Parse((string)forecastData[i].forecastDateTime);
                                    DateTime interpolatedDate = d1;

                                    float yawPositionCurrent = forecastData[i].yawposition;
                                    float interpolatedYaw    = yawPositionCurrent;

                                    float windSpeedCurrent      = forecastData[i].windspeed;
                                    float interpolatedWindSpeed = windSpeedCurrent;

                                    float windDirectionCurrent      = forecastData[i].winddirection;
                                    float interpolatedWindDirection = windDirectionCurrent;

                                    // No data to interpolate to on last data point.
                                    if (i != forecastData.Count - 1)
                                    {
                                        // Date has a unique interpolation.
                                        DateTime d2                 = DateTime.Parse((string)forecastData[i + 1].forecastDateTime);
                                        TimeSpan timeDiff           = (d2 - d1);
                                        var      timeStepDifference = timeDiff / (steps);
                                        var      minutesElapsed     = timeStepDifference * j;
                                        interpolatedDate = d1.AddMinutes(minutesElapsed.TotalMinutes);

                                        int   next            = i + 1;
                                        float yawPositionNext = forecastData[next].yawposition;
                                        interpolatedYaw = interpolateData(yawPositionCurrent, yawPositionNext, j, steps);

                                        float windSpeedNext = forecastData[next].windspeed;
                                        interpolatedWindSpeed = interpolateData(windSpeedCurrent, windSpeedNext, j, steps);

                                        float windDirectionNext = forecastData[next].winddirection;
                                        interpolatedWindDirection = interpolateData(windDirectionCurrent, windDirectionNext, j, steps);
                                    }

                                    // No need to interpolate blade angles since they remain constant.
                                    predictionInput.PowerInputs.Add(new WTInfo
                                    {
                                        Blade1PitchPosition = forecastData[i].bladepitch1,
                                        Blade2PitchPosition = forecastData[i].bladepitch2,
                                        Blade3PitchPosition = forecastData[i].bladepitch3,
                                        OriginSysTime       = interpolatedDate.ToString(),
                                        WindDir             = interpolatedWindDirection,
                                        WindSpeed           = interpolatedWindSpeed,
                                        YawPosition         = interpolatedYaw
                                    });
                                }
                            }

                            WTPowerResultSet predictedPowerResults;

                            if (urlParams.ContainsKey("alldata"))
                            {
                                predictedPowerResults = await getPredictedPower(predictionInput, true);

                                return((ActionResult) new OkObjectResult(predictedPowerResults.powerForecastResults));
                            }
                            else
                            {
                                predictedPowerResults = await getPredictedPower(predictionInput);

                                return((ActionResult) new OkObjectResult(predictedPowerResults.powerResults));
                            }
                        }
                        else
                        {
                            return(null); // new BadRequestObjectResult(response.Content);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                return(new BadRequestObjectResult(e.ToString()));
            }
        }