/// <summary>
        /// reads a country's EM2 country- and dataconfig-XML-files and transfers them to EM3 style
        /// creates the country folder, if it does not exist, and overwrites any existing country file
        /// note: the intended usage is "single country transformation"
        ///       the EM3All class is responsible for complete EM-content transformation (using the EM3Country.Write function)
        /// </summary>
        /// <param name="emPath"> EuromodFiles folder (containing EM2-files in XMLParam and (will contain) EM3-files in EM3Translation\XMLParam) </param>
        /// <param name="country"> short-name of country </param>
        /// <param name="errors"> critical and non-critical erros during the transformation-process, empty structure for no errors </param>
        public static bool Transform(string emPath, string country, out List <string> errors)
        {
            errors = new List <string>(); EMPath pathHandler = new EMPath(emPath);
            string em2CountryFile = string.Empty, em2DataFile = string.Empty;

            try
            {
                DirectoryInfo di = Directory.CreateDirectory(pathHandler.GetCountryFolderPath(country));

                // read EM2-files
                em2CountryFile = pathHandler.GetCountryFilePath(country: country, em2: true);
                em2DataFile    = pathHandler.GetEM2DataConfigFilePath(country);

                bool up2D1 = TransformerCommon.IsFileUpToDate(em2CountryFile, pathHandler.GetCountryFolderPath(country), out string hash1);
                bool up2D2 = TransformerCommon.IsFileUpToDate(em2DataFile, pathHandler.GetCountryFolderPath(country), out string hash2);
                if (up2D1 && up2D2)
                {
                    return(true);                // do not combine in one if, to make sure that both hash-files (for country and dataconfig) are generated
                }
                EM2Country.Content ctryContent = EM2Country.Read(em2CountryFile, out List <string> cErrors);
                EM2Data.Content    dataContent = EM2Data.Read(em2DataFile, out List <string> dErrors);
                // need the global file with policy-switches for proper transformation of local policy switches
                List <List <MultiProp> > extensions = EM2Global.ReadSwitchPol(pathHandler.GetFolderConfig(em2: true), out List <string> gErrors);
                errors.AddRange(cErrors); errors.AddRange(dErrors); errors.AddRange(gErrors);
                if (ctryContent == null || dataContent == null || extensions == null)
                {
                    return(false);
                }

                // write EM3-file (includes EM2->EM3 adaptations, via EM23Adapt class)
                string em3CountryFile = pathHandler.GetCountryFilePath(country);
                bool   success        = Write(ctryContent, dataContent, extensions, em3CountryFile, out List <string> wErrors);
                errors.AddRange(wErrors);

                if (success && errors.Count == 0)
                {
                    TransformerCommon.WriteUpToDate(em2CountryFile, pathHandler.GetCountryFolderPath(country), hash1);
                    TransformerCommon.WriteUpToDate(em2DataFile, pathHandler.GetCountryFolderPath(country), hash2);
                }

                return(success);
            }
            catch (Exception exception)
            {
                errors.Add($"{country}: {exception.Message}");
                return(false);
            }
        }
        public static bool IsUpToDate(string emPath, string country)
        {
            EMPath pathHandler = new EMPath(emPath);

            return(TransformerCommon.IsFileUpToDate(pathHandler.GetCountryFilePath(country, true), pathHandler.GetCountryFolderPath(country), out string hash1) &&
                   TransformerCommon.IsFileUpToDate(pathHandler.GetEM2DataConfigFilePath(country), pathHandler.GetCountryFolderPath(country), out string hash2));
        }
        // note: this assumes an existing EM3Translation-folder (as sub-folder of emPath) and takes only the translated countries in there into account
        public static bool GetInfoCountries(string emPath, out List <CountryInfo> countryInfo, out string errorsAndWarnings,
                                            bool getDatasets = true, bool getRunOptions = true)
        {
            errorsAndWarnings = string.Empty; countryInfo = new List <CountryInfo>();
            EMPath pathHelper = new EMPath(emPath);

            try
            {
                if (!Directory.Exists(pathHelper.GetFolderCountries()))
                {
                    errorsAndWarnings = $"Folder {pathHelper.GetFolderCountries()} not found"; return(false);
                }

                object writeLock = new object(); List <CountryInfo> localCountryInfo = new List <CountryInfo>(); string localErrors = string.Empty;
                Parallel.ForEach(new DirectoryInfo(pathHelper.GetFolderCountries()).GetDirectories(), folder =>
                {
                    lock (writeLock)
                    {
                        if (GetInfoCountry(pathHelper.GetCountryFilePath(folder.Name), out CountryInfo ci, out string error, getDatasets, getRunOptions))
                        {
                            localCountryInfo.Add(ci);
                        }
                        else
                        {
                            localErrors += error + Environment.NewLine;
                        }
                    }
        /// <summary> reads all components of an EM2 version </summary>
        /// <param name="emPath"> path to EUROMOD version (e.g. C:\euromod\EuromodContent\EuromodFiles_H0.13\) </param>
        /// <param name="errors"> list of errors, only critical errors lead to failure-return (null), i.e. there may be errors on "success"</param>
        /// <param name="progressAction">
        /// optional function for progress reporting, in the form 'void funName(string message)'
        /// is called for each item (country, add-on, global file) and sets message to e.g. 'Finished reading ...', 'Failed reading ...'
        /// </param>
        /// <param name="cancelSrc"> optional cancellation item </param>
        /// <returns> Content structure upon success, null upon failure </returns>
        public static Content Read(string emPath, out List <string> errors,
                                   Action <string> progressAction = null, CancellationTokenSource cancelSrc = null)
        {
            Content       content = new Content();
            List <string> _errors = new List <string>();

            object          writeLock       = new object();
            ParallelOptions parallelOptions = new ParallelOptions();

            if (cancelSrc != null)
            {
                parallelOptions.CancellationToken = cancelSrc.Token;
            }

            try
            {
                EMPath pathHandler = new EMPath(emPath);

                // READ COUNTRIES IN PARALLEL
                Parallel.ForEach(new DirectoryInfo(pathHandler.GetFolderCountries(em2: true)).GetDirectories(), parallelOptions, folder =>
                {
                    parallelOptions.CancellationToken.ThrowIfCancellationRequested();

                    string ctryFileName = pathHandler.GetCountryFilePath(country: folder.Name, em2: true);
                    string dataFileName = pathHandler.GetEM2DataConfigFilePath(country: folder.Name);

                    EM2Country.Content c = EM2Country.Read(ctryFileName, out List <string> cErrors);
                    EM2Data.Content d    = EM2Data.Read(dataFileName, out List <string> dErrors);

                    bool success = c != null && d != null;
                    lock (writeLock)
                    {
                        if (success)
                        {
                            content.countries.Add(new CountryContent()
                            {
                                country = c, data = d
                            });
                        }
                        _errors.AddRange(cErrors); _errors.AddRange(dErrors);
                    }
                    ReportSuccess(folder.Name, success, cErrors.Count + dErrors.Count);
                });
                // the rest is read sequentially (parallel would be unnecessary overhead)

                // READ ADD-ONS
                foreach (DirectoryInfo folder in new DirectoryInfo(pathHandler.GetFolderAddOns(em2: true)).GetDirectories())
                {
                    if ((new List <string>()
                    {
                        "HypoData", "SumStat", "XYZ"
                    }).Contains(folder.Name))
                    {
                        continue; // that's just old stuff, I think hardcoding isn't a faux pas
                    }
                    string             aoFileName = pathHandler.GetAddOnFilePath(addOn: folder.Name, em2: true);
                    EM2Country.Content ao         = EM2Country.Read(aoFileName, out List <string> aoErrors);
                    if (ao != null)
                    {
                        content.addOns.Add(ao);
                    }
                    _errors.AddRange(aoErrors); ReportSuccess(folder.Name, ao != null, aoErrors.Count);
                }
                ;

                // READ GLOBAL FILES
                string configPath = pathHandler.GetFolderConfig(em2: true);
                content.exRates = EM2Global.ReadExRates(configPath, out List <string> exErrors); _errors.AddRange(exErrors);
                ReportSuccess("Exchange rates", exErrors.Count == 0, exErrors.Count);
                content.hicp = EM2Global.ReadHICP(configPath, out List <string> hicpErrors); _errors.AddRange(hicpErrors);
                ReportSuccess("HICP", hicpErrors.Count == 0, hicpErrors.Count);
                content.switchPol = EM2Global.ReadSwitchPol(configPath, out List <string> spErrors); _errors.AddRange(spErrors);
                ReportSuccess("Policy switches", spErrors.Count == 0, spErrors.Count);

                // READ VARIABLES
                content.varConfig = EM2Variables.Read(configPath, out List <string> vErrors); _errors.AddRange(vErrors);
                ReportSuccess(EM2Variables.FILE_VARCONFIG, content.varConfig != null, vErrors.Count);

                return(content);
            }
            catch (OperationCanceledException) { progressAction($"Reading {emPath} cancelled!"); return(content); }
            catch (Exception exception)
            {
                lock (writeLock) { _errors.Add(exception.Message); } return(null);
            }
            finally { errors = _errors; }

            void ReportSuccess(string what, bool success, int cntErrors)
            {
                if (success)
                {
                    progressAction($"Finished reading {what} with " + $"{(cntErrors == 0 ? "success" : $"{cntErrors} errors") }");
                }
Esempio n. 5
0
        private static bool HandleExtensionSwitches(Dictionary <string, string> config, out Dictionary <string, string> modifiedExtensionSwitches)
        {
            modifiedExtensionSwitches = new Dictionary <string, string>();
            Dictionary <string, string> toReplace = new Dictionary <string, string>();

            foreach (var entry in config)
            {
                if (!entry.Key.StartsWith(TAGS.EXTENSION_SWITCH))
                {
                    continue;
                }
                string[] splitVal = entry.Value.Split("="); if (splitVal.Count() < 2)
                {
                    continue;
                }
                string extName = splitVal[0], extVal = splitVal[1];
                modifiedExtensionSwitches.Add(extName, extVal);
                if (!EM_Helpers.IsGuid(extName))
                {
                    toReplace.Add(entry.Key, extName.ToLower());
                }
            }
            if (toReplace.Count == 0)
            {
                return(true);
            }

            EMPath       pathHandler       = new EMPath(config[TAGS.CONFIG_PATH_EUROMODFILES]);
            Communicator dummyCommunicator = new Communicator();
            var          globExt           = ExeXmlReader.ReadExtensions(pathHandler.GetExtensionsFilePath(), dummyCommunicator);

            // first search in global file ...
            List <string> done = new List <string>();

            foreach (var tr in toReplace)
            {
                string extName = tr.Value, configKey = tr.Key;
                // the name of the extension must be replaced by the id:
                foreach (var e in globExt)
                {
                    string extId = e.Key, shortName = e.Value.Item1.ToLower(), longName = e.Value.Item2.ToLower();
                    if (extName == shortName || extName == longName)
                    {
                        Replace(configKey, extId); break;
                    }
                }
            }
            // ... if any extension-name was not found in global file, search in country file
            if (done.Count == toReplace.Count)
            {
                return(true);
            }
            ExeXml.Country country = ExeXmlReader.ReadCountry(pathHandler.GetCountryFilePath(config[TAGS.CONFIG_COUNTRY]),
                                                              config[TAGS.CONFIG_ID_SYSTEM], config[TAGS.CONFIG_ID_DATA], false, dummyCommunicator);
            foreach (var tr in toReplace)
            {
                string extName = tr.Value, configKey = tr.Key;
                if (done.Contains(configKey))
                {
                    continue;
                }
                foreach (var e in from ce in country.extensions where ce.Value.localShortName != null select ce)
                {
                    string extId = e.Key, shortName = e.Value.localShortName.ToLower(),
                             longName = e.Value.localLongName; if (longName != null)
                    {
                        longName = longName.ToLower();
                    }
                    if (extName == shortName || extName == longName)
                    {
                        Replace(configKey, extId); break;
                    }
                }
            }

            if (done.Count == toReplace.Count)
            {
                return(true);
            }

            string notDone = string.Empty; foreach (var tr in toReplace)

            {
                if (!done.Contains(tr.Key))
                {
                    notDone += tr.Value + " ";
                }
            }

            Console.WriteLine($"Unknown extension(s): {notDone}");
            return(false);

            void Replace(string configKey, string extId)
            {
                config[configKey] = $"{extId}={config[configKey].Split("=")[1]}"; done.Add(configKey);
            }
        }
        internal static int GoPet(string[] args)
        {
            try
            {
                if (args.Length < 2)
                {
                    return(WrongArgumentError());
                }

                string emPath          = EM_Helpers.RemoveQuotes(args[0].Trim());
                string country         = args[1];
                bool?  transformGlobal = EM_Helpers.GetBool(args[2]);

                // other than for the UI-call, the country-files are saved in the temp-folder, thus we cannot call the standard EM3Country.Transform, etc.
                // as a solution (which is considered to be temporary and therefore should touch other code as less as possible)
                // we do "by hand read-write" (see below) and create an EM3Translation-folder in the temp-folder from where we start the PET-runs

                // here we have the information: EM2 country-file (in temp-folder) and global-files (in config-folder)
                EMPath em2PathHandler = new EMPath(emPath);
                // here we write the EM3 files in a structure the EM3-exe can process, i.e. we create EM3Translation-folder in temp-folder
                EMPath transPathHandler = new EMPath(em2PathHandler.GetFolderTemp());

                List <string> errors  = new List <string>();
                bool          success = TransformCountry() && (transformGlobal == false || (TransformGlobals() && TransformVariables()));
                foreach (string error in errors)
                {
                    Console.Error.WriteLine(error);
                }
                return(success ? 0 : 1);

                bool TransformCountry()
                {
                    // read EM2-files
                    string ccPath = Path.Combine(em2PathHandler.GetFolderTemp(), EMPath.GetCountryFileName(country));
                    string dcPath = Path.Combine(em2PathHandler.GetFolderTemp(), EMPath.GetEM2DataConfigFileName(country));

                    EM2Country.Content       ctryContent = EM2Country.Read(ccPath, out List <string> _errors); errors.AddRange(_errors);
                    EM2Data.Content          dataContent = EM2Data.Read(dcPath, out _errors); errors.AddRange(_errors);
                    List <List <MultiProp> > extensions  = EM2Global.ReadSwitchPol(em2PathHandler.GetFolderConfig(em2: true), out _errors); errors.AddRange(_errors);

                    if (ctryContent == null || dataContent == null || extensions == null)
                    {
                        return(false);
                    }

                    // write EM3-file
                    DirectoryInfo di             = Directory.CreateDirectory(transPathHandler.GetCountryFolderPath(country));
                    string        em3CountryFile = transPathHandler.GetCountryFilePath(country);
                    bool          ok             = EM3Country.Write(ctryContent, dataContent, extensions, em3CountryFile, out _errors); errors.AddRange(_errors);

                    return(ok);
                }

                bool TransformGlobals()
                {
                    // read EM2-files
                    List <List <MultiProp> > exRates  = EM2Global.ReadExRates(em2PathHandler.GetFolderConfig(em2: true), out List <string> _errors); errors.AddRange(_errors);
                    List <List <MultiProp> > hicp     = EM2Global.ReadHICP(em2PathHandler.GetFolderConfig(em2: true), out _errors); errors.AddRange(_errors);
                    List <List <MultiProp> > switches = EM2Global.ReadSwitchPol(em2PathHandler.GetFolderConfig(em2: true), out _errors); errors.AddRange(_errors);

                    // transfer to EM3-structure
                    bool ok = true;

                    try
                    {
                        DirectoryInfo di = Directory.CreateDirectory(transPathHandler.GetFolderConfig());
                        if (!EM3Global.WriteExRates(exRates, transPathHandler.GetFolderEuromodFiles(), out _errors))
                        {
                            ok = false;
                        }
                        errors.AddRange(_errors);
                        if (!EM3Global.WriteHICP(hicp, transPathHandler.GetFolderEuromodFiles(), out _errors))
                        {
                            ok = false;
                        }
                        errors.AddRange(_errors);
                        if (!EM3Global.WriteExtensions(switches, transPathHandler.GetFolderEuromodFiles(), out _errors))
                        {
                            ok = false;
                        }
                        errors.AddRange(_errors);
                    }
                    catch { } // this is a primitive way for provide thread-security, as more than one PETs may be started
                    return(ok);
                }

                bool TransformVariables()
                {
                    // read EM2-file
                    EM2Variables.Content content = EM2Variables.Read(em2PathHandler.GetFolderConfig(em2: true), out List <string> _errors); errors.AddRange(_errors);
                    if (content == null)
                    {
                        return(false);
                    }

                    // transfer to EM3-structure
                    try
                    {
                        DirectoryInfo di = Directory.CreateDirectory(transPathHandler.GetFolderConfig());
                        bool          ok = EM3Variables.Write(content, transPathHandler.GetFolderEuromodFiles(), out _errors); errors.AddRange(_errors);
                        return(ok);
                    }
                    catch { return(true); } // see above
                }
            }
            catch (Exception exception)
            {
                Console.Error.WriteLine("EUROMOD3 TRANSFORM: " + exception.Message);
                return(1);
            }

            int WrongArgumentError()
            {
                string actArgs = string.Empty; foreach (string arg in args)

                {
                    actArgs += arg + " ";
                }

                Console.Error.WriteLine("EUROMOD3 TRANSFORM: invalid use. Correct: EM_ExecutableCaller UI_TRANSFORM_PET emPath 0/1 cc [ao1[|ao2|...|aoN]]" +
                                        Environment.NewLine + $"Acutal use: EM_ExecutableCaller TRANSFORM {actArgs}");
                return(1);
            }
        }
Esempio n. 7
0
        /// <summary> note: this is a private function, exclusively called by EM3All.Transform, just for reasons of clearer arrangement </summary>
        private static bool Write(EM2All.Content content, string emPath, out List <string> errors,
                                  Action <string> report = null, CancellationTokenSource cancelSrc = null)
        {
            List <string> _errors = new List <string>();

            object          errWriteLock    = new object();
            ParallelOptions parallelOptions = new ParallelOptions();

            if (cancelSrc != null)
            {
                parallelOptions.CancellationToken = cancelSrc.Token;
            }

            try
            {
                EMPath pathHandler = new EMPath(emPath);

                // WRITE COUNTRIES IN PARALLEL
                Parallel.ForEach(content.countries, parallelOptions, country =>
                {
                    parallelOptions.CancellationToken.ThrowIfCancellationRequested();

                    string countryName = country.country.general.properties[EM2TAGS.SHORTNAME];
                    DirectoryInfo di   = Directory.CreateDirectory(pathHandler.GetCountryFolderPath(countryName));
                    bool success       = EM3Country.Write(country.country, country.data, content.switchPol,
                                                          pathHandler.GetCountryFilePath(countryName), out List <string> cErrors);
                    if (cErrors.Count > 0)
                    {
                        lock (errWriteLock) { _errors.AddRange(cErrors); }
                    }
                    ReportSuccess(countryName, success, cErrors.Count);

                    if (success && cErrors.Count == 0) // produce up2Date-files
                    {
                        TransformerCommon.WriteUpToDate(pathHandler.GetCountryFilePath(countryName, true), pathHandler.GetCountryFolderPath(countryName));
                        TransformerCommon.WriteUpToDate(pathHandler.GetEM2DataConfigFilePath(countryName), pathHandler.GetCountryFolderPath(countryName));
                    }
                });
                // the rest is written sequentially (parallel would be unnecessary overhead)

                // WRITE ADD-ONS
                foreach (var addOn in content.addOns)
                {
                    string        addOnName = addOn.general.properties[EM2TAGS.SHORTNAME];
                    DirectoryInfo di        = Directory.CreateDirectory(pathHandler.GetAddOnFolderPath(addOnName));
                    bool          success   = EM3Country.Write(addOn, null, content.switchPol,
                                                               pathHandler.GetAddOnFilePath(addOnName), out List <string> aoErrors);
                    if (aoErrors.Count > 0)
                    {
                        _errors.AddRange(aoErrors);
                    }
                    ReportSuccess(addOnName, success, aoErrors.Count);

                    // produce up2Date-file
                    if (success && aoErrors.Count == 0)
                    {
                        TransformerCommon.WriteUpToDate(pathHandler.GetAddOnFilePath(addOnName, true), pathHandler.GetAddOnFolderPath(addOnName));
                    }
                }

                // WRITE GLOBAL FILES
                if (!Directory.Exists(pathHandler.GetFolderConfig()))
                {
                    Directory.CreateDirectory(pathHandler.GetFolderConfig());
                }
                bool erSuccess = EM3Global.WriteExRates(content.exRates, emPath, out List <string> erErrors);
                ReportSuccess("Exchangerates", erSuccess, erErrors.Count); _errors.AddRange(erErrors);
                bool hicSuccess = EM3Global.WriteHICP(content.hicp, emPath, out List <string> hicErrors);
                ReportSuccess("HICP", hicSuccess, hicErrors.Count); _errors.AddRange(hicErrors);
                bool gsSuccess = EM3Global.WriteExtensions(content.switchPol, emPath, out List <string> gsErrors);
                ReportSuccess("Extensions", gsSuccess, gsErrors.Count); _errors.AddRange(gsErrors);

                // WRITE VARIABLES
                bool varSuccess = EM3Variables.Write(content.varConfig, emPath, out List <string> vErrors);
                ReportSuccess("Variables", varSuccess, vErrors.Count); _errors.AddRange(vErrors);
                if (varSuccess && vErrors.Count == 0)
                {
                    TransformerCommon.WriteUpToDate(pathHandler.GetVarFilePath(true), pathHandler.GetFolderConfig());                                   // produce up2Date-file
                }
                return(true);
            }
            catch (OperationCanceledException) { report($"Writing {emPath} cancelled!"); return(true); }
            catch (Exception exception)
            {
                lock (errWriteLock) { _errors.Add(exception.Message); }
                return(false);
            }
            finally { errors = _errors; }

            void ReportSuccess(string what, bool success, int cntErrors)
            {
                if (success)
                {
                    report($"Finished writing {what} with " + $"{(cntErrors == 0 ? "success" : $"{cntErrors} errors") }");
                }