1 #ifndef DECKLIST_H
2 #define DECKLIST_H
3 
4 #include <QList>
5 #include <QMap>
6 #include <QObject>
7 #include <QPair>
8 #include <QSet>
9 #include <QStringList>
10 #include <QVector>
11 
12 // Required on Mac. Forward declaration doesn't work. Don't ask why.
13 #include <QtCore/QXmlStreamReader>
14 #include <QtCore/QXmlStreamWriter>
15 #include <common/pb/move_card_to_zone.pb.h>
16 
17 class CardDatabase;
18 class QIODevice;
19 class QTextStream;
20 
21 class InnerDecklistNode;
22 
23 #define DECK_ZONE_MAIN "main"
24 #define DECK_ZONE_SIDE "side"
25 #define DECK_ZONE_TOKENS "tokens"
26 
27 class SideboardPlan
28 {
29 private:
30     QString name;
31     QList<MoveCard_ToZone> moveList;
32 
33 public:
34     explicit SideboardPlan(const QString &_name = QString(),
35                            const QList<MoveCard_ToZone> &_moveList = QList<MoveCard_ToZone>());
36     bool readElement(QXmlStreamReader *xml);
37     void write(QXmlStreamWriter *xml);
38 
getName()39     QString getName() const
40     {
41         return name;
42     }
getMoveList()43     const QList<MoveCard_ToZone> &getMoveList() const
44     {
45         return moveList;
46     }
47     void setMoveList(const QList<MoveCard_ToZone> &_moveList);
48 };
49 
50 enum DeckSortMethod
51 {
52     ByNumber,
53     ByName,
54     Default
55 };
56 
57 class AbstractDecklistNode
58 {
59 protected:
60     InnerDecklistNode *parent;
61     DeckSortMethod sortMethod;
62 
63 public:
64     explicit AbstractDecklistNode(InnerDecklistNode *_parent = nullptr);
65     virtual ~AbstractDecklistNode() = default;
setSortMethod(DeckSortMethod method)66     virtual void setSortMethod(DeckSortMethod method)
67     {
68         sortMethod = method;
69     }
70     virtual QString getName() const = 0;
getParent()71     InnerDecklistNode *getParent() const
72     {
73         return parent;
74     }
75     int depth() const;
76     virtual int height() const = 0;
77     virtual bool compare(AbstractDecklistNode *other) const = 0;
78 
79     virtual bool readElement(QXmlStreamReader *xml) = 0;
80     virtual void writeElement(QXmlStreamWriter *xml) = 0;
81 };
82 
83 class InnerDecklistNode : public AbstractDecklistNode, public QList<AbstractDecklistNode *>
84 {
85 private:
86     QString name;
87     class compareFunctor;
88 
89 public:
90     explicit InnerDecklistNode(QString _name = QString(), InnerDecklistNode *_parent = nullptr)
AbstractDecklistNode(_parent)91         : AbstractDecklistNode(_parent), name(std::move(_name))
92     {
93     }
94     explicit InnerDecklistNode(InnerDecklistNode *other, InnerDecklistNode *_parent = nullptr);
95     ~InnerDecklistNode() override;
96     void setSortMethod(DeckSortMethod method) override;
getName()97     QString getName() const override
98     {
99         return name;
100     }
setName(const QString & _name)101     void setName(const QString &_name)
102     {
103         name = _name;
104     }
105     static QString visibleNameFromName(const QString &_name);
106     virtual QString getVisibleName() const;
107     void clearTree();
108     AbstractDecklistNode *findChild(const QString &name);
109     int height() const override;
110     int recursiveCount(bool countTotalCards = false) const;
111     bool compare(AbstractDecklistNode *other) const override;
112     bool compareNumber(AbstractDecklistNode *other) const;
113     bool compareName(AbstractDecklistNode *other) const;
114     QVector<QPair<int, int>> sort(Qt::SortOrder order = Qt::AscendingOrder);
115 
116     bool readElement(QXmlStreamReader *xml) override;
117     void writeElement(QXmlStreamWriter *xml) override;
118 };
119 
120 class AbstractDecklistCardNode : public AbstractDecklistNode
121 {
122 public:
AbstractDecklistNode(_parent)123     explicit AbstractDecklistCardNode(InnerDecklistNode *_parent = nullptr) : AbstractDecklistNode(_parent)
124     {
125     }
126     virtual int getNumber() const = 0;
127     virtual void setNumber(int _number) = 0;
128     QString getName() const override = 0;
129     virtual void setName(const QString &_name) = 0;
height()130     int height() const override
131     {
132         return 0;
133     }
134     bool compare(AbstractDecklistNode *other) const override;
135     bool compareNumber(AbstractDecklistNode *other) const;
136     bool compareName(AbstractDecklistNode *other) const;
137 
138     bool readElement(QXmlStreamReader *xml) override;
139     void writeElement(QXmlStreamWriter *xml) override;
140 };
141 
142 class DecklistCardNode : public AbstractDecklistCardNode
143 {
144 private:
145     QString name;
146     int number;
147 
148 public:
149     explicit DecklistCardNode(QString _name = QString(), int _number = 1, InnerDecklistNode *_parent = nullptr)
AbstractDecklistCardNode(_parent)150         : AbstractDecklistCardNode(_parent), name(std::move(_name)), number(_number)
151     {
152     }
153     explicit DecklistCardNode(DecklistCardNode *other, InnerDecklistNode *_parent);
getNumber()154     int getNumber() const override
155     {
156         return number;
157     }
setNumber(int _number)158     void setNumber(int _number) override
159     {
160         number = _number;
161     }
getName()162     QString getName() const override
163     {
164         return name;
165     }
setName(const QString & _name)166     void setName(const QString &_name) override
167     {
168         name = _name;
169     }
170 };
171 
172 class DeckList : public QObject
173 {
174     Q_OBJECT
175 private:
176     QString name, comments;
177     QString deckHash;
178     QMap<QString, SideboardPlan *> sideboardPlans;
179     InnerDecklistNode *root;
180     void getCardListHelper(InnerDecklistNode *node, QSet<QString> &result) const;
181     InnerDecklistNode *getZoneObjFromName(QString zoneName);
182 
183 protected:
getCardZoneFromName(const QString,QString currentZoneName)184     virtual QString getCardZoneFromName(const QString /*cardName*/, QString currentZoneName)
185     {
186         return currentZoneName;
187     };
getCompleteCardName(const QString cardName)188     virtual QString getCompleteCardName(const QString cardName) const
189     {
190         return cardName;
191     };
192 
193 signals:
194     void deckHashChanged();
195 
196 public slots:
197     void setName(const QString &_name = QString())
198     {
199         name = _name;
200     }
201     void setComments(const QString &_comments = QString())
202     {
203         comments = _comments;
204     }
205 
206 public:
207     explicit DeckList();
208     DeckList(const DeckList &other);
209     explicit DeckList(const QString &nativeString);
210     ~DeckList() override;
getName()211     QString getName() const
212     {
213         return name;
214     }
getComments()215     QString getComments() const
216     {
217         return comments;
218     }
219     QList<MoveCard_ToZone> getCurrentSideboardPlan();
220     void setCurrentSideboardPlan(const QList<MoveCard_ToZone> &plan);
getSideboardPlans()221     const QMap<QString, SideboardPlan *> &getSideboardPlans() const
222     {
223         return sideboardPlans;
224     }
225 
226     bool readElement(QXmlStreamReader *xml);
227     void write(QXmlStreamWriter *xml);
228     bool loadFromXml(QXmlStreamReader *xml);
229     bool loadFromString_Native(const QString &nativeString);
230     QString writeToString_Native();
231     bool loadFromFile_Native(QIODevice *device);
232     bool saveToFile_Native(QIODevice *device);
233     bool loadFromStream_Plain(QTextStream &stream);
234     bool loadFromFile_Plain(QIODevice *device);
235     bool saveToStream_Plain(QTextStream &stream, bool prefixSideboardCards, bool slashTappedOutSplitCards);
236     bool saveToFile_Plain(QIODevice *device, bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
237     QString writeToString_Plain(bool prefixSideboardCards = true, bool slashTappedOutSplitCards = false);
238 
239     void cleanList();
isEmpty()240     bool isEmpty() const
241     {
242         return root->isEmpty() && name.isEmpty() && comments.isEmpty() && sideboardPlans.isEmpty();
243     }
244     QStringList getCardList() const;
245 
246     int getSideboardSize() const;
247 
getDeckHash()248     QString getDeckHash() const
249     {
250         return deckHash;
251     }
252     void updateDeckHash();
253 
getRoot()254     InnerDecklistNode *getRoot() const
255     {
256         return root;
257     }
258     DecklistCardNode *addCard(const QString &cardName, const QString &zoneName);
259     bool deleteNode(AbstractDecklistNode *node, InnerDecklistNode *rootNode = nullptr);
260 
261     /**
262      * Calls a given function object for each card in the deck. It must
263      * take a InnerDecklistNode* as its first argument and a
264      * DecklistCardNode* as its second.
265      */
forEachCard(Callback & callback)266     template <typename Callback> void forEachCard(Callback &callback) const
267     {
268         // Support for this is only possible if the internal structure
269         // doesn't get more complicated.
270         for (int i = 0; i < root->size(); i++) {
271             const InnerDecklistNode *node = dynamic_cast<InnerDecklistNode *>(root->at(i));
272             for (int j = 0; j < node->size(); j++) {
273                 const DecklistCardNode *card = dynamic_cast<DecklistCardNode *>(node->at(j));
274                 callback(node, card);
275             }
276         }
277     }
278 };
279 
280 #endif
281