//this file looks like plain C, but it's actually -*- c++ -*-
#ifndef __TQTaggable__
#define __TQTaggable__

#include <map> // for std::map
#include <memory> // for std::shared_ptr

#include "TList.h"
#include "TString.h"
#include "QFramework/TQValue.h"
#include "TObject.h"

class TQTaggable {

protected:

  TList * fTags;
  mutable TList * fReadFlags;//!

  bool fGlobalIgnoreCase;//!
  bool fGlobalOverwrite;//!

  int setTag(TQValue * tag, const TString& destination, bool overwrite);
  inline int setTag(TQValue * tag, const TString& destination = ""){
    return this->setTag(tag,destination,getGlobalOverwrite());
  }

  TQValue * findTag(TString name);

  bool getTag(const TString& key, TQValue * &tag);

  bool getOp(const TString& op, int &opCode);

  int countTagUp (const TString& key);
  int countTagDown(const TString& key);

  enum {
    kOpNone = 0,
    kOpRec = 1,
    kOpOR = 2,
    kOpAND = 3,
    kOpADD = 4,
    kOpMULT = 5,
    kOpCNT = 6
  };

  TList * getListOfTags();

public:

  TList* getListOfTagNames();

  static TList * makeListOfTags(TList* unTags);

  static const TString& getValidKeyCharacters();
  static bool isValidKey(const TString& key);

  static TQTaggable * parseFlags(const TString& flags);

  static TQTaggable * parseParameterList(const TString& parameter, const TString& sep = ",", bool trim = true, const TString& blocks = "", const TString& quotes = "");

  bool parseKey(TString key, TString &bareKey, int &opUp, int &opDown);

  TQTaggable();
  TQTaggable(const TString& tags);
  TQTaggable(const char* tags);
  TQTaggable(TQTaggable * tags);
  TQTaggable(const TQTaggable& tags);

  void setGlobalIgnoreCase(bool globalIgnoreCase = true);
  bool getGlobalIgnoreCase() const;

  void setGlobalOverwrite(bool globalOverwrite = true);
  bool getGlobalOverwrite() const;

  virtual void resetReadFlags();
  virtual bool hasUnreadKeys(const TString& filter = "");
  virtual TList * getListOfUnreadKeys(const TString& filter = "");

  virtual TString getFlags();

  virtual void onAccess(TQValue * tag);
  virtual void onRead(TQValue * tag);
  virtual void onWrite(TQValue * tag);

  virtual TQTaggable * getBaseTaggable() const;
  virtual TList * getDescendantTaggables();
  virtual TList * getTaggablesByName(const TString& name);
  virtual TList * getListOfTaggables(const TString& name);

  int getNTags() const;
  void printTags(TString options = "r");

  TList * getListOfKeys(const TString& filter = "");

  bool tagsAreEquivalentTo(TQTaggable * tags, const TString& filter = "");
  bool printDiffOfTags(TQTaggable * tags, const TString& options = "");
  bool printDiffOfTags(TQTaggable * tags, TQTaggable& options);

  int removeTag(const TString& key);
  int removeTags(const TString& key);
  void clear();
  int clearTags();

  bool renameTag(const TString& oldKey, const TString& newKey);
  int renameTags(const TString& oldPrefix, const TString& newPrefix);

  /* ----- write tags ----- */

  int importTag(TString tag, bool overwrite = true, bool keepStringQuotes = false);
  int importTags(TString tags, bool overwrite = true, bool keepStringQuotes = false);
  int importTags(const TQTaggable * tags, bool overwrite = true, bool recursive = false);
  int importTags(std::shared_ptr<TQTaggable> tags, bool overwrite = true, bool recursive = false);
  int importTags(const TQTaggable& tags, bool overwrite = true, bool recursive = false);

  int importTagWithPrefix (const TString& tag, const TString& prefix, bool overwrite = true, TString fallbackKey = "", bool keepStringQuotes = false);
  int importTagsWithPrefix(TString tags, const TString& prefix, bool overwrite = true, bool keepStringQuotes = false, TString fallbackKey = "");
  int importTagsWithPrefix(const TQTaggable* tags, const TString& prefix, bool overwrite = true, bool recursive = false, TString fallbackKey = "");
  int importTagsWithPrefix(const TQTaggable& tags, const TString& prefix, bool overwrite = true, bool recursive = false, TString fallbackKey = "");
  int importTagsWithoutPrefix(const TQTaggable* tags, const TString& prefix, bool overwrite = true, bool recursive = false);
  int importTagsWithoutPrefix(const TQTaggable& tags, const TString& prefix, bool overwrite = true, bool recursive = false);

