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