#pragma once #include #include #include #include "inthashmap.h" #include "oclub.h" #include #include /************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2018 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ const int baseNameLength = 64; const int baseNameLengthUTF = 96; //Has 0-clearing constructor. Must not contain any //dynamic data etc. struct RunnerDBEntryV1 { RunnerDBEntryV1(); char name[32]; int cardNo; int clubNo; char national[3]; char sex; short int birthYear; short int reserved; }; struct RunnerDBEntryV2 { // Init from old struct void init(const RunnerDBEntryV1 &dbe); RunnerDBEntryV2(); /** Binary compatible with V1*/ char name[32]; int cardNo; int clubNo; char national[3]; char sex; short int birthYear; short int reserved; /** End of V1*/ __int64 extId; }; struct RunnerDBEntryV3 { // Init from old struct RunnerDBEntryV3(); char name[56]; int cardNo; int clubNo; char national[3]; char sex; short int birthYear; short int reserved; /** End of V1*/ __int64 extId; }; struct RunnerDBEntry { // Init from old struct void init(const RunnerDBEntryV2 &dbe); void init(const RunnerDBEntryV3 &dbe); RunnerDBEntry(); // 8 it versions string getNationality() const; string getSex() const; char name[baseNameLengthUTF]; int cardNo; int clubNo; char national[3]; char sex; short int birthYear; short int reserved; /** End of V1*/ __int64 extId; bool isRemoved() const { return (reserved & 1) == 1; } void remove() { reserved |= 1; } bool isUTF() const { return (reserved & 2) == 2; } void setUTF() { reserved |= 2; } }; class RunnerDB; struct RunnerWDBEntry { private: RunnerDB *owner; size_t ix; public: // Init from old struct void init(RunnerDB *p, size_t ix); RunnerWDBEntry(); // Link to narrow DB Entry const RunnerDBEntry &dbe() const; RunnerDBEntry &dbe(); void initName() const; void recode(const RunnerDBEntry &dest) const; mutable wchar_t name[baseNameLength]; void getName(wstring &name) const; void setName(const wchar_t *name); void setNameUTF(const char *name); const wchar_t *RunnerWDBEntry::getNameCstr() const; wstring getGivenName() const; wstring getFamilyName() const; wstring getNationality() const; int getBirthYear() const {return dbe().birthYear;} wstring getSex() const; __int64 getExtId() const; void setExtId(__int64 id); bool isRemoved() const {return (dbe().reserved & 1) == 1;} void remove() {dbe().reserved |= 1;} }; typedef vector RunnerDBVector; class oDBRunnerEntry; class oClass; class oDBClubEntry; class RunnerDB { private: oEvent *oe; Table *runnerTable; Table *clubTable; static int cellEntryIndex; bool check(const RunnerDBEntry &rde) const; intkeymap runnerInEvent; /** Init name hash lazy */ void setupNameHash() const; void setupIdHash() const; void setupCNHash() const; vector rdb; vector rwdb; vector cdb; vector oRDB; // Runner card hash inthashmap rhash; // Runner id hash mutable intkeymap idhash; // Club id hash inthashmap chash; // Last known free index int freeCIx; // Name hash mutable multimap nhash; // Club name hash mutable multimap cnhash; static void canonizeSplitName(const wstring &name, vector &split); bool loadedFromServer; /** Date when database was updated. The format is YYYYMMDD */ int dataDate; /** Time when database was updated. The format is HH:MM:SS */ int dataTime; void fillClubs(vector< pair > &out) const; class ClubNodeHash { //map hash; vector index; public: void setupHash(const wstring &key, int keyOffset, int ix); void match(RunnerDB &db, set< pair > &ix, const vector &key, const wstring &skey) const; }; class RunnerClubNodeHash { protected: vector index; public: void setupHash(const wchar_t *key, int keyOffset, int ix); void match(RunnerDB &db, set< pair > &ix, const vector &key) const; }; class RunnerNodeHash : public RunnerClubNodeHash { map hash; public: // Note: Non virtual. No reference by parent type void setupHash(const wchar_t *key, int keyOffset, int ix); void match(RunnerDB &db, set< pair > &ix, const vector &key) const; }; unordered_map clubHash; unordered_map runnerHash; unordered_map runnerHashByClub; enum class AutoHashMode { Clubs, Runners, RunnerClub }; void setupAutoCompleteHash(AutoHashMode mode); static int keyFromString(const wstring &n, size_t offset) { pair key; //static_assert(sizeof(key) == sizeof int); if (n.length() == 1 + offset) { key.first = n[offset]; key.second = 0; } else if (n.length() > 1 + offset) { key.first = n[offset]; key.second = n[offset+1]; } int *ikey = static_cast((void *)&key); return *ikey; } static int keyFromString(const wchar_t *n) { pair key; if (n[0] == 0) return 0; else { key.first = n[0]; key.second = n[1]; } int *ikey = static_cast((void *)&key); return *ikey; } public: vector getClubSuggestions(const wstring &key, int limit); vector> getRunnerSuggestions(const wstring &name, int clubId, int limit); void generateRunnerTableData(Table &table, oDBRunnerEntry *addEntry); void generateClubTableData(Table &table, oClub *addEntry); void refreshRunnerTableData(Table &table); void refreshClubTableData(Table &table); void refreshTables(); Table *getRunnerTB(); Table *getClubTB(); void hasEnteredCompetition(__int64 extId); void releaseTables(); /** Get the date, YYYY-MM-DD HH:MM:SS when database was updated */ string getDataDate() const; /** Set the date YYYY-MM-DD HH:MM:SS when database was updated */ void setDataDate(const string &date); /** Returns true if the database was loaded from server */ bool isFromServer() const {return loadedFromServer;} /** Prepare for loading runner from server*/ void prepareLoadFromServer(int nrunner, int nclub); const vector& getRunnerDB() const; const vector& getRunnerDBN() const; const vector& getClubDB(bool checkProblems) const; void clearRunners(); void clearClubs(); /** Add a club. Create a new Id if necessary*/ int addClub(oClub &c, bool createNewId); RunnerWDBEntry *addRunner(const wchar_t *name, __int64 extId, int club, int card); RunnerWDBEntry *addRunner(const char *nameUTF, __int64 extId, int club, int card); oDBRunnerEntry *addRunner(); oClub *addClub(); RunnerWDBEntry *getRunnerByIndex(size_t index) const; RunnerWDBEntry *getRunnerById(__int64 extId) const; RunnerWDBEntry *getRunnerByCard(int card) const; RunnerWDBEntry *getRunnerByName(const wstring &name, int clubId, int expectedBirthYear) const; bool getClub(int clubId, wstring &club) const; oClub *getClub(int clubId) const; oClub *getClub(const wstring &name) const; void saveClubs(const wstring &file); void saveRunners(const wstring &file); void loadRunners(const wstring &file); void loadClubs(const wstring &file); void updateAdd(const oRunner &r, map &clubIdMap); void importClub(oClub &club, bool matchName); void compactifyClubs(); void getAllNames(vector &givenName, vector &familyName); RunnerDB(oEvent *); ~RunnerDB(void); friend class oDBRunnerEntry; friend class oDBClubEntry; friend struct RunnerWDBEntry; }; class oDBRunnerEntry : public oBase { private: RunnerDB *db; int index; protected: /** Get internal data buffers for DI */ oDataContainer &getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const; int getDISize() const {return 0;} void changedObject() {} public: int getIndex() const {return index;} void init(RunnerDB *db_, int index_) {db=db_, index=index_; Id = index;} const RunnerDBEntry &getRunner() const; void addTableRow(Table &table) const; bool inputData(int id, const wstring &input, int inputId, wstring &output, bool noUpdate); void fillInput(int id, vector< pair > &out, size_t &selected); oDBRunnerEntry(oEvent *oe); virtual ~oDBRunnerEntry(); void remove(); bool canRemove() const; wstring getInfo() const {return L"Database Runner";} }; class oDBClubEntry : public oClub { private: int index; RunnerDB *db; wstring canonizedName; wstring canonizedNameExact; public: void setCanonizedName(wstring &&n, wstring &&nExact) { canonizedName = n; canonizedNameExact = nExact; } const wstring &getCanonizedName() { return canonizedName; } const wstring &getCanonizedNameExact() { return canonizedNameExact; } oDBClubEntry(oEvent *oe, int id, int index, RunnerDB *db); oDBClubEntry(const oClub &c, int index, RunnerDB *db); int getTableId() const; virtual ~oDBClubEntry(); void remove(); bool canRemove() const; };