1 #ifndef CSM_WOLRD_IDCOLLECTION_H
2 #define CSM_WOLRD_IDCOLLECTION_H
3 
4 #include <components/esm/esmreader.hpp>
5 
6 #include "collection.hpp"
7 #include "land.hpp"
8 
9 namespace CSMWorld
10 {
11     /// \brief Single type collection of top level records
12     template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
13     class IdCollection : public Collection<ESXRecordT, IdAccessorT>
14     {
15             virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader, bool& isDeleted);
16 
17         public:
18 
19             /// \return Index of loaded record (-1 if no record was loaded)
20             int load (ESM::ESMReader& reader, bool base);
21 
22             /// \param index Index at which the record can be found.
23             /// Special values: -2 index unknown, -1 record does not exist yet and therefore
24             /// does not have an index
25             ///
26             /// \return index
27             int load (const ESXRecordT& record, bool base, int index = -2);
28 
29             bool tryDelete (const std::string& id);
30             ///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored.
31             ///
32             /// \return Has the ID been deleted?
33     };
34 
35     template<typename ESXRecordT, typename IdAccessorT>
loadRecord(ESXRecordT & record,ESM::ESMReader & reader,bool & isDeleted)36     void IdCollection<ESXRecordT, IdAccessorT>::loadRecord (ESXRecordT& record,
37                                                             ESM::ESMReader& reader,
38                                                             bool& isDeleted)
39     {
40         record.load (reader, isDeleted);
41     }
42 
43     template<>
loadRecord(Land & record,ESM::ESMReader & reader,bool & isDeleted)44     inline void IdCollection<Land, IdAccessor<Land> >::loadRecord (Land& record,
45         ESM::ESMReader& reader, bool& isDeleted)
46     {
47         record.load (reader, isDeleted);
48 
49         // Load all land data for now. A future optimisation may only load non-base data
50         // if a suitable mechanism for avoiding race conditions can be established.
51         int flags = ESM::Land::DATA_VHGT | ESM::Land::DATA_VNML |
52             ESM::Land::DATA_VCLR | ESM::Land::DATA_VTEX;
53         record.loadData (flags);
54 
55         // Prevent data from being reloaded.
56         record.mContext.filename.clear();
57     }
58 
59     template<typename ESXRecordT, typename IdAccessorT>
load(ESM::ESMReader & reader,bool base)60     int IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
61     {
62         ESXRecordT record;
63         bool isDeleted = false;
64 
65         loadRecord (record, reader, isDeleted);
66 
67         std::string id = IdAccessorT().getId (record);
68         int index = this->searchId (id);
69 
70         if (isDeleted)
71         {
72             if (index==-1)
73             {
74                 // deleting a record that does not exist
75                 // ignore it for now
76                 /// \todo report the problem to the user
77                 return -1;
78             }
79 
80             if (base)
81             {
82                 this->removeRows (index, 1);
83                 return -1;
84             }
85 
86             Record<ESXRecordT> baseRecord = this->getRecord (index);
87             baseRecord.mState = RecordBase::State_Deleted;
88             this->setRecord (index, baseRecord);
89             return index;
90         }
91 
92         return load (record, base, index);
93     }
94 
95     template<typename ESXRecordT, typename IdAccessorT>
load(const ESXRecordT & record,bool base,int index)96     int IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base,
97         int index)
98     {
99         if (index==-2)
100             index = this->searchId (IdAccessorT().getId (record));
101 
102         if (index==-1)
103         {
104             // new record
105             Record<ESXRecordT> record2;
106             record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
107             (base ? record2.mBase : record2.mModified) = record;
108 
109             index = this->getSize();
110             this->appendRecord (record2);
111         }
112         else
113         {
114             // old record
115             Record<ESXRecordT> record2 = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
116 
117             if (base)
118                 record2.mBase = record;
119             else
120                 record2.setModified (record);
121 
122             this->setRecord (index, record2);
123         }
124 
125         return index;
126     }
127 
128     template<typename ESXRecordT, typename IdAccessorT>
tryDelete(const std::string & id)129     bool IdCollection<ESXRecordT, IdAccessorT>::tryDelete (const std::string& id)
130     {
131         int index = this->searchId (id);
132 
133         if (index==-1)
134             return false;
135 
136         Record<ESXRecordT> record = Collection<ESXRecordT, IdAccessorT>::getRecord (index);
137 
138         if (record.isDeleted())
139             return false;
140 
141         if (record.mState==RecordBase::State_ModifiedOnly)
142         {
143             Collection<ESXRecordT, IdAccessorT>::removeRows (index, 1);
144         }
145         else
146         {
147             record.mState = RecordBase::State_Deleted;
148             this->setRecord (index, record);
149         }
150 
151         return true;
152     }
153 }
154 
155 #endif
156