/// <summary> /// Gets Product Information Database (PID) from Veterinary Medicines Directorate (VMD) /// </summary> /// <param name="options"><see cref="PidFactoryOptions"/>Options for processing and storage of PID</param> /// <returns></returns> public static async Task <VMDPID> GetVmdPid(PidFactoryOptions options = PidFactoryOptions.None) { if (_vmdpid != null) { return(_vmdpid); } var pidUpdated = false; //do we have an in-memory copy? if (_vmdpid == null || (options & PidFactoryOptions.OverrideCachedCopy) != 0) { //is there one available on disk? var pidDeserialiseSuccess = false; if ((options & PidFactoryOptions.PersistentPid) != 0) { pidDeserialiseSuccess = GetPidFromDisk(); // ReSharper disable once PossibleNullReferenceException if (pidDeserialiseSuccess && await GetPidUpdateDate() > _vmdpid.CreatedDateTime) { _vmdpid = await GetPidFromVmd(); pidUpdated = true; _cachedCopyOptions = options; } } if (!pidDeserialiseSuccess) { _vmdpid = await GetPidFromVmd(); pidUpdated = true; _cachedCopyOptions = options; } } //process target species options if ((options & PidFactoryOptions.GetTargetSpeciesForExpiredVmdProduct) != 0 && ((_cachedCopyOptions & PidFactoryOptions.GetTargetSpeciesForExpiredVmdProduct) == 0 || pidUpdated) ) { _vmdpid = await PopulateExpiredProductTargetSpecies(_vmdpid); } if ((options & PidFactoryOptions.GetTargetSpeciesForExpiredEmaProduct) != 0 && ((_cachedCopyOptions & PidFactoryOptions.GetTargetSpeciesForExpiredEmaProduct) == 0) || pidUpdated) { _vmdpid = await PopulateExpiredProductTargetSpeciesFromEma(_vmdpid); } //persist new copy if ((options & PidFactoryOptions.PersistentPid) != 0 && pidUpdated) { Serialize(_vmdpid); } return(_vmdpid); }
/// <summary> /// Writes <see cref="VMDPID"/> to temp file defined in _tf in binary format /// </summary> /// <param name="pid"></param> private static void Serialize(VMDPID pid) { using (var fs = File.Open(TempFile, FileMode.Create, FileAccess.Write)) { Formatter.Serialize(fs, pid); } }
/// <summary> /// Downloads SPC documents from VMD website for <see cref="ExpiredProduct"/>s, then uses /// <see cref="SPCParser"/> to extract target species /// </summary> /// <param name="inpid"></param> /// <returns>Provided <see cref="VMDPID"/> with populated target species for expired products</returns> private static async Task <VMDPID> PopulateExpiredProductTargetSpecies(VMDPID inpid) { var expiredProducts = new ConcurrentBag <ExpiredProduct>(inpid.ExpiredProducts.Where( ep => ep.SPC_Link.ToLower().EndsWith(".doc") || ep.SPC_Link.ToLower().EndsWith(".docx"))); var tasks = expiredProducts.Select(async ep => await PopulateTargetSpecies(ep)); await Task.WhenAll(tasks); inpid.ExpiredProducts = inpid.ExpiredProducts.Where(ep => !(ep.SPC_Link.ToLower().EndsWith(".doc") || ep.SPC_Link.ToLower().EndsWith(".docx"))) .Union(expiredProducts).ToList(); return(inpid); }
/// <summary> /// Tries to deserialise VMDPID from temp file into _vmdpid /// </summary> /// <returns>Success</returns> private static bool GetPidFromDisk() { if (!File.Exists(TempFile) || new FileInfo(TempFile).Length == 0) { return(false); } using (var fs = File.OpenRead(TempFile)) { try { _vmdpid = (VMDPID)Formatter.Deserialize(fs); } catch (Exception) { return(false); } } return(true); }
/// <summary> /// Uses <see cref="EPARTools"/> to ascertain which <see cref="ExpiredProduct"/>s in a <see cref="VMDPID"/> are /// EMA-authorised, search for an SPC document on the EMA website (as no direct links to documents /// are provided in the PID) and then uses <see cref="SPCParser"/> to extract a dictionary of /// products and target species. The product in question is matched to this dictionary by name. /// </summary> /// <param name="inpid"></param> /// <returns>The provided <see cref="VMDPID"/> with EMA-authorised expired products' target species populated</returns> private static async Task <VMDPID> PopulateExpiredProductTargetSpeciesFromEma(VMDPID inpid) { var expiredProducts = new ConcurrentBag <ExpiredProduct>(inpid.ExpiredProducts.Where( ep => EPARTools.IsEPAR(ep.SPC_Link))); var tasks = expiredProducts.Select(async ep => await PopulateTargetSpeciesFromEma(ep)); await Task.WhenAll(tasks); inpid.ExpiredProducts = inpid.ExpiredProducts.Where(ep => !EPARTools.IsEPAR(ep.SPC_Link)) .Union(expiredProducts).ToList(); return(inpid); }
/// <summary> /// Converts autogen-from-xsd (VMD_PIDProducts.xsd) /// class hierarchy into clean human-created one /// </summary> /// <param name="raw">As-parsed VMDPID_Raw</param> /// <param name="createdDateTime">Created DateTime from xml comment</param> /// <returns>Instance of VMDPID containing cleaned data from raw</returns> private static VMDPID CleanAndParse(VMDPID_Raw raw, DateTime?createdDateTime) { var output = new VMDPID { //TODO: refactor repetitive product processing logic CurrentlyAuthorisedProducts = raw.CurrentAuthorisedProducts.Select(rcp => new CurrentlyAuthorisedProduct { ActiveSubstances = rcp.ActiveSubstances.Split(',').Select(a => a.Trim().ToLowerInvariant()).ToArray(), AuthorisationRoute = rcp.AuthorisationRoute.Trim().ToLowerInvariant(), ControlledDrug = rcp.ControlledDrug, DateOfIssue = rcp.DateOfIssue, DistributionCategory = rcp.DistributionCategory.Trim().ToLowerInvariant(), //remove stray html tags in Distributor field Distributors = rcp.Distributors.Replace("<span>", "").Split(';').Select(a => a.Trim().ToLowerInvariant()).ToArray(), MAHolder = rcp.MAHolder.Trim().ToLowerInvariant(), Name = rcp.Name.Trim().ToLowerInvariant(), PAAR_Link = rcp.PAAR_Link.Trim().ToLowerInvariant(), PharmaceuticalForm = rcp.PharmaceuticalForm.Trim().ToLowerInvariant(), SPC_Link = rcp.SPC_Link.Trim().ToLowerInvariant(), TargetSpecies = rcp.TargetSpecies.Split(',').Select(a => a.Trim().ToLowerInvariant()).ToArray(), TherapeuticGroup = rcp.TherapeuticGroup.Trim().ToLowerInvariant(), UKPAR_Link = rcp.UKPAR_Link.Trim().ToLowerInvariant(), VMNo = rcp.VMNo.Trim().ToLowerInvariant() }).ToList(), ExpiredProducts = raw.ExpiredProducts.Select(rep => new ExpiredProduct { ActiveSubstances = rep.ActiveSubstances.Split(',').Select(a => a.Trim().ToLowerInvariant()).ToArray(), AuthorisationRoute = rep.AuthorisationRoute.Trim().ToLowerInvariant(), MAHolder = rep.MAHolder.Trim().ToLowerInvariant(), Name = rep.Name.Trim().ToLowerInvariant(), SPC_Link = rep.SPC_Link.Trim().ToLowerInvariant(), VMNo = rep.VMNo.Trim().ToLowerInvariant(), DateofExpiration = rep.DateOfExpiration }).ToList(), SuspendedProducts = raw.SuspendedProducts.Select(rsp => new SuspendedProduct() { ActiveSubstances = rsp.ActiveSubstances.Split(',').Select(a => a.Trim().ToLowerInvariant()).ToArray(), AuthorisationRoute = rsp.AuthorisationRoute.Trim().ToLowerInvariant(), ControlledDrug = rsp.ControlledDrug, DateOfIssue = rsp.DateOfIssue, DistributionCategory = rsp.DistributionCategory.Trim().ToLowerInvariant(), MAHolder = rsp.MAHolder.Trim().ToLowerInvariant(), Name = rsp.Name.Trim().ToLowerInvariant(), PAAR_Link = rsp.PAAR_Link.Trim().ToLowerInvariant(), PharmaceuticalForm = rsp.PharmaceuticalForm.Trim().ToLowerInvariant(), SPC_Link = rsp.SPC_Link.Trim().ToLowerInvariant(), TargetSpecies = rsp.TargetSpecies.Split(',').Select(a => a.Trim().ToLowerInvariant()).ToArray(), TherapeuticGroup = rsp.TherapeuticGroup.Trim().ToLowerInvariant(), UKPAR_Link = rsp.UKPAR_Link.Trim().ToLowerInvariant(), VMNo = rsp.VMNo.Trim().ToLowerInvariant(), DateOfSuspension = rsp.DateOfSuspension }).ToList(), HomoeopathicProducts = raw.HomeopathicProducts.Select(rhp => new HomoeopathicProduct { ActiveSubstances = rhp.ActiveSubstances.Split(',').Select(a => a.Trim().ToLowerInvariant()).ToArray(), AuthorisationRoute = rhp.AuthorisationRoute.Trim().ToLowerInvariant(), ControlledDrug = rhp.ControlledDrug, DateOfIssue = rhp.DateOfIssue, DistributionCategory = rhp.DistributionCategory.Trim().ToLowerInvariant(), MAHolder = rhp.MAHolder.Trim().ToLowerInvariant(), Name = rhp.Name.Trim().ToLowerInvariant(), PharmaceuticalForm = rhp.PharmaceuticalForm.Trim().ToLowerInvariant(), TargetSpecies = rhp.TargetSpecies.Split(',').Select(a => a.Trim().ToLowerInvariant()).ToArray(), TherapeuticGroup = rhp.TherapeuticGroup.Trim().ToLowerInvariant(), VMNo = rhp.VMNo.Trim().ToLowerInvariant() }).ToList(), CreatedDateTime = createdDateTime ?? default(DateTime) }; foreach (var product in output.AllProducts) { PopulateStaticTypedTargetSpecies(product); } return(output); }