  int setTagAuto(const TString& key, TString value, const TString& destination = "");

  /* these four methods do the same ... */
  int setTag (const TString& key, double value, const TString& destination = "");
  int setTag (const TString& key, int value, const TString& destination = "");
  int setTag (const TString& key, bool value, const TString& destination = "");
  int setTag (const TString& key, const TString& value, const TString& destination = "");
  int setTag (const TString& key, const char* value, const TString& destination = "");
  
  int setTag (const char* key, double value, const TString& destination = "");
  int setTag (const char* key, int value, const TString& destination = "");
  int setTag (const char* key, bool value, const TString& destination = "");
  int setTag (const char* key, const TString& value, const TString& destination = "");
  int setTag (const char* key, const char* value, const TString& destination = "");  

  /* ... like these four methods */
  int setTagDouble  (TString key, double value, const TString& destination = "");
  int setTagInteger (TString key, int value, const TString& destination = "");
  int setTagBool    (TString key, bool value, const TString& destination = "");
  int setTagString  (TString key, const TString& value, const TString& destination = "");

  // this one is a little different
  int setTagList (const TString& key, TString value, const TString& destination = "");
  template<class T> int setTagList (const TString& key, const std::vector<T>& list, const TString& destination = "");

  /* ----- check tags ----- */

  int printClaim(const TString& definition);
  int claimTags(const TString& definition, bool printErrMsg = false);
  int claimTags(const TString& definition, TString& message);
  int claimTags(const TString& definition, TString& missing, TString& invalid, TString& unexpected);

  bool hasTag (const TString& key);
  bool hasTagDouble (const TString& key);
  bool hasTagInteger (const TString& key);
  bool hasTagBool (const TString& key);
  bool hasTagString (const TString& key);
  bool hasMatchingTag(const TString& name) const;
  int countMatchingTags(const TString& name) const;  

  bool hasEquivalentTag(const TQValue* reference, bool recurseUp=true);
  bool hasEquivalentTag(const TQValue& reference, bool recurseUp=true);
  bool hasEquivalentTag(const TString& key, const TString& value);
  bool hasEquivalentTag(const TString& key, const double value);
  bool hasEquivalentTag(const TString& key, const int value);
  bool hasEquivalentTag(const TString& key, const bool value);

  bool isTagOverwrittenByDescendants(TString key);

  bool tagIsOfTypeDouble (const TString& key);
  bool tagIsOfTypeInteger (const TString& key);
  bool tagIsOfTypeBool (const TString& key);
  bool tagIsOfTypeString (const TString& key);

  bool hasTagWithIndex(const TString& key);
  bool hasTagWithoutIndex(const TString& key);
  bool canSetThisTag(const TString& key, bool& treatAsList);

  bool allTagsValidDoubles();
  bool allTagsValidIntegers();
  bool allTagsValidBools();

  bool allTagsOfTypeDouble();
  bool allTagsOfTypeInteger();
  bool allTagsOfTypeBool();
  bool allTagsOfTypeString();

  /* ----- read tags ----- */

  int exportTags(TQTaggable * dest, const TString& subDest = "", const TString& filter = "", bool recursive = false);
  TString exportTagsAsString(const TString& filter = "", bool xmlStyle = false);
  TString exportTagsAsConfigString(const TString& prefix, const TString& filter = "");
  std::string exportTagsAsStandardString(const TString& filter = "", bool xmlStyle = false);
  std::string exportTagsAsStandardConfigString(const TString& prefix, const TString& filter = "");

  TString replaceInTextRecursive(TString in, const TString& prefix = "", bool keepQuotes = false);
  TString replaceInText(const TString& in, const char* prefix, bool keepQuotes = false);
  TString replaceInText(const TString& in, const TString& prefix, bool keepQuotes = false);
  TString replaceInText(const TString& in, bool keepQuotes = false);
  TString replaceInText(const TString& in, int &nReplaced, int &nFailed, bool keepQuotes = false);
  TString replaceInText(TString in, int &nReplaced, int &nFailed, const TString& prefix, bool keepQuotes = false);

  std::string replaceInStandardStringRecursive(TString in, const TString& prefix = "", bool keepQuotes = false);
  std::string replaceInStandardString(const TString& in, const char* prefix, bool keepQuotes = false);
  std::string replaceInStandardString(const TString& in, const TString& prefix, bool keepQuotes = false);
  std::string replaceInStandardString(const TString& in, bool keepQuotes = false);

