· 8 years ago · Jan 23, 2018, 11:16 PM
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Collections.Specialized;
5using System.Text;
6using System.Text.RegularExpressions;
7using System.Net;
8using System.Net.NetworkInformation;
9using System.Net.Mail;
10using System.Reflection;
11using System.IO;
12using System.Xml;
13using System.Threading;
14
15using System.Data.Odbc;
16
17using Server;
18using Server.Accounting;
19
20using Server.EUO.Donations.MySQL;
21using Server.EUO.Donations.Encryption;
22
23namespace Server.EUO.Donations
24{
25 public sealed class ADCTrackerOptions
26 {
27 [CommandProperty(AccessLevel.Administrator)]
28 public string Execute
29 {
30 get { return String.Empty; }
31 set
32 {
33 switch (value.ToUpper())
34 {
35 case "SYNC": { ADCTracker.Sync(); } break;
36 case "LOAD": { ADCTracker.Load(); } break;
37 case "SAVE": { ADCTracker.Save(); } break;
38 case "LOADCONFIG": { ADCTracker.LoadConfig(); } break;
39 case "SAVECONFIG": { ADCTracker.SaveConfig(); } break;
40 case "IMPORTDB": { ADCTracker.ImportDatabase(); } break;
41 case "EXPORTDB": { ADCTracker.ExportDatabase(); } break;
42 case "IMPORTMYSQL": { ADCTracker.ImportMySQL(); } break;
43 case "EXPORTMYSQL": { ADCTracker.ExportMySQL(); } break;
44 }
45 }
46 }
47
48 [CommandProperty(AccessLevel.Administrator)]
49 public bool Running { get { return ADCTracker.Running; } }
50
51 [CommandProperty(AccessLevel.Administrator)]
52 public bool Connected { get { return ADCTracker.Connection.Connected; } }
53
54 [CommandProperty(AccessLevel.Administrator)]
55 public int ProfileTotal { get { return ADCTracker.CentralDatabase.Registry.Count; } }
56
57 [CommandProperty(AccessLevel.Administrator)]
58 public ADCDatabaseStatus Status { get { return ADCTracker.CentralDatabase.Status; } }
59
60 private bool _QuietMode;
61 [CommandProperty(AccessLevel.Administrator)]
62 public bool QuietMode { get { return _QuietMode; } set { _QuietMode = value; } }
63
64 private double _ExchangeRate = 1.0;
65 [CommandProperty(AccessLevel.Administrator)]
66 public double ExchangeRate
67 {
68 get
69 {
70 if (_ExchangeRate < 0)
71 { _ExchangeRate = 0; }
72
73 return _ExchangeRate;
74 }
75 set
76 {
77 if (value < 0)
78 { value = 0; }
79
80 _ExchangeRate = value;
81 }
82 }
83
84 private int _MySQLRetries;
85 [CommandProperty(AccessLevel.Administrator)]
86 public int MySQLRetries
87 {
88 get
89 {
90 if (_MySQLRetries < 0)
91 { _MySQLRetries = 0; }
92
93 return _MySQLRetries;
94 }
95 set
96 {
97 if (value < 0)
98 { value = 0; }
99
100 _MySQLRetries = value;
101 }
102 }
103
104 private TimeSpan _ImportTimeOut = TimeSpan.FromSeconds(30.0);
105 [CommandProperty(AccessLevel.Administrator)]
106 public TimeSpan ImportTimeOut { get { return _ImportTimeOut; } set { _ImportTimeOut = value; } }
107
108 private TimeSpan _ExportTimeOut = TimeSpan.FromSeconds(30.0);
109 [CommandProperty(AccessLevel.Administrator)]
110 public TimeSpan ExportTimeOut { get { return _ExportTimeOut; } set { _ExportTimeOut = value; } }
111
112 private string _MySQLDatabase = "adc_db";
113 [CommandProperty(AccessLevel.Administrator)]
114 public string MySQLDatabase
115 {
116 get { return _MySQLDatabase; }
117 set
118 {
119 if (value != _MySQLDatabase)
120 { _MySQLDatabase = value; }
121 }
122 }
123
124 private string _MySQLTable = "adc_trans";
125 [CommandProperty(AccessLevel.Administrator)]
126 public string MySQLTable
127 {
128 get { return _MySQLTable; }
129 set
130 {
131 if (value != _MySQLTable)
132 { _MySQLTable = value; }
133 }
134 }
135
136 public ADCTrackerOptions()
137 { }
138
139 public override string ToString()
140 { return "..."; }
141 }
142
143 [PropertyObject]
144 public sealed class ADCTracker
145 {
146 private static FileInfo _ConfigFile;
147 public static FileInfo ConfigFile
148 {
149 get
150 {
151 if (_ConfigFile == null)
152 { _ConfigFile = new FileInfo(@"ADC\Config.bin"); }
153
154 return _ConfigFile;
155 }
156 set
157 {
158 if (value == null)
159 { ADCEvents.InvokeException(new ArgumentNullException("ConfigFile `value`"), "ConfigFile can not be null"); }
160 else
161 {
162 if (value != _ConfigFile)
163 { _ConfigFile = value; }
164 }
165 }
166 }
167
168 private static ADCTrackerOptions _Options = new ADCTrackerOptions();
169 public static ADCTrackerOptions Options { get { return _Options; } }
170
171 public static Dictionary<IAccount, ADCDonationProfile> Registry { get { return CentralDatabase.Registry; } }
172
173 private static MySQLConnection _Connection;
174 public static MySQLConnection Connection
175 {
176 get
177 {
178 if (_Connection == null || !_Connection.Connected)
179 { _Connection = new MySQLConnection(MySQLConfig.DefaultCredentials); }
180
181 return _Connection;
182 }
183 }
184
185 private static IADCDatabase _CentralDatabase;
186 public static IADCDatabase CentralDatabase
187 {
188 get
189 {
190 if (_CentralDatabase == null)
191 { _CentralDatabase = new ADCDatabaseBinary(@"ADC\Databases\Central.bin"); }
192
193 return _CentralDatabase;
194 }
195 set
196 {
197 if (value == null)
198 { ADCEvents.InvokeException(new ArgumentNullException("Database `value`"), "Database can not be null"); }
199 else
200 {
201 if (value != _CentralDatabase)
202 { _CentralDatabase = value; }
203 }
204 }
205 }
206
207 private static bool _Running;
208 public static bool Running { get { return _Running; } }
209
210 private static TimeSpan _LoadTime, _SaveTime, _SyncTime;
211
212 private static void OnWorldCrashed(CrashedEventArgs e)
213 {
214 if (!_Options.QuietMode)
215 { Console.WriteLine(); }
216
217 Save();
218 }
219
220 private static void OnWorldSave(WorldSaveEventArgs e)
221 {
222 if (!_Options.QuietMode)
223 { Console.WriteLine(); }
224
225 Sync();
226 SaveConfig();
227 }
228
229 public static void Invoke()
230 {
231 try
232 {
233 LoadConfig();
234
235 if (_Running)
236 {
237 if (!_Options.QuietMode)
238 { Console.WriteLine("[ADC/Tracker]: Could not Invoke ADC Tracker, the ADC Tracker is already running."); }
239
240 ADCEvents.InvokeException(new InvalidOperationException("Could not Invoke ADC Tracker"), "ADC Tracker is already running.");
241 return;
242 }
243
244 EventSink.WorldSave += new WorldSaveEventHandler(OnWorldSave);
245 EventSink.Crashed += new CrashedEventHandler(OnWorldCrashed);
246
247 _Running = true;
248
249 InvokeMySQL();
250 Load();
251 }
252 catch (Exception e)
253 {
254 _Running = false;
255
256 if (!_Options.QuietMode)
257 {
258 Console.WriteLine("[ADC/Tracker]: An unexpected exception occured that was not specified. (Tracker Invokation)");
259 Console.WriteLine(e);
260 }
261
262 ADCEvents.InvokeException(e, "An unexpected exception occured that was not specified. (Tracker Invokation)");
263 }
264 }
265
266 public static void LoadConfig()
267 {
268 if (!ConfigFile.Exists || ConfigFile.Length == 0)
269 { return; }
270
271 using (FileStream fs = _ConfigFile.Open(FileMode.OpenOrCreate, FileAccess.Read))
272 {
273 GenericReader gr = new BinaryFileReader(new BinaryReader(fs));
274
275 CentralDatabase = (IADCDatabase)Type.GetType(gr.ReadString()).GetConstructor(new Type[] { typeof(string) }).Invoke(new object[] { gr.ReadString() });
276 _Options.MySQLDatabase = gr.ReadString();
277 _Options.MySQLTable = gr.ReadString();
278 _Options.MySQLRetries = gr.ReadInt();
279 _Options.QuietMode = gr.ReadBool();
280 _Options.ImportTimeOut = gr.ReadTimeSpan();
281 _Options.ExportTimeOut = gr.ReadTimeSpan();
282 }
283 }
284
285 public static void SaveConfig()
286 {
287 if (!_ConfigFile.Exists)
288 { _ConfigFile.Create().Close(); }
289
290 using (FileStream fs = _ConfigFile.Open(FileMode.OpenOrCreate, FileAccess.Write))
291 {
292 GenericWriter gw = new BinaryFileWriter(fs, true);
293
294 gw.Write(_CentralDatabase.GetType().FullName);
295 gw.Write(_CentralDatabase.Document.FullName);
296 gw.Write(_Options.MySQLDatabase);
297 gw.Write(_Options.MySQLTable);
298 gw.Write(_Options.MySQLRetries);
299 gw.Write(_Options.QuietMode);
300 gw.Write(_Options.ImportTimeOut);
301 gw.Write(_Options.ExportTimeOut);
302
303 gw.Close();
304 }
305 }
306
307 public static void Load()
308 {
309 if (!_Running)
310 {
311 ADCEvents.InvokeException(new InvalidOperationException("Could not perform method call"), "ADC Tracker is not running, call Invoke to start the Tracker");
312 return;
313 }
314
315 if (!_Options.QuietMode)
316 { Console.WriteLine("[ADC/Tracker]: Loading..."); }
317
318 DateTime then = DateTime.Now;
319
320 ImportDatabase();
321 ImportMySQL();
322
323 _LoadTime = TimeSpan.FromSeconds((DateTime.Now - then).TotalSeconds);
324
325 if (!_Options.QuietMode)
326 {
327 Console.WriteLine("[ADC/Tracker]: Load completed in {0:F2} second{1}.", _LoadTime.TotalSeconds, _LoadTime.TotalSeconds != 1 ? "s" : String.Empty);
328 DatabaseReport();
329 }
330 }
331
332 public static void Save()
333 {
334 if (!_Running)
335 {
336 ADCEvents.InvokeException(new InvalidOperationException("Could not perform method call"), "ADC Tracker is not running, call Invoke to start the Tracker");
337 return;
338 }
339
340 if (!_Options.QuietMode)
341 { Console.WriteLine("[ADC/Tracker]: Saving..."); }
342
343 DateTime then = DateTime.Now;
344
345 ExportDatabase();
346 ExportMySQL();
347
348 _SaveTime = TimeSpan.FromSeconds((DateTime.Now - then).TotalSeconds);
349
350 if (!_Options.QuietMode)
351 {
352 Console.WriteLine("[ADC/Tracker]: Save completed in {0:F2} second{1}.", _SaveTime.TotalSeconds, _SaveTime.TotalSeconds != 1 ? "s" : String.Empty);
353 DatabaseReport();
354 }
355 }
356
357 public static void Sync()
358 {
359 if (!_Running)
360 {
361 ADCEvents.InvokeException(new InvalidOperationException("Could not perform method call"), "ADC Tracker is not running, call Invoke to start the Tracker");
362 return;
363 }
364
365 if (!_Options.QuietMode)
366 { Console.WriteLine("[ADC/Tracker]: Syncing..."); }
367
368 DateTime then = DateTime.Now;
369
370 ImportMySQL();
371 ExportDatabase();
372 ExportMySQL();
373
374 _SyncTime = TimeSpan.FromSeconds((DateTime.Now - then).TotalSeconds);
375
376 if (!_Options.QuietMode)
377 {
378 Console.WriteLine("[ADC/Tracker]: Sync completed in {0:F2} second{1}.", _SyncTime.TotalSeconds, _SyncTime.TotalSeconds != 1 ? "s" : String.Empty);
379 DatabaseReport();
380 }
381 }
382
383 public static void DatabaseReport()
384 {
385 if (!_Options.QuietMode)
386 { Console.WriteLine("[ADC/Tracker]: The Database reports status as {0} with {1} profile entr{2}.", ADCTracker.CentralDatabase.Status.ToString(), (ADCTracker.CentralDatabase.Registry.Count == 0) ? "no" : ADCTracker.CentralDatabase.Registry.Count.ToString("#,#"), (ADCTracker.CentralDatabase.Registry.Count != 1) ? "ies" : "y"); }
387 }
388
389 public static void ImportDatabase()
390 {
391 DateTime now = DateTime.Now;
392 ADCDatabaseResult result = ADCDatabaseResult.Busy;
393
394 while (result == ADCDatabaseResult.Busy)
395 {
396 if (DateTime.Now < (now + _Options.ImportTimeOut))
397 { result = CentralDatabase.Import(); }
398 else
399 { break; }
400 }
401
402 if (result == ADCDatabaseResult.Error || result == ADCDatabaseResult.Null)
403 {
404 if (CentralDatabase.HasErrors)
405 {
406 if (!_Options.QuietMode)
407 {
408 foreach (Exception e in CentralDatabase.Errors)
409 { Console.WriteLine(e); }
410
411 Console.WriteLine("[ADC/Tracker]: There {0} {1} error{2}.",
412 CentralDatabase.Errors.Count != 1 ? "are" : "is",
413 CentralDatabase.Errors.Count > 0 ? CentralDatabase.Errors.Count.ToString("#,#") : "no",
414 CentralDatabase.Errors.Count != 1 ? "s" : "");
415 }
416 }
417 else
418 {
419 if (!_Options.QuietMode)
420 { Console.WriteLine("[ADC/Tracker]: An unexpected exception occured that was not specified. (Database Import)"); }
421 }
422 }
423
424 if (result != ADCDatabaseResult.OK)
425 {
426 if (!_Options.QuietMode)
427 { Console.WriteLine("[ADC/Tracker]: A problem with the central database was detected, import will not continue."); }
428 }
429 else
430 {
431 if (!_Options.QuietMode)
432 {
433 Console.WriteLine("[ADC/Tracker]: {0} Profile record{1} imported from central database.",
434 CentralDatabase.Registry.Count > 0 ? CentralDatabase.Registry.Count.ToString("#,#") : "No",
435 CentralDatabase.Registry.Count != 1 ? "s" : "");
436 }
437
438 ADCEvents.InvokeDatabaseImported(CentralDatabase);
439 }
440 }
441
442 public static ADCDatabaseResult ExportDatabase()
443 {
444 DateTime now = DateTime.Now;
445 ADCDatabaseResult result = ADCDatabaseResult.Busy;
446
447 while (result == ADCDatabaseResult.Busy)
448 {
449 if (DateTime.Now < (now + _Options.ExportTimeOut))
450 { result = CentralDatabase.Export(); }
451 else
452 { break; }
453 }
454
455 if (result == ADCDatabaseResult.Error || result == ADCDatabaseResult.Null)
456 {
457 if (CentralDatabase.HasErrors)
458 {
459 if (!_Options.QuietMode)
460 {
461 foreach (Exception e in CentralDatabase.Errors)
462 { Console.WriteLine(e); }
463
464 Console.WriteLine("[ADC/Tracker]: There {0} {1} error{2}.",
465 CentralDatabase.Errors.Count != 1 ? "are" : "is",
466 CentralDatabase.Errors.Count > 0 ? CentralDatabase.Errors.Count.ToString("#,#") : "no",
467 CentralDatabase.Errors.Count != 1 ? "s" : "");
468 }
469 }
470 else
471 {
472 if (!_Options.QuietMode)
473 { Console.WriteLine("[ADC/Tracker]: An unexpected exception occured that was not specified. (Database Export)"); }
474 }
475 }
476
477 if (result != ADCDatabaseResult.OK)
478 {
479 if (!_Options.QuietMode)
480 { Console.WriteLine("[ADC/Tracker]: A problem with the central database was detected, export will not continue."); }
481 }
482 else
483 {
484 if (!_Options.QuietMode)
485 {
486 Console.WriteLine("[ADC/Tracker]: {0} Profile record{1} exported to central database.",
487 CentralDatabase.Registry.Count > 0 ? CentralDatabase.Registry.Count.ToString("#,#") : "No",
488 CentralDatabase.Registry.Count != 1 ? "s" : "");
489 }
490
491 ADCEvents.InvokeDatabaseExported(CentralDatabase);
492 }
493
494 return result;
495 }
496
497 public static void InvokeMySQL()
498 {
499 if (Connection.Connect(_Options.MySQLRetries))
500 {
501 Connection.NonQuery(@"CREATE DATABASE IF NOT EXISTS `{0}` DEFAULT CHARSET `utf8` DEFAULT COLLATE `utf8_bin`", _Options.MySQLDatabase);
502 Connection.UseDatabase(_Options.MySQLDatabase);
503
504 string query = @"CREATE TABLE IF NOT EXISTS `" + _Options.MySQLTable + @"` ("
505 + @"`id` varchar(255) collate utf8_bin NOT NULL,"
506 + @"`state` varchar(255) collate utf8_bin NOT NULL,"
507 + @"`account` varchar(255) collate utf8_bin NOT NULL,"
508 + @"`email` varchar(255) collate utf8_bin NOT NULL,"
509 + @"`total` decimal(10,2) NOT NULL,"
510 + @"`credit` bigint(20) NOT NULL,"
511 + @"`time` int(11) NOT NULL,"
512 + @"`version` int(11),"
513 + @"`notes` text collate utf8_bin,"
514 + @"`extra` text collate utf8_bin,"
515 + @"PRIMARY KEY (`id`),"
516 + @"KEY `state` (`state`),"
517 + @"KEY `account` (`account`),"
518 + @"KEY `email` (`email`)"
519 + @") ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;";
520
521 if (Connection.NonQuery(query) > 0)
522 {
523 if (!_Options.QuietMode)
524 { Console.WriteLine("[ADC/Tracker]: Created MySQL Table '" + _Options.MySQLTable + "' for use with ADC."); }
525 }
526 }
527 }
528
529 public static void ImportMySQL()
530 {
531 ImportMySQL(ADCTransactionState.PENDING);
532 ImportMySQL(ADCTransactionState.PROCESSED);
533 ImportMySQL(ADCTransactionState.CLAIMED);
534 ImportMySQL(ADCTransactionState.VOIDED);
535 }
536
537 public static void ImportMySQL(ADCTransactionState state)
538 {
539 if (Connection.Connect(_Options.MySQLRetries))
540 {
541 int count = 0;
542
543 Connection.UseDatabase(_Options.MySQLDatabase);
544
545 MySQLRow[] rows = Connection.Select(_Options.MySQLTable, null, new MySQLData[] { new MySQLData("state", state) }, "time", MySQLSortOrder.ASC);
546
547 if (Connection.HasError)
548 {
549 if (!_Options.QuietMode)
550 {
551 foreach (OdbcError e in Connection.Errors)
552 { Console.WriteLine(e); }
553
554 Console.WriteLine("[ADC/Tracker]: There {0} {1} error{2}.",
555 CentralDatabase.Errors.Count != 1 ? "are" : "is",
556 CentralDatabase.Errors.Count > 0 ? CentralDatabase.Errors.Count.ToString("#,#") : "no",
557 CentralDatabase.Errors.Count != 1 ? "s" : "");
558 }
559 }
560 else if (rows.Length > 0)
561 {
562 List<ADCTransaction> gTrans = new List<ADCTransaction>(rows.Length);
563
564 foreach (MySQLRow row in rows)
565 {
566 try
567 {
568 decimal total = row["total"].GetValue<decimal>();
569 long credit = row["credit"].GetValue<long>();
570 int
571 time = row["time"].GetValue<int>(),
572 version = row["version"].GetValue<int>();
573 string
574 id = row["id"].GetValue<string>(),
575 email = row["email"].GetValue<string>(),
576 notes = row["notes"].GetValue<string>(),
577 extra = row["extra"].GetValue<string>(),
578 status = row["state"].GetValue<string>(),
579 account = row["account"].GetValue<string>();
580
581 gTrans.Add(new ADCTransaction(id, (ADCTransactionState)Enum.Parse(typeof(ADCTransactionState), status, true), (Account)Accounts.GetAccount(account), email, total, new ADCCredits(credit), TimeStamp.FromUnixTimeStamp(time), version, notes, extra));
582 }
583 catch (Exception e)
584 { ADCEvents.InvokeException(e, "Could not load MySQL data for ADCTransaction in row {0}", row.ID.ToString("#,#")); }
585 }
586
587 List<Exception> errors = new List<Exception>();
588
589 foreach (ADCTransaction trans in gTrans)
590 {
591 try
592 {
593 if (!CentralDatabase.Registry.ContainsKey(trans.Account))
594 { Register(trans.Account, new ADCDonationProfile(trans.Account)); }
595
596 if (!CentralDatabase.Registry[trans.Account].Contains(trans))
597 { CentralDatabase.Registry[trans.Account].Add(trans); }
598
599 switch (trans.State)
600 {
601 case ADCTransactionState.PENDING:
602 {
603 if (CentralDatabase.Registry[trans.Account].Process(trans))
604 { }
605
606 count++;
607 } break;
608 case ADCTransactionState.PROCESSED: { count++; } break;
609 case ADCTransactionState.CLAIMED: { count++; } break;
610 case ADCTransactionState.VOIDED:
611 {
612 if (CentralDatabase.Registry[trans.Account].Void(trans))
613 { }
614
615 count++;
616 } break;
617 }
618 }
619 catch (Exception e)
620 {
621 ADCEvents.InvokeException(e, "Could not load MySQL data for ADCTransaction ID {0}", trans.ID);
622 errors.Add(e);
623 }
624 }
625
626 if (errors.Count > 0)
627 {
628 if (!_Options.QuietMode)
629 {
630 foreach (Exception e in errors)
631 { Console.WriteLine(e); }
632
633 Console.WriteLine("[ADC/Tracker]: There {0} {1} error{2}.",
634 errors.Count != 1 ? "are" : "is",
635 errors.Count > 0 ? errors.Count.ToString("#,#") : "no",
636 errors.Count != 1 ? "s" : "");
637 }
638 }
639 }
640
641 if (!_Options.QuietMode)
642 {
643 Console.WriteLine("[ADC/Tracker]: {0} ({1}) Transaction record{2} imported from MySQL.",
644 count > 0 ? count.ToString("#,#") : "No",
645 state.ToString(),
646 count != 1 ? "s" : "");
647 }
648 }
649 }
650
651 public static void ExportMySQL()
652 {
653 ExportMySQL(ADCTransactionState.PENDING);
654 ExportMySQL(ADCTransactionState.PROCESSED);
655 ExportMySQL(ADCTransactionState.CLAIMED);
656 ExportMySQL(ADCTransactionState.VOIDED);
657 }
658
659 public static void ExportMySQL(ADCTransactionState state)
660 {
661 if (Connection.Connect(_Options.MySQLRetries))
662 {
663 Connection.UseDatabase(_Options.MySQLDatabase);
664
665 List<Exception> errors = new List<Exception>();
666 int count = 0;
667
668 foreach (ADCDonationProfile dp in CentralDatabase.Registry.Values)
669 {
670 foreach (ADCTransaction trans in dp)
671 {
672 try
673 {
674 if (trans.State != state)
675 { continue; }
676
677 if (Connection.Contains(_Options.MySQLTable, "id", new MySQLData[] { new MySQLData("id", trans.ID) }))
678 {
679 Connection.Update(_Options.MySQLTable, new MySQLData[] {
680 new MySQLData("state", trans.State),
681 new MySQLData("version", trans.Version),
682 new MySQLData("notes", trans.Notes),
683 new MySQLData("extra", trans.Extra)},
684 new MySQLData[] { new MySQLData("id", trans.ID) });
685 }
686 else
687 {
688 Connection.Insert(_Options.MySQLTable, new MySQLData[] {
689 new MySQLData("id", trans.ID),
690 new MySQLData("state", trans.State),
691 new MySQLData("account", trans.Account.Username),
692 new MySQLData("email", trans.Email),
693 new MySQLData("total", trans.Total),
694 new MySQLData("credit", trans.Credit.Value),
695 new MySQLData("time", trans.Time.Stamp),
696 new MySQLData("version", trans.Version),
697 new MySQLData("notes", trans.Notes),
698 new MySQLData("extra", trans.Extra)});
699 }
700
701 count++;
702 }
703 catch (Exception e)
704 {
705 ADCEvents.InvokeException(e, "Could not save MySQL data for ADCTransaction ID {0}", trans.ID);
706 errors.Add(e);
707 }
708 }
709 }
710
711 if (errors.Count > 0)
712 {
713 if (!_Options.QuietMode)
714 {
715 foreach (Exception e in errors)
716 { Console.WriteLine(e); }
717
718 Console.WriteLine("[ADC/Tracker]: There {0} {1} error{2}.",
719 errors.Count != 1 ? "are" : "is",
720 errors.Count > 0 ? errors.Count.ToString("#,#") : "no",
721 errors.Count != 1 ? "s" : "");
722 }
723 }
724
725 if (!_Options.QuietMode)
726 {
727 Console.WriteLine("[ADC/Tracker]: {0} ({1}) Transaction record{2} exported to MySQL.",
728 count > 0 ? count.ToString("#,#") : "No",
729 state.ToString(),
730 count != 1 ? "s" : "");
731 }
732 }
733 }
734
735 public static void Register(IAccount a, ADCDonationProfile dp)
736 {
737 if (a == null || dp == null)
738 {
739 if (a == null && dp == null)
740 { ADCEvents.InvokeException(new ArgumentNullException("Account `a`, DonationProfile `dp`"), "Failed to register unknown DonationProfile to unknown Account"); }
741 else if (a == null && dp != null)
742 { ADCEvents.InvokeException(new ArgumentNullException("Account `a`"), "Failed to register DonationProfile `{0}` to unknown Account", dp); }
743 else if (a != null && dp == null)
744 { ADCEvents.InvokeException(new ArgumentNullException("DonationProfile `dp`"), "Failed to register unknown DonationProfile to Account `{0}`", a); }
745
746 return;
747 }
748
749 if (CentralDatabase.Registry.ContainsKey(a))
750 { CentralDatabase.Registry[a] = dp; }
751 else
752 { CentralDatabase.Registry.Add(a, dp); }
753 }
754
755 public static ADCDonationProfile Find(IAccount a)
756 {
757 if (a == null)
758 { return null; }
759
760 if (Validate(a))
761 { return CentralDatabase.Registry[a]; }
762
763 return null;
764 }
765
766 public static IAccount Find(ADCDonationProfile dp)
767 {
768 if (dp == null)
769 { return null; }
770
771 if (CentralDatabase.Registry.ContainsValue(dp))
772 {
773 foreach (KeyValuePair<IAccount, ADCDonationProfile> kvp in CentralDatabase.Registry)
774 {
775 if (kvp.Value == dp)
776 { return kvp.Key; }
777 }
778 }
779
780 return null;
781 }
782
783 public static bool Validate(IAccount a)
784 {
785 if (a == null)
786 { return false; }
787
788 return (CentralDatabase.Registry.ContainsKey(a));
789 }
790 }
791}