1 /**
2 * Copyright Mikael H�gdahl - triyana@users.sourceforge.net
3 *
4 * This source is distributed under the terms of the Q Public License version 1.0,
5 * created by Trolltech (www.trolltech.com).
6 */
7
8 #include "db/DBFactory.h"
9 #include "db/Account.h"
10 #include "db/Guard.h"
11 #include "db/Pref.h"
12 #include "db/Price.h"
13 #include "db/Portfolio.h"
14 #include "db/Security.h"
15 #include "db/Set.h"
16 #include "db/SetItem.h"
17 #include "Enums.h"
18 #include "Progress.h"
19 #include <MHCSVFile.h>
20 #include <MHDate.h>
21 #include <MHDebug.h>
22 #include <MHVector.h>
23
24 char DBFactory::aaPathSep = '\0';
25 int DBFactory::aaCacheSize = DBFactory::CACHE_SIZE;
26 int DBFactory::aaCacheTimeout = DBFactory::CACHE_TIMEOUT;
27 int DBFactory::aaPriceAccess[CACHE_SIZE];
28 MHString* DBFactory::aaLogName = 0;
29 MHString* DBFactory::aaPath = 0;
30 MHString* DBFactory::aaWorkSpace = 0;
31 MHVector* DBFactory::aaAccount = 0;
32 MHVector* DBFactory::aaClosed[CACHE_SIZE];
33 MHVector* DBFactory::aaGuard = 0;
34 MHVector* DBFactory::aaPref = 0;
35 MHVector* DBFactory::aaPrice[CACHE_SIZE];
36 MHVector* DBFactory::aaSecurity = 0;
37 MHVector* DBFactory::aaSet = 0;
38 Security* DBFactory::aaPriceName[CACHE_SIZE];
39 #define SLEEPING //MHDate::SLEEPING (1);
40
41
42
43 /**
44 *
45 */
Clear()46 void DBFactory::Clear () {
47 if (DBFactory::aaAccount) DBFactory::aaAccount->Erase();
48 if (DBFactory::aaPref) DBFactory::aaPref->Erase();
49 if (DBFactory::aaGuard) DBFactory::aaGuard->Erase();
50 if (DBFactory::aaSecurity) DBFactory::aaSecurity->Erase();
51 if (DBFactory::aaSet) DBFactory::aaSet->Erase();
52 ClearPrice ();
53 }
54
55
56
57 /**
58 *
59 */
ClearPrice()60 void DBFactory::ClearPrice () {
61 for (int f = 0; f < CACHE_SIZE; f++) {
62 aaPrice[f]->Erase();
63 aaClosed[f]->Erase();
64 delete aaPriceName[f];
65 aaPriceName[f] = 0;
66 aaPriceAccess[f] = 0;
67 }
68 }
69
70
71
72 /**
73 * Export all database or parts of to xtrader import text file
74 */
Export(const char * fileName,bool account,bool transactions,bool set,bool security,bool price,bool guard,bool pref)75 void DBFactory::Export (const char* fileName, bool account, bool transactions, bool set, bool security, bool price, bool guard, bool pref) {
76 MHString name = DBFactory::Database();
77 MHVector* ve;
78 MHVector ve2;
79 int f;
80 FILE* fs = fopen (fileName, "w");
81
82 if (!fs) throw (STRING(ERROR_SAVE));
83 DBFactory::Clear ();
84
85 //---------------------------------
86 ve = DBFactory::LoadSecurity();
87 xtrader_reset (7 + ve->Size());
88 if (security)
89 Security::Export (ve, fs);
90 xtrader_add(1);
91 if (xtrader_abort()) return;
92 SLEEPING
93
94 //---------------------------------
95 if (price) {
96 for (f = 0; f < ve->Size(); f++) {
97 Security* sec = (Security*)(*ve)[f];
98 Price::LoadAll(sec, &ve2);
99 Price::Export (sec, &ve2, fs);
100 ve2.Erase();
101 xtrader_add(1);
102 SLEEPING
103
104 }
105 }
106 else
107 xtrader_add(ve->Size());
108
109 //---------------------------------
110 if (pref) {
111 ve = DBFactory::LoadPref();
112 Pref::Export (ve, fs);
113 }
114 xtrader_add(1);
115 if (xtrader_abort()) return;
116 SLEEPING
117
118 //---------------------------------
119 ve = DBFactory::LoadAccount();
120 if (account)
121 Account::Export (ve, fs);
122 xtrader_add(1);
123 if (xtrader_abort()) return;
124 SLEEPING
125
126 //---------------------------------
127 if (transactions) {
128 for (f = 0; f < ve->Size(); f++) {
129 Account* acc = (Account*)(*ve)[f];
130 Portfolio::Load (acc, &ve2);
131 Portfolio::Export (acc, &ve2, fs);
132 ve2.Erase ();
133 }
134 }
135 ve->Erase ();
136 xtrader_add(1);
137 if (xtrader_abort()) return;
138 SLEEPING
139
140 //---------------------------------
141 if (set) {
142 ve = DBFactory::LoadSet();
143 Set::Export (ve, fs);
144
145 for (f = 0; f < ve->Size(); f++) {
146 Set* set = (Set*)(*ve)[f];
147 MHVector* vec = new MHVector ();
148
149 DBFactory::LoadSetItem (set, vec);
150 SetItem::Export (set, vec, fs);
151 vec->Erase ();
152 delete vec;
153 }
154 }
155 xtrader_add(1);
156 if (xtrader_abort()) return;
157 SLEEPING
158
159 //---------------------------------
160 if (guard) {
161 ve = DBFactory::LoadGuard();
162 Guard::Export (ve, fs);
163 }
164 xtrader_add(1);
165
166 fclose (fs);
167 }
168
169
170
171 /**
172 * Get preference integer value
173 * @param const char* - Key
174 * @param int - Legal min value
175 * @param int - Legal max value
176 * @param int - Default value if key is not found
177 * @return int - Value
178 */
GetPrefIntValue(const char * key,int min,int max,int def)179 int DBFactory::GetPrefIntValue (const char* key, int min, int max, int def) {
180 MHVector* ve = DBFactory::LoadPref ();
181 Pref p (key);
182 Pref* pref = (Pref*) ve->Find (&p, 0, 0, 0);
183
184 if (pref) {
185 int v = pref->GetValue()->ToInt();
186 if (v >= min && v <= max)
187 return v;
188 else
189 return def;
190 }
191 else
192 return def;
193 }
194
195
196
197 /**
198 * Get preference integer value
199 * @param const char* - Key
200 * @param int - View number
201 * @param int - Legal min value
202 * @param int - Legal max value
203 * @param int - Default value if key is not found
204 * @return int - Value
205 */
GetPrefIntValue(const char * key,int view,int min,int max,int def)206 int DBFactory::GetPrefIntValue (const char* key, int view, int min, int max, int def) {
207 static char key2[100];
208 snprintf (key2, 99, "%s_%d", key, view);
209 return DBFactory::GetPrefIntValue (key2, min, max, def);
210 }
211
212
213
214 /**
215 * Get preference string value
216 * @param const char* - Key
217 * @param const char* - Default value of key is not found
218 * @return const char* - Value
219 */
GetPrefStringValue(const char * key,const char * def)220 const char* DBFactory::GetPrefStringValue (const char* key, const char* def) {
221 MHVector* ve = DBFactory::LoadPref ();
222 Pref p (key);
223 Pref* pref = (Pref*) ve->Find (&p, 0, 0, 0);
224
225 if (pref)
226 return pref->GetValue()->Get();
227 else
228 return def;
229 }
230
231
232
233 /**
234 * Get a unique id number.
235 * Throws Exception at failure
236 * @return int - The unique id
237 */
GetUniqueID()238 int DBFactory::GetUniqueID () {
239 MHString name = DBFactory::Database ();
240 name += "id.db";
241 int id;
242
243
244 try {
245 try {
246 MHCSVFile infile (name(), '\t');
247 if (infile.ReadRow())
248 id = infile.GetInt (0);
249 else
250 id = 0;
251 }
252 catch (const char*) {
253 id = 0;
254 }
255 id++;
256
257 MHCSVFile outfile;
258 char buffer[30];
259
260 sprintf (buffer, "%d", id);
261 outfile.WriteString (buffer);
262 outfile.WriteFile (name());
263 }
264 catch (const char* x) {
265 DBFactory::WriteLog ("Saving id failed file=%s, error=%s", name(), x);
266 throw STRING(ERROR_SAVE);
267 }
268
269 return id;
270 }
271
272
273
274 /**
275 *
276 */
LoadAccount()277 MHVector* DBFactory::LoadAccount() {
278 if (aaAccount->Size() > 0)
279 return aaAccount;
280 Account::Load (aaAccount);
281 return aaAccount;
282 }
283
284
285
286 /**
287 *
288 */
LoadGuard()289 MHVector* DBFactory::LoadGuard() {
290 if (aaGuard->Size() > 0)
291 return aaGuard;
292 Guard::Load (aaGuard);
293 return aaGuard;
294 }
295
296
297
298 /**
299 *
300 */
LoadPref()301 MHVector* DBFactory::LoadPref() {
302 if (aaPref->Size() > 0)
303 return aaPref;
304 Pref::Load (aaPref);
305 return aaPref;
306 }
307
308
309
310 /**
311 *
312 */
LoadPortfolio(Account * account,MHVector * out)313 void DBFactory::LoadPortfolio (Account* account, MHVector* out) {
314 Portfolio::Load (account, out);
315 }
316
317
318
319 /**
320 * Load price data either form cache or from disk
321 * @param Security* - The security we want price data for
322 */
loadPrice(Security * security,bool closed)323 MHVector* DBFactory::loadPrice(Security* security, bool closed) {
324 DBG ("DBFactory::loadPrice")
325 int f;
326 int slot = -1;
327
328 if (!security) return 0;
329
330 // Check if searched security does exist in cache
331 Security* sec;
332 for (f = 0; f < DBFactory::aaCacheSize; f++) {
333 sec = (Security*) aaPriceName[f];
334
335 if (sec && *sec == *security) {
336 int diff = ((int) time(0)) - aaPriceAccess[f];
337 if (diff > aaCacheTimeout) {
338 slot = f;
339 DBG_LOG1 ("Cache to old for %d", security->GetID());
340 break;
341 }
342 DBG_LOG1 ("Cache found for %d", security->GetID());
343 aaPriceAccess[f] = (int) time(0);
344
345 if (closed)
346 return aaClosed[f];
347 else
348 return aaPrice[f];
349 }
350 }
351
352 // Find available slot, if full erase oldest accessed slot
353 if (slot == -1) {
354 slot = 0;
355 int oldest = aaPriceAccess[0];
356 for (f = 1; f < DBFactory::aaCacheSize && oldest > 0; f++) {
357 if (aaPriceAccess[f] < oldest) {
358 oldest = aaPriceAccess[f];
359 slot = f;
360 }
361 }
362 }
363
364 DBG_LOG1 ("Cache NOT found for %d", security->GetID());
365 delete aaPriceName[slot];
366 Price::Load (security, aaPrice[slot], aaClosed[slot]);
367 aaPriceName[slot] = new Security(*security);
368 aaPriceAccess[slot] = (int) time(0);
369
370 if (closed)
371 return aaClosed[slot];
372 else
373 return aaPrice[slot];
374 }
375
376
377
378 /**
379 *
380 */
LoadRawPrice(Security * security,MHVector * out)381 void DBFactory::LoadRawPrice (Security* security, MHVector* out) {
382 Price::LoadAll (security, out);
383 }
384
385
386
387 /**
388 * Load security objects from databse
389 */
LoadSecurity()390 MHVector* DBFactory::LoadSecurity() {
391 if (aaSecurity->Size() > 0)
392 return aaSecurity;
393 Security::Load (aaSecurity);
394 return aaSecurity;
395 }
396
397
398
399 /**
400 * Load set objects from databse
401 */
LoadSet()402 MHVector* DBFactory::LoadSet() {
403 if (aaSet->Size() > 0)
404 return aaSet;
405 Set::Load (aaSet);
406 return aaSet;
407 }
408
409
410
411 /**
412 *
413 */
LoadSetItem(Set * set,MHVector * out)414 void DBFactory::LoadSetItem (Set* set, MHVector* out) {
415 SetItem::Load (set, out);
416 }
417
418
419
420 /**
421 * Set integer value into application preference table
422 * @param const char* - Key
423 * @param int - Legal min value
424 * @param int - Legam max value
425 * @param int - Default value if value is out of range
426 * @param int - Value
427 */
SetPrefIntValue(const char * key,int min,int max,int def,int val)428 void DBFactory::SetPrefIntValue (const char* key, int min, int max, int def, int val) {
429 MHVector* ve = DBFactory::LoadPref ();
430 Pref p (key);
431 Pref* pref = (Pref*) ve->Find (&p, 0, 0, 0);
432
433 val = (val >= min && val <= max) ? val : def;
434
435 if (pref)
436 pref->SetValue(val);
437 else
438 ve->InsertSorted (new Pref (key, val));
439 }
440
441
442
443 /**
444 * Set preference integer value
445 * @param const char* - Key
446 * @param int - View number
447 * @param int - Legal min value
448 * @param int - Legal max value
449 * @param int - Default value if value is out of range
450 * @return int - Value
451 */
SetPrefIntValue(const char * key,int view,int min,int max,int def,int val)452 void DBFactory::SetPrefIntValue (const char* key, int view, int min, int max, int def, int val) {
453 static char key2[100];
454 snprintf (key2, 99, "%s_%d", key, view);
455 DBFactory::SetPrefIntValue (key2, min, max, def, val);
456 }
457
458
459
460 /**
461 * Set integer value into application preference table
462 * @param const char* - Key
463 * @param const char* - Value
464 */
SetPrefStringValue(const char * key,const char * val)465 void DBFactory::SetPrefStringValue (const char* key, const char* val) {
466 MHVector* ve = DBFactory::LoadPref ();
467 Pref p (key);
468 Pref* pref = (Pref*) ve->Find (&p, 0, 0, 0);
469
470 if (pref)
471 pref->SetValue(val);
472 else
473 ve->InsertSorted (new Pref (key, val));
474 }
475
476
477
478 /**
479 * Set workspace file.
480 * @param const char* - Filename
481 */
SetWorkSpace(const char * file)482 void DBFactory::SetWorkSpace (const char* file) {
483 if (aaWorkSpace) {
484 delete aaWorkSpace;
485 aaWorkSpace = 0;
486 DBFactory::ClearPref ();
487 }
488
489 aaWorkSpace = new MHString (file);
490 }
491
492
493
494 /**
495 *
496 */
Start(const char * database)497 void DBFactory::Start (const char* database) {
498 aaAccount = new MHVector ();
499 aaGuard = new MHVector ();
500 aaPref = new MHVector ();
501 aaSecurity = new MHVector ();
502 aaSet = new MHVector ();
503
504 for (int f = 0; f < CACHE_SIZE; f++) {
505 aaPrice[f] = new MHVector ();
506 aaClosed[f] = new MHVector ();
507 aaPriceName[f] = 0;
508 aaPriceAccess[f] = 0;
509 }
510
511 aaPath = new MHString (database);
512 if (aaPath->Size() > 0 && aaPath->GetChar(aaPath->Size() - 1) != '/' && aaPath->GetChar(aaPath->Size() - 1) != '\\')
513 *aaPath += DBFactory::Slash ();
514
515 aaLogName = new MHString (*aaPath);
516 *aaLogName += "xtrader.log";
517 if (DBFactory::GetPrefIntValue (STRING(PREF_COMPRESS), XTRADER_NO, XTRADER_YES, XTRADER_NO) == XTRADER_YES) MHCSVFile::Compress();
518
519 //!!!Radera alla tmp filer i databaskatalogen via MHFileTransaction::ClearTmpFile (dir)
520 // eller mhutil
521 }
522
523
524
525 /**
526 *
527 */
Stop()528 void DBFactory::Stop () {
529 DBFactory::Clear();
530 delete aaAccount;
531 delete aaGuard;
532 delete aaLogName;
533 delete aaPath;
534 delete aaPref;
535 delete aaSecurity;
536 delete aaSet;
537 delete aaWorkSpace;
538
539 for (int f = 0; f < CACHE_SIZE; f++) {
540 delete aaPrice[f];
541 delete aaClosed[f];
542 delete aaPriceName[f];
543
544 aaPrice[f] = 0;
545 aaClosed[f] = 0;
546 aaPriceName[f] = 0;
547 }
548
549 aaPath = 0;
550 aaAccount = 0;
551 aaPref = 0;
552 aaGuard = 0;
553 aaSecurity = 0;
554 aaSet = 0;
555 aaWorkSpace = 0;
556 aaLogName = 0;
557 }
558
559
560
561 /**
562 * Log message
563 * @param char* - First string
564 * @param ... - Additional data
565 */
WriteLog(const char * Message,...)566 void DBFactory::WriteLog (const char *Message, ...) {
567 MHDate date;
568 char buffer[501];
569 const char* dateStr = date.Get (MHDate::FULL_DATE);
570 FILE* file;
571
572 va_list args;
573 va_start (args, Message);
574 vsnprintf (buffer, 500, Message, args);
575 va_end (args);
576
577 if (MHFile::Size(aaLogName->Get()) > 500000) {
578 MHString tmp;
579 tmp = *aaLogName;
580 tmp += ".old";
581 unlink (tmp());
582 if (rename (aaLogName->Get(), tmp())) return;
583 }
584
585 file = fopen (aaLogName->Get(), "a");
586 if (file) {
587 fwrite (dateStr, sizeof(char), strlen(dateStr), file);
588 fwrite (" | ", sizeof(char), 3, file);
589 fwrite (buffer, sizeof(char), strlen(buffer), file);
590 fwrite ("\n", sizeof(char), 1, file);
591 fclose (file);
592 }
593 }
594