#pragma once #include "basedata.h" #include "mdatetime.h" #include "mregex.h" #include "uvdata.h" #include using michlib::BFileW; using michlib::MDateTime; using TIndex = std::vector; enum class ActionID { INFO, TSC, UV, GENINTFILE }; template struct ActionCarrier { constexpr static ActionID action = id; }; template struct IsActionSupportedTest { static constexpr bool ans = false; }; template struct IsActionSupportedTest { static constexpr bool ans = InfoSupported; }; template struct IsActionSupportedTest { static constexpr bool ans = ReadPSupported || ReadSupported; }; template struct IsActionSupportedTest { static constexpr bool ans = ReadPSupported || ReadSupported; }; template struct IsActionSupportedTest { static constexpr bool ans = ReadIsGrid; }; template constexpr bool IsActionSupported = IsActionSupportedTest::ans; using ActionVariants = std::variant, ActionCarrier, ActionCarrier, ActionCarrier>; class Action: public ActionVariants { public: Action() = default; Action(ActionVariants&& d): ActionVariants(std::move(d)) {} MString Init(const CLArgs& args) { MString act = args.contains("action") ? args.at("action") : "info"; if(act == "info") *this = ActionVariants(ActionCarrier()); else if(act == "tsc") *this = ActionVariants(ActionCarrier()); else if(act == "uv") *this = ActionVariants(ActionCarrier()); else if(act == "genintfile") *this = ActionVariants(ActionCarrier()); else return "Unknown action: " + act; return ""; } }; template struct DoAction_ { static MString DoAction(const CLArgs& args, D& data) { return "Internal error"; } }; template MString DoAction(const CLArgs& args, D& data) { return DoAction_::DoAction(args, data); } template size_t GetTIndex(const D& data, const MDateTime& t) { size_t nt = data.NTimes(); if(t <= data.Time(0)) return 0; if(t >= data.Time(nt - 1)) return nt - 1; for(size_t i = 0; i < nt - 1; i++) if(t >= data.Time(i) && t <= data.Time(i + 1)) return (t - data.Time(i) <= data.Time(i + 1) - t) ? i : (i + 1); return 0; } template std::pair GetTIndexes(const D& data, const CLArgs& args, michlib_internal::ParameterListEx& pars) { TIndex tindexes; if(args.contains("time") && (args.contains("timeb") || args.contains("timee"))) return {tindexes, "Time must be set via time parameter or timeb and timee parameter but not via both"}; if(!(args.contains("time") || (args.contains("timeb") && args.contains("timee")))) return {tindexes, "Time must be set via time parameter or timeb and timee parameter"}; if(args.contains("time")) { MString regex = args.at("time"); MDateTime time; if(time.FromString(regex)) return {TIndex(1, GetTIndex(data, time)), ""}; // Time, not regex if(regex == "BEGIN" || regex == "BEG" || regex == "FIRST") return {TIndex(1, 0), ""}; // First time if(regex == "END" || regex == "LAST") return {TIndex(1, data.NTimes() - 1), ""}; // Last time michlib::RegExpSimple reg(regex.Buf()); if(reg.Compile() != 0) return {tindexes, "Bad regular expression: " + regex}; for(size_t i = 0; i < data.NTimes(); i++) { MString date = data.Time(i).ToString(); if(reg.Match(date.Buf())) tindexes.push_back(i); } if(tindexes.size() == 0) return {tindexes, "There are no times matching the regular expression: " + regex}; if(tindexes.size() == 1) pars.SetParameter("time", data.Time(tindexes[0]).ToString()); else pars.SetParameter("timeregex", args.at("time")); } else { MString tb = args.at("timeb"); MString te = args.at("timee"); MDateTime b(tb), e(te); auto nt = data.NTimes(); if(tb == "BEGIN" || tb == "BEG") b = data.Time(0); if(te == "LAST" || te == "END") e = data.Time(nt - 1); const MDateTime& beg = (b < e) ? b : e; const MDateTime& end = (b > e) ? b : e; if(beg > data.Time(nt - 1)) return {tindexes, "Begin time " + b.ToTString() + " is greater then end time in the dataset " + data.Time(nt - 1).ToTString()}; if(end < data.Time(0)) return {tindexes, "End time " + e.ToTString() + " is lesser then begin time in the dataset " + data.Time(0).ToTString()}; size_t ib = 0, ie = nt - 1; for(size_t i = 0; i < nt; i++) if(data.Time(i) >= beg) { ib = i; break; } for(size_t i = nt; i != 0; i--) if(data.Time(i - 1) <= end) { ie = i - 1; break; } tindexes.resize(ie - ib + 1); for(size_t i = 0; i < ie - ib + 1; i++) tindexes[i] = i + ib; if(tindexes.size() == 0) return {tindexes, "There are no times between " + b.ToString() + " and " + e.ToString()}; pars.SetParameter("timeb", b.ToString()); pars.SetParameter("timee", e.ToString()); } return {tindexes, ""}; } template BaseData Read(const D& data, const MString& vname, const BaseParameters* p, const TIndex& tindex) { using RT = ReadType; size_t ind; if(tindex.size() == 1) { ind = tindex[0]; michlib::message("Time: " + data.Time(ind).ToTString()); if constexpr(ReadPSupported) return data.Read(vname, p, ind); else if constexpr(ReadSupported) return data.Read(vname, ind); } else { Averager out; bool ok = true; for(size_t i = 0; i < tindex.size(); i++) { if(!ok) break; ind = tindex[i]; michlib::message("Time: " + data.Time(ind).ToTString()); RT dat; if constexpr(ReadPSupported) dat = data.Read(vname, p, ind); else if constexpr(ReadSupported) dat = data.Read(vname, ind); if(dat) out.Add(dat); else ok = false; } if(ok) return out.Div(); } return BaseData(); } template UVData> ReadUV(const D& data, const BaseParameters* p, size_t ind) { using RT = ReadType; using UV = UVData; michlib::message("Time: " + data.Time(ind).ToTString()); RT u, v; if constexpr(ReadPSupported) { u = data.Read("u", p, ind); v = data.Read("v", p, ind); } else if constexpr(ReadSupported) { u = data.Read("u", ind); v = data.Read("v", ind); } return UV(u, v); } template UVData> ReadUV(const D& data, const BaseParameters* p, const TIndex& tindex) { using RT = ReadType; using UV = UVData; if(tindex.size() == 1) return ReadUV(data, p, tindex[0]); else { Averager out; bool ok = true; size_t ind; for(size_t i = 0; i < tindex.size(); i++) { if(!ok) break; ind = tindex[i]; michlib::message("Time: " + data.Time(ind).ToTString()); RT u, v; if constexpr(ReadPSupported) { u = data.Read("u", p, ind); v = data.Read("v", p, ind); } else if constexpr(ReadSupported) { u = data.Read("u", ind); v = data.Read("v", ind); } UV dat(u, v); if(dat) out.Add(dat); else ok = false; } if(ok) return out.Div(); } return UV(); }