  bool getTag (const TString& key, double &value);
  bool getTag (const TString& key, int &value);
  bool getTag (const TString& key, bool &value);
  bool getTag (const TString& key, TString &value);

  bool getTagDouble (const TString& key, double &value);
  bool getTagInteger (const TString& key, int &value);
  bool getTagBool (const TString& key, bool &value);
  bool getTagString (const TString& key, TString &value);

  double  getTagDefault (const TString& key, double defaultVal);
  int     getTagDefault (const TString& key, int defaultVal);
  bool    getTagDefault (const TString& key, bool defaultVal);
  TString getTagDefault (const TString& key, const TString& defaultVal);
  TString getTagDefault (const TString& key, const char* defaultVal);

  double      getTagDoubleDefault (const TString& key, double defaultVal = 0.);
  int         getTagIntegerDefault (const TString& key, int defaultVal = 0);
  bool        getTagBoolDefault (const TString& key, bool defaultVal = false);
  TString     getTagStringDefault (const TString& key, const TString& defaultVal = "");
  std::string getTagStandardStringDefault (const TString& key, const TString& defaultVal = "");

  bool getTagAsString (const TString& key, TString &tag);
  bool getTypeOfTagAsString (const TString& key, TString &type);
  bool getValueOfTagAsString (const TString& key, TString &value);

  int getTag(const TString& key, std::vector<TString >& vec);
  int getTag(const TString& key, std::vector<int >& vec);
  int getTag(const TString& key, std::vector<double>& vec);
  int getTag(const TString& key, std::vector<bool >& vec);

  int getTag(const TString& key, TList* l);

  std::vector<TString > getTagVString (const TString& key);
  std::vector<std::string > getTagVStandardString (const TString& key);
  std::vector<int > getTagVInt (const TString& key);
  std::vector<int > getTagVInteger(const TString& key);
  std::vector<double> getTagVDouble (const TString& key);
  std::vector<bool > getTagVBool (const TString& key);

  TString getValuesOfTags(const TString& keys, const TString& sep = ", ");

  TList* getTagList(const TString& key);
  int getTagListLength(const TString& key);

  virtual ~TQTaggable();

  bool getTag (const TString& key, double &value, bool recursive);
  bool getTag (const TString& key, int &value, bool recursive);
  bool getTag (const TString& key, bool &value, bool recursive);
  bool getTag (const TString& key, TString &value, bool recursive);

  bool getTagDouble (const TString& key, double &value, bool recursive);
  bool getTagInteger (const TString& key, int &value, bool recursive);
  bool getTagBool (const TString& key, bool &value, bool recursive);
  bool getTagString (const TString& key, TString &value, bool recursive);

  TQTaggable& operator=(const TString& s){
    this->importTags(s);
    return *this;
  }
  TQTaggable& operator=(const char* s){
    TString str(s);
    this->importTags(str);
    return *this;
  }

  TQTaggable& operator=( const TQTaggable& other ) {
    this->importTags(other);
    return *this;
  }

  bool exportConfigFile(const TString& filename, const TString& prefix, bool writeUnreadKeys = true);
  bool exportConfigFile(const TString& filename, bool writeUnreadKeys = true);
  bool exportConfigFile(bool writeUnreadKeys = true);

  int replaceInTags(TQTaggable& params, const TString& tagFilter = "*");

  int getTagsSize();
  int getFlagsSize();  
  
  //static std::vector<TString>& getTagPlaceholdersFromString(const TString& templatedString);

  //static members to allow for globally available tags (global options, aliases,...)
protected:
  static std::map<TString,std::shared_ptr<TQTaggable>> sGlobalTaggables;
public:
  static std::shared_ptr<TQTaggable> getGlobalTaggable(const char* name);
  static std::shared_ptr<TQTaggable> getGlobalTaggable(const TString& name);

  static bool hasGlobalTaggable(const char* name);
  static bool hasGlobalTaggable(const TString& name);

  static bool removeGlobalTaggable(const char* name);
  static bool removeGlobalTaggable(const TString& name);


  ClassDef(TQTaggable, 7); // storage class for meta-information

};

