1 /*
2     SPDX-FileCopyrightText: 2008 Akarsh Simha <akarshsimha@gmail.com>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "starblockfactory.h"
8 
9 #include "starblock.h"
10 #include "starobject.h"
11 
12 #include <kstars_debug.h>
13 
14 // TODO: Implement a better way of deciding this
15 #define DEFAULT_NCACHE 12
16 
17 StarBlockFactory *StarBlockFactory::pInstance = nullptr;
18 
Instance()19 StarBlockFactory *StarBlockFactory::Instance()
20 {
21     if (!pInstance)
22         pInstance = new StarBlockFactory();
23     return pInstance;
24 }
25 
StarBlockFactory()26 StarBlockFactory::StarBlockFactory()
27 {
28     first   = nullptr;
29     last    = nullptr;
30     nBlocks = 0;
31     drawID  = 0;
32     nCache  = DEFAULT_NCACHE;
33 }
34 
~StarBlockFactory()35 StarBlockFactory::~StarBlockFactory()
36 {
37     deleteBlocks(nBlocks);
38     if (pInstance)
39         pInstance = nullptr;
40 }
41 
getBlock()42 std::shared_ptr<StarBlock> StarBlockFactory::getBlock()
43 {
44     std::shared_ptr<StarBlock> freeBlock;
45 
46     if (nBlocks < nCache)
47     {
48         freeBlock.reset(new StarBlock);
49         if (freeBlock.get())
50         {
51             ++nBlocks;
52             return freeBlock;
53         }
54     }
55     if (last && (last->drawID != drawID || last->drawID == 0))
56     {
57         //        qCDebug(KSTARS) << "Recycling block with drawID =" << last->drawID << "and current drawID =" << drawID;
58         if (last->parent->block(last->parent->getBlockCount() - 1) != last)
59             qCDebug(KSTARS) << "ERROR: Goof up here!";
60         freeBlock = last;
61         last      = last->prev;
62         if (last)
63         {
64             last->next = nullptr;
65         }
66         if (freeBlock == first)
67         {
68             first = nullptr;
69         }
70         freeBlock->reset();
71         freeBlock->prev = nullptr;
72         freeBlock->next = nullptr;
73         return freeBlock;
74     }
75     freeBlock.reset(new StarBlock);
76     if (freeBlock.get())
77         ++nBlocks;
78 
79     return freeBlock;
80 }
81 
markFirst(std::shared_ptr<StarBlock> & block)82 bool StarBlockFactory::markFirst(std::shared_ptr<StarBlock>& block)
83 {
84     if (!block.get())
85         return false;
86 
87     //    fprintf(stderr, "markFirst()!\n");
88     if (!first)
89     {
90         //        qCDebug(KSTARS) << "INFO: Linking in first block";
91         last = first = block;
92         first->prev = first->next = nullptr;
93         first->drawID             = drawID;
94         return true;
95     }
96 
97     if (block == first) // Block is already in the front
98     {
99         block->drawID = drawID;
100         return true;
101     }
102 
103     if (block == last)
104         last = block->prev;
105 
106     if (block->prev)
107         block->prev->next = block->next;
108 
109     if (block->next)
110         block->next->prev = block->prev;
111 
112     first->prev = block;
113     block->next = first;
114     block->prev = nullptr;
115     first       = block;
116 
117     block->drawID = drawID;
118 
119     return true;
120 }
121 
markNext(std::shared_ptr<StarBlock> & after,std::shared_ptr<StarBlock> & block)122 bool StarBlockFactory::markNext(std::shared_ptr<StarBlock>& after, std::shared_ptr<StarBlock>& block)
123 {
124     //    fprintf(stderr, "markNext()!\n");
125     if (!block.get() || !after.get())
126     {
127         qCDebug(KSTARS) << "WARNING: markNext called with nullptr argument";
128         return false;
129     }
130 
131     if (!first.get())
132     {
133         qCDebug(KSTARS) << "WARNING: markNext called without an existing linked list";
134         return false;
135     }
136 
137     if (block == after)
138     {
139         qCDebug(KSTARS) << "ERROR: Trying to mark a block after itself!";
140         return false;
141     }
142 
143     if (block->prev == after) // Block is already after 'after'
144     {
145         block->drawID = drawID;
146         return true;
147     }
148 
149     if (block == first)
150     {
151         if (block->next == nullptr)
152         {
153             qCDebug(KSTARS) << "ERROR: Trying to mark only block after some other block";
154             return false;
155         }
156         first = block->next;
157     }
158 
159     if (after->getFaintMag() > block->getFaintMag() && block->getFaintMag() != -5)
160     {
161         qCDebug(KSTARS) << "WARNING: Marking block with faint mag = " << block->getFaintMag() << " after block with faint mag "
162                  << after->getFaintMag() << "in trixel" << block->parent->getTrixel();
163     }
164 
165     if (block == last)
166         last = block->prev;
167 
168     if (block->prev)
169         block->prev->next = block->next;
170     if (block->next)
171         block->next->prev = block->prev;
172 
173     block->next = after->next;
174     if (block->next)
175         block->next->prev = block;
176     block->prev = after;
177     after->next = block;
178 
179     if (after == last)
180         last = block;
181 
182     block->drawID = drawID;
183 
184     return true;
185 }
186 
187 /*
188 bool StarBlockFactory::groupMove( StarBlock *start, const int nblocks ) {
189 
190     StarBlock * end = nullptr;
191 
192     // Check for trivial cases
193     if( !start || nblocks < 0 )
194         return false;
195 
196     if( nblocks == 0 )
197         return true;
198 
199     if( !first )
200         return false;
201 
202     // Check for premature end
203     end = start;
204     for( int i = 1; i < nblocks; ++i ) {
205         if( end == nullptr )
206             return false;
207         end = end->next;
208     }
209     if( end == nullptr )
210         return false;
211 
212     // Update drawIDs
213     end = start;
214     for( int i = 1; i < nblocks; ++i ) {
215         end->drawID = drawID;
216         end = end->next;
217     }
218     end->drawID = drawID;
219 
220     // Check if we are already in the front
221     if( !start->prev )
222         return true;
223 
224     start->prev->next = end->next;
225     end->next->prev = start->prev;
226 
227     first->prev = end;
228     end->next = first;
229     start->prev = nullptr;
230     first = start;
231 }
232 */
233 
deleteBlocks(int nblocks)234 int StarBlockFactory::deleteBlocks(int nblocks)
235 {
236     int i           = 0;
237     std::shared_ptr<StarBlock> temp;
238 
239     while (last != nullptr && i != nblocks)
240     {
241         temp = last->prev;
242         last.reset();
243         last = temp;
244         i++;
245     }
246     if (last)
247         last->next = nullptr;
248     else
249         first = nullptr;
250 
251     qCDebug(KSTARS) << nblocks << "StarBlocks freed from StarBlockFactory";
252 
253     nBlocks -= i;
254     return i;
255 }
256 
printStructure() const257 void StarBlockFactory::printStructure() const
258 {
259     std::shared_ptr<StarBlock> cur;
260     Trixel curTrixel = 513; // TODO: Change if we change HTMesh level
261     int index        = 0;
262     bool draw        = false;
263 
264     cur = first;
265     do
266     {
267         if (curTrixel != cur->parent->getTrixel())
268         {
269             qCDebug(KSTARS) << "Trixel" << cur->parent->getTrixel() << "starts at index" << index;
270             curTrixel = cur->parent->getTrixel();
271         }
272         if (cur->drawID == drawID && !draw)
273         {
274             qCDebug(KSTARS) << "Blocks from index" << index << "are drawn";
275             draw = true;
276         }
277         if (cur->drawID != drawID && draw)
278         {
279             qCDebug(KSTARS) << "Blocks from index" << index << "are not drawn";
280             draw = false;
281         }
282         cur = cur->next;
283         ++index;
284     } while (cur != last);
285 }
286 
freeUnused()287 int StarBlockFactory::freeUnused()
288 {
289     int i           = 0;
290     std::shared_ptr<StarBlock> temp;
291 
292     while (last != nullptr && last->drawID < drawID && i != nBlocks)
293     {
294         temp = last->prev;
295         last.reset();
296         last = temp;
297         i++;
298     }
299     if (last)
300         last->next = nullptr;
301     else
302         first = nullptr;
303 
304     qCDebug(KSTARS) << i << "StarBlocks freed from StarBlockFactory";
305 
306     nBlocks -= i;
307     return i;
308 }
309