using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using FarmmapsApi.Models; using Google.Apis.Upload; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Linq; using static FarmmapsApi.Extensions; using static FarmmapsApiSamples.Constants; namespace FarmmapsApi.Services { public class GeneralService { private readonly ILogger _logger; private readonly FarmmapsApiService _farmmapsApiService; public GeneralService(ILogger logger, FarmmapsApiService farmmapsApiService) { _logger = logger; _farmmapsApiService = farmmapsApiService; } public async Task CreateCropfieldItemAsync(string parentItemCode, string name, int year, string fieldGeomJson, string data = "{}") { var currentYear = new DateTime(year, 1, 1); var cropfieldItemRequest = new ItemRequest() { ParentCode = parentItemCode, ItemType = CROPFIELD_ITEMTYPE, Name = name, DataDate = currentYear, DataEndDate = currentYear.AddYears(1).AddDays(-1), Data = JObject.Parse(data), Geometry = JObject.Parse(fieldGeomJson) }; return await _farmmapsApiService.CreateItemAsync(cropfieldItemRequest); } public async Task UploadDataAsync(UserRoot root, string itemType, string filePath, string itemName) { var startUpload = DateTime.UtcNow.AddSeconds(-3); var result = await _farmmapsApiService.UploadFile(filePath, root.Code, progress => _logger.LogInformation($"Status: {progress.Status} - BytesSent: {progress.BytesSent}")); if (result.Progress.Status == UploadStatus.Failed) return null; return await FindChildItemAsync(root.Code, itemType, itemName, i => i.Created >= startUpload && i.Name.ToLower().Contains(itemName.ToLower())); } public async Task UploadZipWithShapeAsync(UserRoot root, string filePath, string itemName) { var startUpload = DateTime.UtcNow; var result = await _farmmapsApiService.UploadFile(filePath, root.Code, progress => _logger.LogInformation($"Status: {progress.Status} - BytesSent: {progress.BytesSent}")); if (result.Progress.Status == UploadStatus.Failed) return null; return await FindChildItemAsync(root.Code, SHAPE_PROCESSED_ITEMTYPE, itemName, i => i.Created >= startUpload && i.Name.ToLower().Contains(itemName.ToLower())); ; } public async Task ShapeToGeotiff(Item shapeItem) { await RunAndWaitForTask(shapeItem, "vnd.farmmaps.task.shapetogeotiff"); // the parent of the shape item is now the tiff item shapeItem = await _farmmapsApiService.GetItemAsync(shapeItem.Code); return await _farmmapsApiService.GetItemAsync(shapeItem.ParentCode); } public async Task GeotiffToShape(Item tiffItem) { var taskmapRequest = new TaskRequest { TaskType = TASKMAP_TASK }; string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(tiffItem.Code, taskmapRequest); await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => { var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(tiffItem.Code, itemTaskCode); _logger.LogInformation($"Waiting on converting geotiff to shape; status: {itemTaskStatus.State}"); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); var itemTask = await _farmmapsApiService.GetTaskStatusAsync(tiffItem.Code, itemTaskCode); if (itemTask.State == ItemTaskState.Error) { _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); return null; } //the taskmap is a child of the input tiff *** Update feb 2021: it is a child of the cropfield. var itemName = "Taskmap"; var taskMapItem = await FindChildItemAsync(tiffItem.ParentCode, SHAPE_PROCESSED_ITEMTYPE, itemName); if (taskMapItem == null) { _logger.LogError("Could not find the shape taskmap as a child item under the input"); return null; } return taskMapItem; } public async Task RunAndWaitForTask(Item subjectItem, string taskIdentifier, Action configureCallback = null, int retrySeconds = 3) { var taskRequest = new TaskRequest() { TaskType = taskIdentifier }; configureCallback?.Invoke(taskRequest); var taskCode = await _farmmapsApiService.QueueTaskAsync(subjectItem.Code, taskRequest); await PollTask(TimeSpan.FromSeconds(retrySeconds), async (tokenSource) => { _logger.LogInformation($"Checking {taskIdentifier} task status"); var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(subjectItem.Code, taskCode); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); _logger.LogInformation($"{taskIdentifier} finished"); return await _farmmapsApiService.GetTaskStatusAsync(subjectItem.Code, taskCode); } public async Task FindChildItemAsync(string parentCode, string itemType, string containsName, Func filter = null, int maxTries = 10) { Item dataItem = null; int tries = 0; await PollTask(TimeSpan.FromSeconds(3), async source => { _logger.LogInformation($"Trying to get {containsName} data"); var uploadedFilesChildren = await _farmmapsApiService.GetItemChildrenAsync(parentCode, itemType); Func func = filter ?? (i => i.Name.ToLower().Contains(containsName.ToLower())); dataItem = uploadedFilesChildren.FirstOrDefault(func); if (dataItem != null || tries == maxTries) { source.Cancel(); } tries++; }); if (dataItem == null) { _logger.LogError("dataItem not found"); return null; } _logger.LogInformation($"Found {containsName} item"); return dataItem; } public async Task RunBofekTask(Item cropfieldItem) { var taskmapRequest = new TaskRequest { TaskType = BOFEK_TASK }; string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, taskmapRequest); await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => { var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); _logger.LogInformation($"Waiting on retreiving BOFEK data; status: {itemTaskStatus.State}"); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); if (itemTask.State == ItemTaskState.Error) { _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); return null; } //the BOFEK data is a child of the cropfield var itemName = "bofek"; var bofekItem = await FindChildItemAsync(cropfieldItem.Code, SHAPE_PROCESSED_ITEMTYPE, itemName); if (bofekItem == null) { _logger.LogError("Could not find the BOFEK data as a child item under the cropfield"); return null; } return bofekItem; } public async Task RunAhnTask(Item cropfieldItem) { var taskmapRequest = new TaskRequest { TaskType = AHN_TASK }; string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, taskmapRequest); await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => { var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); _logger.LogInformation($"Waiting on retreiving AHN data; status: {itemTaskStatus.State}"); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); if (itemTask.State == ItemTaskState.Error) { _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); return null; } //the AHN data is a child of the cropfield var itemName = "ahn"; var ahnItem = await FindChildItemAsync(cropfieldItem.Code, GEOTIFF_PROCESSED_ITEMTYPE, itemName); if (ahnItem == null) { _logger.LogError("Could not find the AHN data as a child item under the cropfield"); return null; } return ahnItem; } public async Task RunShadowTask(Item cropfieldItem) { var taskmapRequest = new TaskRequest { TaskType = SHADOW_TASK }; string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, taskmapRequest); await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => { var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); _logger.LogInformation($"Waiting on calculation shadow data; status: {itemTaskStatus.State}"); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); if (itemTask.State == ItemTaskState.Error) { _logger.LogError($"Something went wrong with task execution: {itemTask.Message}"); return null; } //the shadow data is a child of the cropfield var itemName = "shadow"; var shadowItem = await FindChildItemAsync(cropfieldItem.Code, GEOTIFF_PROCESSED_ITEMTYPE, itemName); if (shadowItem == null) { _logger.LogError("Could not find the shadow data as a child item under the cropfield"); return null; } return shadowItem; } public async Task RunSatelliteTask(Item cropfieldItem) { _logger.LogInformation("Gathering satellite information for cropfield, this might take a while!"); var taskmapRequest = new TaskRequest { TaskType = SATELLITE_TASK }; string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, taskmapRequest); await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => { var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); _logger.LogInformation($"Waiting on satellite data; status: {itemTaskStatus.State}"); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); if (itemTask.State == ItemTaskState.Error) { _logger.LogError($"Something went wrong when trying to process satellite data; {itemTask.Message}"); } return itemTask.Code; } public async Task FindSatelliteItem(Item cropfieldItem, string satelliteTaskCode, string FieldName, bool StoreStatistics) { var taskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, satelliteTaskCode); // find ndvi or wdvi satellite data geotiffs var temporalItem = await FindChildItemAsync(cropfieldItem.Code, TEMPORAL_ITEMTYPE, "Cropfield Satellite items", item => item.SourceTask == SATELLITE_TASK && taskStatus.Finished >= item.Created && taskStatus.Finished <= item.Created.Value.AddHours(1)); if (temporalItem == null) { _logger.LogError("Temporal item not found"); } var satelliteTiffs = await _farmmapsApiService.GetItemChildrenAsync(temporalItem.Code); _logger.LogInformation("Available satellite images:"); var count = 0; TimeSpan.FromSeconds(0.5); foreach (var item in satelliteTiffs) { Console.WriteLine($"Satellite image #{count}: {item.DataDate}"); count++; } _logger.LogInformation("Enter satellite image number for NBS application"); int elment = Int32.Parse(Console.ReadLine()); var selectedSatelliteItem = satelliteTiffs[elment]; if (selectedSatelliteItem == null) { _logger.LogError("Satellite item not found"); } return selectedSatelliteItem; } //VanDerSat public async Task RunVanDerSatTask(Item cropfieldItem) { _logger.LogInformation("Gathering VanDerSat information for cropfield, this might take a while!"); var taskmapRequest = new TaskRequest { TaskType = VANDERSAT_TASK }; string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, taskmapRequest); await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => { var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); _logger.LogInformation($"Waiting on VanDerSat data; status: {itemTaskStatus.State}"); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); if (itemTask.State == ItemTaskState.Error) { _logger.LogError($"Something went wrong when trying to process VanDerSat data; {itemTask.Message}"); } return itemTask.Code; } public async Task RunWatBalTask(Item cropfieldItem) { _logger.LogInformation("Gathering WatBal information for cropfield, this might take a while!"); var taskmapRequest = new TaskRequest { TaskType = WATBAL_TASK }; string itemTaskCode = await _farmmapsApiService.QueueTaskAsync(cropfieldItem.Code, taskmapRequest); await PollTask(TimeSpan.FromSeconds(5), async (tokenSource) => { var itemTaskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); _logger.LogInformation($"Waiting on VanDerSat data; status: {itemTaskStatus.State}"); if (itemTaskStatus.IsFinished) tokenSource.Cancel(); }); var itemTask = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, itemTaskCode); if (itemTask.State == ItemTaskState.Error) { _logger.LogError($"Something went wrong when trying to process WatBal data; {itemTask.Message}"); } return itemTask.Code; } public async Task FindVanDerSatItem(Item cropfieldItem, string VanDerSatTaskCode, string FieldName, bool StoreStatistics) { var taskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, VanDerSatTaskCode); // find VanDerSat data temporal var temporalItem = await FindChildItemAsync(cropfieldItem.Code, TEMPORAL_ITEMTYPE, "Van der Sat"); if (temporalItem == null) { _logger.LogError("Temporal item not found"); } var VanDerSatiffs = await _farmmapsApiService.GetItemChildrenAsync(temporalItem.Code); _logger.LogInformation("Available VanDerSat images:"); var count = 0; TimeSpan.FromSeconds(0.5); foreach (var item in VanDerSatiffs) { //Console.WriteLine($"Van der Sat image #{count}: {item.DataDate}"); //if (count == 0 ) { // Console.WriteLine($"vandersat image #{count}: {item.Data}"); //} if (StoreStatistics == true) { var VanDerSatBand = item.Data["layers"][0]["name"]; var VanderSatFile = $"C:\\Akkerweb\\{FieldName}_{VanDerSatBand}.csv"; var NewLineField = $"Field,Date,Mean,Min,Max,Standard deviation, ConfidenceInterval low, ConfidenceInterval high" + Environment.NewLine; if (count == 0) { File.AppendAllText(VanderSatFile, NewLineField); var numbervandersat = VanDerSatiffs.Count; Console.WriteLine($"{numbervandersat} Van der Sat images found"); } var VanderSatStatistics = item.Data["layers"][0]["renderer"]["band"]["statistics"]; var VanDerSatImageDate = (DateTime)item.DataDate; var VanderSatDate = VanDerSatImageDate.ToString("yyyy-MM-dd"); var NewLineDate = $"\"date\":{VanderSatDate}" + Environment.NewLine; if (VanderSatStatistics == null) { Console.WriteLine($"{VanderSatDate} no statistics found"); //Console.WriteLine($"Available data: {item.Data}"); } else { File.AppendAllText(VanderSatFile, $"{FieldName},{VanderSatDate},{VanderSatStatistics["mean"]},{VanderSatStatistics["min"]},{VanderSatStatistics["max"]},{VanderSatStatistics["stddev"]},{VanderSatStatistics["confidenceIntervalLow"]},{VanderSatStatistics["confidenceIntervalHigh"]}" + Environment.NewLine); } } count++; } //_logger.LogInformation("Enter VanDerSat image number"); //int element = Int32.Parse(Console.ReadLine()); int element = 0; var selectedVanDerSatItem = VanDerSatiffs[element]; if (selectedVanDerSatItem == null) { _logger.LogError("VanDerSat item not found"); } return selectedVanDerSatItem; } public async Task FindWatBalItem(Item cropfieldItem, string WatBalTaskCode, string FieldName, bool StoreStatistics) { var taskStatus = await _farmmapsApiService.GetTaskStatusAsync(cropfieldItem.Code, WatBalTaskCode); // find WatBal data temporal var temporalItem = await FindChildItemAsync(cropfieldItem.Code, TEMPORAL_ITEMTYPE, "WatBal");//, item => item.SourceTask == VANDERSAT_TASK && // taskStatus.Finished >= item.Created && // taskStatus.Finished <= item.Created.Value.AddHours(1)); if (temporalItem == null) { _logger.LogError("Temporal item not found"); } var WatBalData = await _farmmapsApiService.GetItemChildrenAsync(temporalItem.Code); _logger.LogInformation("Available WatBal Data:"); var count = 0; TimeSpan.FromSeconds(0.5); foreach (var item in WatBalData) { Console.WriteLine($"WatBal data #{count}: {item.DataDate}"); if (count == 0) { Console.WriteLine($"WatBalData #{count}: {item.Data}"); } count++; } int element = 0; var selectedWatBalItem = WatBalData[element]; if (selectedWatBalItem == null) { _logger.LogError("WatBal item not found"); } return selectedWatBalItem; } } }