using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Threading.Tasks; using FarmmapsApi; using FarmmapsApi.Models; using FarmmapsApi.Services; using FarmmapsDownloadCL.Models; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using static FarmmapsApiSamples.Constants; namespace FarmmapsDownloadCL { public class DownloadCLApplication : IApplication { private readonly ILogger _logger; private readonly FarmmapsApiService _farmmapsApiService; private readonly DownloadCLService _DownloadCLService; private readonly GeneralService _generalService; public readonly Dictionary> _dictCl; string _itemcode; public DownloadCLApplication(ILogger logger, FarmmapsApiService farmmapsApiService, GeneralService generalService, DownloadCLService DownloadCLService) { _logger = logger; _farmmapsApiService = farmmapsApiService; _generalService = generalService; _DownloadCLService = DownloadCLService; CodelistsClasses clc = new CodelistsClasses(); _itemcode = clc.itemcode; _dictCl = clc.dictCl; } public async Task RunAsync() { var fieldsInputJson = File.ReadAllText("DownloadCLInput.json"); DownloadCLInput clInput = JsonConvert.DeserializeObject(fieldsInputJson); // !! this call is needed the first time an api is called with a fresh clientid and secret !! await _farmmapsApiService.GetCurrentUserCodeAsync(); var roots = await _farmmapsApiService.GetCurrentUserRootsAsync(); //Where to write the output string downloadFolder = clInput.DownloadFolder; if (string.IsNullOrEmpty(downloadFolder)) { downloadFolder = "Downloads"; } if (!Directory.Exists(downloadFolder)) Directory.CreateDirectory(downloadFolder); //Get the most recent codelists foreach (string codelist in clInput.codelists) { try { await Process(roots, codelist, downloadFolder); } catch (Exception ex) { _logger.LogError(ex.Message); } } } private async Task Process(List roots, string codelistname, string downloadFolder) { List codelist; string itemtype; string className; string body; string header; string value; string[] aboutArray = null; string[] headerArray = null; PropertyInfo[] props; PropertyInfo prop; List dataList; string clJson = Path.Combine(downloadFolder, $"{codelistname}.json"); string clCsv = Path.Combine(downloadFolder, $"{codelistname}.csv"); try { itemtype = _dictCl[codelistname][0]; className = _dictCl[codelistname][1]; codelist = await _farmmapsApiService.GetItemChildrenAsync(_itemcode, itemtype); //Write full codelist in json format to clJson. body = JsonConvert.SerializeObject(codelist); File.WriteAllText(clJson, body); _logger.LogInformation($"Downloaded file {clJson}"); //Write full list in csv format to clCsv. StreamWriter sw = new StreamWriter(clCsv); //Write metadata in top: when downloaded sw.WriteLine($"Editeelt codelist {codelistname} downloaded on {DateTime.Now} with the FarmmapsDownloadCL application"); //Generic, for any Codelist as long as it is also defined in FarmmapsDownloadCL.Models in string typerequest = "FarmmapsDownloadCL.Models." + className + ", FarmmapsDownloadCL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"; Type objType = Type.GetType(typerequest); object clitem = Activator.CreateInstance(objType); props = clitem.GetType().GetProperties(); //Lookup about info and write to top foreach (PropertyInfo pi in props) { if (pi.Name == "about") { aboutArray = (string[])pi.GetValue(clitem); foreach (string about in aboutArray) { //Add quotes value = "\"" + about + "\""; //Write each about to a separate line in the csv file sw.WriteLine(value); } } } //Write an empty line sw.WriteLine(); //Look up the headerArray and write the header comma separated int i = 0; while (headerArray == null) { prop = props[i]; if (prop.Name == "headers") { headerArray = (string[])prop.GetValue(clitem); } i++; } header = string.Join(",", headerArray); sw.WriteLine(header); //Add quotes because a value for field 'description' could be '21% Cl, 16.5%CaO, 1330 g/l' and without the quotes that //would show up as separate columns. So per definition we will add quotes, except if we have a fieldname in the listNotToQuote, then value for that fieldname will not be given quotes //e.g. not code "3" but code 3. List listNotToQuote = new List() { "code", "n", "p", "k", "quantity", "cropGroupCode", "cultivationGroupCode" }; //Loop through all items in the codelist foreach (Item item in codelist) { dataList = new List { }; clitem = JsonConvert.DeserializeObject(item.Data.ToString(), objType); //Add values of the cLitem to the dataList in the same order as the header foreach (string h in headerArray) { value = (string)clitem.GetType().GetProperty(h).GetValue(clitem, null); if(listNotToQuote.Contains(h) == false) value = "\"" +value + "\""; dataList.Add(value); } string dataLine = string.Join(",", dataList); sw.WriteLine(string.Join(",", dataList)); } sw.Close(); _logger.LogInformation($"Downloaded file {clCsv}"); } catch { _logger.LogWarning($"Missing lookup information on codelist {codelistname}"); } } } }