256 lines
7.5 KiB
C++
256 lines
7.5 KiB
C++
#pragma once
|
|
|
|
/************************************************************************
|
|
MeOS - Orienteering Software
|
|
Copyright (C) 2009-2017 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 <http://www.gnu.org/licenses/>.
|
|
|
|
Melin Software HB - software@melin.nu - www.melin.nu
|
|
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
|
|
|
************************************************************************/
|
|
|
|
#include <set>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
#include "oEvent.h"
|
|
|
|
class oWordDatabase;
|
|
typedef oWordDatabase* pWordDatabase;
|
|
typedef map<wchar_t, pWordDatabase> MapTable;
|
|
|
|
const wchar_t indexMapStart='a';
|
|
const wchar_t indexMapEnd='z';
|
|
const int hashSplitSize=16;
|
|
const int hashTableSize=indexMapEnd-indexMapStart+1;
|
|
|
|
|
|
class oFreeImport;
|
|
|
|
class oWordDatabase {
|
|
public:
|
|
virtual char getType() const = 0;
|
|
virtual const char *deserialize(const char *bf, const char *end) = 0;
|
|
virtual char *serialize(char *bf) const = 0;
|
|
virtual int serialSize() const = 0;
|
|
virtual pWordDatabase split() {return this;}
|
|
virtual void insert(const wchar_t *s) = 0;
|
|
virtual bool lookup(const wchar_t *s) const = 0;
|
|
virtual ~oWordDatabase() = 0 {}
|
|
};
|
|
|
|
class oWordDB : public oWordDatabase {
|
|
protected:
|
|
char getType() const {return 1;}
|
|
set<wstring> str;
|
|
public:
|
|
const char *deserialize(const char *bf, const char *end);
|
|
char *serialize(char *bf) const;
|
|
int serialSize() const;
|
|
pWordDatabase split();
|
|
void insert(const wchar_t *s);
|
|
bool lookup(const wchar_t *s) const;
|
|
size_t size();
|
|
};
|
|
|
|
class oWordIndexHash : public oWordDatabase {
|
|
protected:
|
|
char getType() const {return 2;}
|
|
pWordDatabase hashTable[hashTableSize];
|
|
MapTable unMapped;
|
|
bool hashAll;
|
|
public:
|
|
const char *deserialize(const char *bf, const char *end);
|
|
char *serialize(char *bf) const;
|
|
int serialSize() const;
|
|
void insert(const wchar_t *s);
|
|
bool lookup(const wchar_t *s) const;
|
|
void clear();
|
|
~oWordIndexHash();
|
|
oWordIndexHash(bool hashAll_);
|
|
};
|
|
|
|
class oWordList {
|
|
protected:
|
|
oWordIndexHash wh;
|
|
public:
|
|
void serialize(vector<char> &serial) const;
|
|
void deserialize(const vector<char> &serial);
|
|
|
|
void save(const wstring &file) const;
|
|
void load(const wstring &file);
|
|
|
|
void insert(const wchar_t *s);
|
|
bool lookup(const wchar_t *s) const;
|
|
~oWordList();
|
|
oWordList();
|
|
};
|
|
|
|
struct oEntryPerson {
|
|
wstring name1;
|
|
wstring name2;
|
|
wstring club;
|
|
int cardNo;
|
|
void swap();
|
|
int nameCount() const;
|
|
oEntryPerson(const wstring &clb);
|
|
};
|
|
|
|
struct oEntryBlock {
|
|
// Remember clear for additional data
|
|
vector<oEntryPerson> ePersons;
|
|
wstring eClub;
|
|
wstring eClass;
|
|
bool isClassSet;
|
|
wstring eStartTime;
|
|
bool canInsertName;
|
|
int nClubsSet;
|
|
const oFreeImport &freeImporter;
|
|
|
|
int nameCount();
|
|
|
|
void setClub(const wchar_t *s);
|
|
void setClass(const wchar_t *s);
|
|
void setCardNo(int c);
|
|
void setStartTime(const wchar_t *s);
|
|
void addPerson(const wchar_t *s, bool complete);
|
|
vector<wstring> getPersons() const;
|
|
void clear(const wstring &rulingClub, const wstring &rulingClass);
|
|
|
|
// Return true if more clubs can be accepted
|
|
bool acceptMoreClubs(int expectedNumRunners) const;
|
|
|
|
bool expectMoreNames(int expectedNumRunners) const;
|
|
bool needCard() const;
|
|
bool hasClub() const {return !eClub.empty();}
|
|
/** Return true if class explicitly set. May have a ruling class anyway*/
|
|
bool hasClass() const {return isClassSet;}
|
|
bool hasStartTime() const {return !eStartTime.empty();}
|
|
bool hasName() {return !ePersons.empty() &&
|
|
!ePersons.front().name1.empty();}
|
|
void cleanEntry(); //Remove bad data.
|
|
oEntryBlock(const oFreeImport &importer);
|
|
oEntryBlock(const oEntryBlock &eb);
|
|
void operator=(const oEntryBlock &eb);
|
|
int getNumPersons() const {return ePersons.size();}
|
|
|
|
wstring getTeamName() const;
|
|
wstring getName(int k) const;
|
|
wstring getClub(int k) const;
|
|
int getCard(int k) const;
|
|
|
|
/** Make name complete */
|
|
void completeName();
|
|
};
|
|
|
|
struct MatchPattern {
|
|
short nName;
|
|
short singleName;
|
|
short nClass;
|
|
short nClub;
|
|
short nTime;
|
|
short nCard;
|
|
|
|
bool isClass(int level=2) const {return nClass>(nClub+nTime+nCard)+level;}
|
|
bool isClub(int level=2) const {return nClub>(nClass+nTime+nCard)+level;}
|
|
bool isTime(int level=2) const {return nTime>(nClass+nClub+nCard)+level;}
|
|
bool isCard(int level=2) const {return nCard>(nClass+nTime+nTime)+level;}
|
|
bool isName(int level=2) const {return nName>(nCard+nClass+nTime+nClub)+level;}
|
|
bool isCompleteName() const {return singleName<int(nName*0.8);}
|
|
MatchPattern():nClass(0), nClub(0), nTime(0),
|
|
nCard(0), nName(0), singleName(0) {}
|
|
};
|
|
|
|
class oFreeImport {
|
|
protected:
|
|
set<int> separator;
|
|
oWordList givenDB;
|
|
oWordList familyDB;
|
|
oWordList clubDB;
|
|
oWordList classDB;
|
|
|
|
enum Types {
|
|
None = -2,
|
|
Unknown = -1,
|
|
Club = 0,
|
|
Class = 1,
|
|
Time = 2,
|
|
Card = 3,
|
|
Name = 4
|
|
};
|
|
|
|
void analyzePart(wchar_t *part, const MatchPattern &ptrn, int nNamesPerPart,
|
|
oEntryBlock &entry, vector<oEntryBlock> &entries, bool allowNames);
|
|
|
|
//bool analyze(vector<bool> &b, int &offset, int &delta) const;
|
|
wchar_t *extractWord(wchar_t *&str, int &count) const;
|
|
wchar_t *extractPart(wchar_t *&str, int &wordCount) const;
|
|
wchar_t *extractLine(wchar_t *&str, int &count) const;
|
|
bool isNumber(const wchar_t *str, int &number) const;
|
|
|
|
bool isTime(const wstring &m) const;
|
|
bool isName(const wchar_t *p) const;
|
|
bool isCard(const wchar_t *p) const;
|
|
bool isCrap(const wchar_t *p) const;
|
|
|
|
bool loaded;
|
|
|
|
int preAnalyzeRow(vector<wchar_t *> &p,
|
|
const vector<MatchPattern> &ptrn,
|
|
vector<int> &classified);
|
|
|
|
// Runners per class in defined classes
|
|
map<wstring, int> runnersPerClass;
|
|
|
|
/** Must not return 0 */
|
|
int getExpectedNumRunners(const wstring &cls) const;
|
|
friend struct oEntryBlock;
|
|
|
|
/** Check if a line is a header and remove header words,
|
|
name: , class: etc. Returns true if the entire line
|
|
is header (->ignore) */
|
|
bool analyzeHeaders(vector<wchar_t *> &line) const;
|
|
|
|
/** Returns true if the given word is a header word */
|
|
bool isHeaderWord(const wstring &word) const;
|
|
|
|
mutable set<wstring> headerWords;
|
|
|
|
// Expected club for all entries
|
|
wstring rulingClub;
|
|
wstring rulingClass;
|
|
Types lastInsertedType;
|
|
public:
|
|
void load();
|
|
bool isLoaded() const {return loaded;}
|
|
void save() const;
|
|
|
|
void init(const oRunnerList &r, const oClubList &clb, const oClassList &cls);
|
|
|
|
void buildDatabases(oEvent &oe);
|
|
|
|
void extractEntries(wchar_t *bf, vector<oEntryBlock> &entries);
|
|
void showEntries(gdioutput &gdi, const vector<oEntryBlock> &entries);
|
|
void addEntries(pEvent oe, const vector<oEntryBlock> &entries);
|
|
|
|
void test(const oRunnerList &li);
|
|
oFreeImport(void);
|
|
~oFreeImport(void);
|
|
|
|
friend class oEvent;
|
|
};
|