1 /****************************************************************************************
2  * Copyright (c) 2012 Matěj Laitl <matej@laitl.cz>                                      *
3  *                                                                                      *
4  * This program is free software; you can redistribute it and/or modify it under        *
5  * the terms of the GNU General Public License as published by the Free Software        *
6  * Foundation; either version 2 of the License, or (at your option) any later           *
7  * version.                                                                             *
8  *                                                                                      *
9  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
10  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
11  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
12  *                                                                                      *
13  * You should have received a copy of the GNU General Public License along with         *
14  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
15  ****************************************************************************************/
16 
17 #ifndef STATSYNCING_TRACKTUPLE_H
18 #define STATSYNCING_TRACKTUPLE_H
19 
20 #include "statsyncing/Provider.h"
21 #include "statsyncing/Track.h"
22 
23 #include <QMap>
24 
25 namespace StatSyncing
26 {
27     class Options;
28 
29     /**
30      * Smallest element of synchronization, a container for provider-to-one-track map with
31      * methods to perform statistics synchronization and querying methods.
32      */
33     class TrackTuple
34     {
35         public:
36             /**
37              * Constructs an empty tuple.
38              */
39             TrackTuple();
40 
41             /**
42              * Inserts a track into this tuple; if it already contains a track from
43              * provider, the old track si replaced with the new one.
44              *
45              * It does make sense to only add tracks that are in some sence equal to tracks
46              * already present in the tuple.
47              *
48              * @param provider the provider
49              * @param track the track
50              */
51             void insert( ProviderPtr provider, const TrackPtr &track );
52 
53             /**
54              * Returns a list of providers that have tracks in this tuple.
55              */
56             ProviderPtrList providers() const;
57 
58             /**
59              * Returns provider of the i-th track in this tuple. If i is out of bounds,
60              * returns null.
61              */
62             ProviderPtr provider( int i ) const;
63 
64             /**
65              * Returns track associated with @p provider. Asserts that there's
66              * a track from @param provider
67              */
68             TrackPtr track( const ProviderPtr &provider ) const;
69 
70             /**
71              * Returns a number of tracks in this tuple.
72              */
73             int count() const;
74 
75             /**
76              * Returns true if there are no tracks in the tuple, false otherwise.
77              */
78             bool isEmpty() const;
79 
80             /**
81              * Return true if Meta::val* field @p field is going to be updated.
82              * If @p provider is null, returns true if at least one child track
83              * is going to be updated; otherwise works on a track from @p provider.
84              *
85              * @param field the field.
86              * @param options the options.
87              * @param provider the provider.
88              */
89             bool fieldUpdated( qint64 field, const Options &options, ProviderPtr provider = ProviderPtr() ) const;
90 
91             /**
92              * Return true if there's at least one field going to be updated.
93              */
94             bool hasUpdate( const Options &options ) const;
95 
96             /**
97              * Returns true if there's a (perhaps resolved) conflict in field &field
98              */
99             bool fieldHasConflict( qint64 field, const Options &options, bool includeResolved = true ) const;
100 
101             /**
102              * Return true if there's a (perhaps resolved) conflict in this tuple.
103              */
104             bool hasConflict( const Options &options ) const;
105 
106             /**
107              * Returns a provider whose track's rating will be used in case of conflict.
108              * Will be null if rating provider hasn't been explicitly set.
109              */
110             ProviderPtr ratingProvider() const;
111 
112             /**
113              * Sets the rating provider. Only accepts null provider or a provider of one
114              * track in this tuple.
115              */
116             void setRatingProvider( const ProviderPtr &provider );
117 
118             /**
119              * Returns providers whose labels will be OR-ed together in case of conflict.
120              * Will be empty if no provider hasn't been explicitly set.
121              */
122             ProviderPtrSet labelProviders() const;
123 
124             /**
125              * Sets label providers. Only accepts empty set a or a set of providers that
126              * are contained in this tuple.
127              */
128             void setLabelProviders( const ProviderPtrSet &providers );
129 
130             /**
131              * Return synchronized rating. Specifically, returns -1 if there's unsolved
132              * rating conflict.
133              */
134             int syncedRating( const Options &options ) const;
135             QDateTime syncedFirstPlayed( const Options &options ) const;
136             QDateTime syncedLastPlayed( const Options &options ) const;
137             int syncedPlaycount( const Options &options ) const;
138             QSet<QString> syncedLabels( const Options &options ) const;
139 
140             /**
141              * Perform actual synchronization. For each track, only sets fields that are
142              * in fieldUpdated( .., .., provider). Specifically this method does not write
143              * ratings or labels if there's unresolved rating/label conflict. Can only be
144              * called from non-main thread and may block for longer time.
145              *
146              * @return a set of providers that had their track updated
147              */
148             ProviderPtrSet synchronize( const Options &options ) const;
149 
150         private:
151             int syncedRating( const Options &options, ProviderPtr ratingProvider ) const;
152             // @param hasConflict is set to true or false
153             QSet<QString> syncedLabels( const Options &options, const ProviderPtrSet &labelProviders,
154                                         bool &hasConflict ) const;
155 
156             static const QList<qint64> s_fields; /// list of Meta::val* fields capable of syncing
157             QMap<ProviderPtr, TrackPtr> m_map;
158             ProviderPtr m_ratingProvider; /// source of rating in the event of conflict
159             ProviderPtrSet m_labelProviders; /// sources of labels in the event of conflict
160     };
161 
162 } // namespace StatSyncing
163 
164 #endif // STATSYNCING_TRACKTUPLE_H
165