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; 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 var itemName = "Taskmap"; var taskMapItem = await FindChildItemAsync(tiffItem.Code, 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; } } }