#endif
 TQTaggable.h:1
 TQTaggable.h:2
 TQTaggable.h:3
 TQTaggable.h:4
 TQTaggable.h:5
 TQTaggable.h:6
 TQTaggable.h:7
 TQTaggable.h:8
 TQTaggable.h:9
 TQTaggable.h:10
 TQTaggable.h:11
 TQTaggable.h:12
 TQTaggable.h:13
 TQTaggable.h:14
 TQTaggable.h:15
 TQTaggable.h:16
 TQTaggable.h:17
 TQTaggable.h:18
 TQTaggable.h:19
 TQTaggable.h:20
 TQTaggable.h:21
 TQTaggable.h:22
 TQTaggable.h:23
 TQTaggable.h:24
 TQTaggable.h:25
 TQTaggable.h:26
 TQTaggable.h:27
 TQTaggable.h:28
 TQTaggable.h:29
 TQTaggable.h:30
 TQTaggable.h:31
 TQTaggable.h:32
 TQTaggable.h:33
 TQTaggable.h:34
 TQTaggable.h:35
 TQTaggable.h:36
 TQTaggable.h:37
 TQTaggable.h:38
 TQTaggable.h:39
 TQTaggable.h:40
 TQTaggable.h:41
 TQTaggable.h:42
 TQTaggable.h:43
 TQTaggable.h:44
 TQTaggable.h:45
 TQTaggable.h:46
 TQTaggable.h:47
 TQTaggable.h:48
 TQTaggable.h:49
 TQTaggable.h:50
 TQTaggable.h:51
 TQTaggable.h:52
 TQTaggable.h:53
 TQTaggable.h:54
 TQTaggable.h:55
 TQTaggable.h:56
 TQTaggable.h:57
 TQTaggable.h:58
 TQTaggable.h:59
 TQTaggable.h:60
 TQTaggable.h:61
 TQTaggable.h:62
 TQTaggable.h:63
 TQTaggable.h:64
 TQTaggable.h:65
 TQTaggable.h:66
 TQTaggable.h:67
 TQTaggable.h:68
 TQTaggable.h:69
 TQTaggable.h:70
 TQTaggable.h:71
 TQTaggable.h:72
 TQTaggable.h:73
 TQTaggable.h:74
 TQTaggable.h:75
 TQTaggable.h:76
 TQTaggable.h:77
 TQTaggable.h:78
 TQTaggable.h:79
 TQTaggable.h:80
 TQTaggable.h:81
 TQTaggable.h:82
 TQTaggable.h:83
 TQTaggable.h:84
 TQTaggable.h:85
 TQTaggable.h:86
 TQTaggable.h:87
 TQTaggable.h:88
 TQTaggable.h:89
 TQTaggable.h:90
 TQTaggable.h:91
 TQTaggable.h:92
 TQTaggable.h:93
 TQTaggable.h:94
 TQTaggable.h:95
 TQTaggable.h:96
 TQTaggable.h:97
 TQTaggable.h:98
 TQTaggable.h:99
 TQTaggable.h:100
 TQTaggable.h:101
 TQTaggable.h:102
 TQTaggable.h:103
 TQTaggable.h:104
 TQTaggable.h:105
 TQTaggable.h:106
 TQTaggable.h:107
 TQTaggable.h:108
 TQTaggable.h:109
 TQTaggable.h:110
 TQTaggable.h:111
 TQTaggable.h:112
 TQTaggable.h:113
 TQTaggable.h:114
 TQTaggable.h:115
 TQTaggable.h:116
 TQTaggable.h:117
 TQTaggable.h:118
 TQTaggable.h:119
 TQTaggable.h:120
 TQTaggable.h:121
 TQTaggable.h:122
 TQTaggable.h:123
 TQTaggable.h:124
 TQTaggable.h:125
 TQTaggable.h:126
 TQTaggable.h:127
 TQTaggable.h:128
 TQTaggable.h:129
 TQTaggable.h:130
 TQTaggable.h:131
 TQTaggable.h:132
 TQTaggable.h:133
 TQTaggable.h:134
 TQTaggable.h:135
 TQTaggable.h:136
 TQTaggable.h:137
 TQTaggable.h:138
 TQTaggable.h:139
 TQTaggable.h:140
 TQTaggable.h:141
 TQTaggable.h:142
 TQTaggable.h:143
 TQTaggable.h:144
 TQTaggable.h:145
 TQTaggable.h:146
 TQTaggable.h:147
 TQTaggable.h:148
 TQTaggable.h:149
 TQTaggable.h:150
 TQTaggable.h:151
 TQTaggable.h:152
 TQTaggable.h:153
 TQTaggable.h:154
 TQTaggable.h:155
 TQTaggable.h:156
 TQTaggable.h:157
 TQTaggable.h:158
 TQTaggable.h:159
 TQTaggable.h:160
 TQTaggable.h:161
 TQTaggable.h:162
 TQTaggable.h:163
 TQTaggable.h:164
 TQTaggable.h:165
 TQTaggable.h:166
 TQTaggable.h:167
 TQTaggable.h:168
 TQTaggable.h:169
 TQTaggable.h:170
 TQTaggable.h:171
 TQTaggable.h:172
 TQTaggable.h:173
 TQTaggable.h:174
 TQTaggable.h:175
 TQTaggable.h:176
 TQTaggable.h:177
 TQTaggable.h:178
 TQTaggable.h:179
 TQTaggable.h:180
 TQTaggable.h:181
 TQTaggable.h:182
 TQTaggable.h:183
 TQTaggable.h:184
 TQTaggable.h:185
 TQTaggable.h:186
 TQTaggable.h:187
 TQTaggable.h:188
 TQTaggable.h:189
 TQTaggable.h:190
 TQTaggable.h:191
 TQTaggable.h:192
 TQTaggable.h:193
 TQTaggable.h:194
 TQTaggable.h:195
 TQTaggable.h:196
 TQTaggable.h:197
 TQTaggable.h:198
 TQTaggable.h:199
 TQTaggable.h:200
 TQTaggable.h:201
 TQTaggable.h:202
 TQTaggable.h:203
 TQTaggable.h:204
 TQTaggable.h:205
 TQTaggable.h:206
 TQTaggable.h:207
 TQTaggable.h:208
 TQTaggable.h:209
 TQTaggable.h:210
 TQTaggable.h:211
 TQTaggable.h:212
 TQTaggable.h:213
 TQTaggable.h:214
 TQTaggable.h:215
 TQTaggable.h:216
 TQTaggable.h:217
 TQTaggable.h:218
 TQTaggable.h:219
 TQTaggable.h:220
 TQTaggable.h:221
 TQTaggable.h:222
 TQTaggable.h:223
 TQTaggable.h:224
 TQTaggable.h:225
 TQTaggable.h:226
 TQTaggable.h:227
 TQTaggable.h:228
 TQTaggable.h:229
 TQTaggable.h:230
 TQTaggable.h:231
 TQTaggable.h:232
 TQTaggable.h:233
 TQTaggable.h:234
 TQTaggable.h:235
 TQTaggable.h:236
 TQTaggable.h:237
 TQTaggable.h:238
 TQTaggable.h:239
 TQTaggable.h:240
 TQTaggable.h:241
 TQTaggable.h:242
 TQTaggable.h:243
 TQTaggable.h:244
 TQTaggable.h:245
 TQTaggable.h:246
 TQTaggable.h:247
 TQTaggable.h:248
 TQTaggable.h:249
 TQTaggable.h:250
 TQTaggable.h:251
 TQTaggable.h:252
 TQTaggable.h:253
 TQTaggable.h:254
 TQTaggable.h:255
 TQTaggable.h:256
 TQTaggable.h:257
 TQTaggable.h:258
 TQTaggable.h:259
 TQTaggable.h:260
 TQTaggable.h:261
 TQTaggable.h:262
 TQTaggable.h:263
 TQTaggable.h:264
 TQTaggable.h:265
 TQTaggable.h:266
 TQTaggable.h:267
 TQTaggable.h:268
 TQTaggable.h:269
 TQTaggable.h:270
 TQTaggable.h:271
 TQTaggable.h:272
 TQTaggable.h:273
 TQTaggable.h:274
 TQTaggable.h:275
 TQTaggable.h:276
 TQTaggable.h:277
 TQTaggable.h:278
 TQTaggable.h:279
 TQTaggable.h:280
 TQTaggable.h:281
 TQTaggable.h:282
 TQTaggable.h:283
 TQTaggable.h:284
 TQTaggable.h:285
 TQTaggable.h:286
 TQTaggable.h:287
 TQTaggable.h:288
 TQTaggable.h:289
 TQTaggable.h:290
 TQTaggable.h:291
 TQTaggable.h:292
 TQTaggable.h:293
 TQTaggable.h:294
 TQTaggable.h:295
 TQTaggable.h:296
 TQTaggable.h:297
 TQTaggable.h:298
 TQTaggable.h:299
 TQTaggable.h:300
 TQTaggable.h:301
 TQTaggable.h:302
 TQTaggable.h:303
 TQTaggable.h:304
 TQTaggable.h:305
 TQTaggable.h:306
 TQTaggable.h:307
 TQTaggable.h:308
 TQTaggable.h:309
 TQTaggable.h:310
 TQTaggable.h:311