/GolfSigma.Inventory/Model/TeeTime.cs

http://github.com/golfsigma/inventory-client · C# · 559 lines · 373 code · 87 blank · 99 comment · 47 complexity · 030f8879e376f33743d2900fbc7318f9 MD5 · raw file

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.Serialization;
  5. using System.Xml.Serialization;
  6. using GolfSigma.Inventory.Extension;
  7. namespace GolfSigma.Inventory.Model
  8. {
  9. #region Enumerations tied directed to TeeTime(s)
  10. public enum FeeEnum : int
  11. {
  12. UnKnown = 0,
  13. Green = 1,
  14. Cart = 2,
  15. Booking = 3,
  16. Tax = 4,
  17. RackRate = 5
  18. }
  19. public enum TeeTimeAttributeEnum : int
  20. {
  21. Holes18 = 0,
  22. Holes9 = 5,
  23. Holes27 = 10,
  24. Holes36 = 15,
  25. ResidentRestriction = 20,
  26. ResidentOnly = 25,
  27. GPSIncluded = 30,
  28. MembersOnly = 35,
  29. MemberDiscount = 40,
  30. PlayerCardDiscount = 45,
  31. PlayerCardOnly = 50,
  32. PracticeBalls = 55,
  33. SeniorDiscount = 60,
  34. SeniorOnly = 65,
  35. Twilight = 70,
  36. TaxIncluded = 75,
  37. Walking = 80,
  38. CartIncluded = 85,
  39. CaddieIncluded = 90,
  40. PullCartIncluded = 95,
  41. Replay = 100,
  42. Aerification = 105,
  43. MilitaryDiscount = 110,
  44. ShotgunStart = 115,
  45. CourseAlert = 120,
  46. FreeReplay = 125,
  47. OverSeeding = 130,
  48. BestRateGuarantee = 135,
  49. CartPathOnly = 140,
  50. PrePaidOnline = 145
  51. }
  52. [Flags]
  53. public enum PlayerEnum : int
  54. {
  55. None = 0x0,
  56. Single = 0x1,
  57. Twosome = 0x2,
  58. Threesome = 0x4,
  59. Foursome = 0x8,
  60. All = Single | Twosome | Threesome | Foursome
  61. }
  62. /// <summary>
  63. /// Currencies and their official names
  64. /// </summary>
  65. public enum CurrencyEnum
  66. {
  67. /// <summary>
  68. /// United States dollar
  69. /// </summary>
  70. USD = 0,
  71. /// <summary>
  72. /// British Pound
  73. /// </summary>
  74. GBP = 5,
  75. /// <summary>
  76. /// Canadian dollar
  77. /// </summary>
  78. CAD = 10,
  79. /// <summary>
  80. /// Euro
  81. /// </summary>
  82. EUR = 15,
  83. /// <summary>
  84. /// Australian dollar
  85. /// </summary>
  86. AUD = 20,
  87. /// <summary>
  88. /// Japanese yen
  89. /// </summary>
  90. JPY = 25,
  91. /// <summary>
  92. /// Swiss Franc
  93. /// </summary>
  94. CHF = 30,
  95. /// <summary>
  96. /// Hong Kong Dollar
  97. /// </summary>
  98. HKD = 35,
  99. /// <summary>
  100. /// Mexican Peso
  101. /// </summary>
  102. MXN = 40
  103. }
  104. #endregion
  105. [XmlRoot("TeeTime")]
  106. public class TeeTime : IXmlSerializable
  107. {
  108. #region Ids
  109. /// <summary>
  110. /// Id of the tee-time. Id will be dropped on insert(s)
  111. /// </summary>
  112. public UInt64 TeeTimeId { get; set; }
  113. /// <summary>
  114. /// Website for the specific tee-time.
  115. /// </summary>
  116. public UInt32 WebSiteId { get; set; }
  117. /// <summary>
  118. /// Course for the specific tee-time
  119. /// </summary>
  120. public UInt64 CourseId { get; set; }
  121. #endregion
  122. #region Time and Players
  123. /// <summary>
  124. /// Date and Time of the tee-time.
  125. /// </summary>
  126. public DateTime Time { get; set; }
  127. /// <summary>
  128. /// Number of players available for the current tee time. Use bitwise operators to determine the number
  129. /// of players available.
  130. /// </summary>
  131. public PlayerEnum Players { get; set; }
  132. /// <summary>
  133. /// Miscellaneous data. Providers can store information used to regenerate lookups to their own tee-time ids etc.
  134. /// </summary>
  135. public string MiscData { get; set; }
  136. #endregion
  137. #region Fees
  138. /// <summary>
  139. /// Total searchType per player. Sum of GreenFee, CartFee, Tax and Booking Fee
  140. /// </summary>
  141. public float TotalPricePerPlayer { get; set; }
  142. /// <summary>
  143. /// Percentage of interval off the original green fee
  144. /// </summary>
  145. public double? Savings { get; set; }
  146. /// <summary>
  147. /// Detailed breakdown of fees for this tee-time
  148. /// </summary>
  149. public Dictionary<FeeEnum, float> Fees { get; set; }
  150. /// <summary>
  151. /// Currency of the fees and total price per player
  152. /// </summary>
  153. public CurrencyEnum Currency { get; set; }
  154. #endregion
  155. #region Dates
  156. /// <summary>
  157. /// DateTime of when this tee time was created. (UTC) (Item will be dropped on any insert or update.)
  158. /// </summary>
  159. public DateTime Created { get; set; }
  160. /// <summary>
  161. /// DateTime of when this tee-time was last updated. (UTC) (Item will be dropped on any insert or update.)
  162. /// </summary>
  163. public DateTime? Updated { get; set; }
  164. /// <summary>
  165. /// DateTime of when this tee-time was deleted. (UTC) (Item will be dropped on any insert or update.)
  166. /// </summary>
  167. public DateTime? Deleted { get; set; }
  168. #endregion
  169. #region Attributes
  170. /// <summary>
  171. /// Attributes for the given tee times. List of integers (comma separated when serialized) representing
  172. /// all attributes that apply for the given tee time
  173. /// </summary>
  174. public List<TeeTimeAttributeEnum> Attributes { get; set; }
  175. private int? _NumberOfHoles;
  176. /// <summary>
  177. /// The number of holes for this tee-time
  178. /// ** ASSUME 18 HOLES!! **
  179. /// </summary>
  180. public int NumberOfHoles
  181. {
  182. get
  183. {
  184. if (_NumberOfHoles.HasValue)
  185. return _NumberOfHoles.Value;
  186. if (this.Attributes == null || this.Attributes.Count < 1)
  187. {
  188. _NumberOfHoles = 18;
  189. }
  190. else
  191. {
  192. if (this.Attributes.Contains(TeeTimeAttributeEnum.Holes9))
  193. _NumberOfHoles = 9;
  194. else if (this.Attributes.Contains(TeeTimeAttributeEnum.Holes27))
  195. _NumberOfHoles = 27;
  196. else if (this.Attributes.Contains(TeeTimeAttributeEnum.Holes36))
  197. _NumberOfHoles = 36;
  198. else
  199. _NumberOfHoles = 18;
  200. }
  201. // Return the number of holes
  202. return _NumberOfHoles.Value;
  203. }
  204. }
  205. #endregion
  206. #region IXmlSerializable Members
  207. public System.Xml.Schema.XmlSchema GetSchema()
  208. {
  209. return null;
  210. }
  211. public void ReadXml(System.Xml.XmlReader reader)
  212. {
  213. // Check to see if we were provided an id
  214. string teeTimeId = reader.GetAttribute("id");
  215. if (!string.IsNullOrEmpty(teeTimeId))
  216. {
  217. UInt64 teeTimeIdParsed;
  218. if (UInt64.TryParse(teeTimeId, out teeTimeIdParsed))
  219. TeeTimeId = teeTimeIdParsed;
  220. else
  221. throw new FormatException();
  222. }
  223. bool breakRead = false;
  224. while (breakRead == false)
  225. {
  226. reader.Read();
  227. string localName = reader.LocalName;
  228. string elementAsString = string.Empty;
  229. elementAsString = reader.ReadString();
  230. switch (localName)
  231. {
  232. case "WebSiteId":
  233. UInt32? webSiteIdParsed = StringExtension.ToUInt32(elementAsString);
  234. if (!webSiteIdParsed.HasValue)
  235. throw new FormatException();
  236. else
  237. WebSiteId = webSiteIdParsed.Value;
  238. break;
  239. case "CourseId":
  240. UInt64? courseIdParsed = StringExtension.ToUInt64(elementAsString);
  241. if (!courseIdParsed.HasValue)
  242. throw new FormatException();
  243. else
  244. CourseId = courseIdParsed.Value;
  245. break;
  246. case "Players":
  247. int playersParsed = 0;
  248. if (!int.TryParse(elementAsString, out playersParsed))
  249. throw new FormatException();
  250. else
  251. Players = (PlayerEnum)playersParsed;
  252. if (Players == PlayerEnum.None)
  253. throw new FormatException();
  254. break;
  255. case "Time":
  256. DateTime timeParsed;
  257. if (!DateTime.TryParseExact(
  258. elementAsString,
  259. Extension.StringExtension.DateTimeFormatShort,
  260. System.Globalization.CultureInfo.InvariantCulture,
  261. System.Globalization.DateTimeStyles.AssumeLocal | System.Globalization.DateTimeStyles.AllowWhiteSpaces,
  262. out timeParsed))
  263. throw new FormatException();
  264. else
  265. Time = timeParsed;
  266. break;
  267. case "Created":
  268. DateTime createdParsed;
  269. if (!DateTime.TryParseExact(
  270. elementAsString,
  271. Extension.StringExtension.DateTimeFormatUTC,
  272. System.Globalization.CultureInfo.InvariantCulture,
  273. System.Globalization.DateTimeStyles.AssumeUniversal | System.Globalization.DateTimeStyles.AllowWhiteSpaces,
  274. out createdParsed))
  275. throw new FormatException();
  276. else
  277. Created = createdParsed;
  278. break;
  279. case "Deleted":
  280. DateTime deletedParsed;
  281. if (!DateTime.TryParseExact(
  282. elementAsString,
  283. Extension.StringExtension.DateTimeFormatUTC,
  284. System.Globalization.CultureInfo.InvariantCulture,
  285. System.Globalization.DateTimeStyles.AssumeUniversal | System.Globalization.DateTimeStyles.AllowWhiteSpaces,
  286. out deletedParsed))
  287. throw new FormatException();
  288. else
  289. Deleted = deletedParsed;
  290. break;
  291. case "Price":
  292. float priceParsed;
  293. if (float.TryParse(elementAsString, out priceParsed))
  294. TotalPricePerPlayer = priceParsed;
  295. else
  296. // Failed (anything lower than -1 is a failure)
  297. throw new FormatException();
  298. if (TotalPricePerPlayer < -1 || TotalPricePerPlayer > 1000)
  299. throw new FormatException();
  300. break;
  301. case "Currency":
  302. try
  303. {
  304. CurrencyEnum currencyParsed = (CurrencyEnum)Enum.Parse(
  305. typeof(CurrencyEnum),
  306. elementAsString,
  307. true);
  308. Currency = currencyParsed;
  309. }
  310. catch
  311. {
  312. throw new FormatException();
  313. }
  314. break;
  315. case "Savings":
  316. Double savingsParsed;
  317. if (double.TryParse(elementAsString, out savingsParsed))
  318. Savings = savingsParsed;
  319. else
  320. throw new FormatException();
  321. break;
  322. case "Fees":
  323. // Create a new list
  324. if (Fees == null)
  325. Fees = new Dictionary<FeeEnum, float>();
  326. while (reader.IsStartElement("Fee"))
  327. {
  328. string feeType = reader.GetAttribute("type");
  329. string feeValue = reader.GetAttribute("value");
  330. // Skip if we don't have a fee AND value
  331. if (string.IsNullOrEmpty(feeType) || string.IsNullOrEmpty(feeValue))
  332. {
  333. reader.Read();
  334. continue;
  335. }
  336. FeeEnum feeTypeParsed = FeeEnum.UnKnown;
  337. try
  338. {
  339. // Attempt to convert the feeType into an enum
  340. feeTypeParsed = (FeeEnum)Enum.Parse(typeof(FeeEnum), feeType);
  341. }
  342. catch
  343. {
  344. throw new FormatException();
  345. }
  346. // Attempt to parse the value
  347. float feeValueParsed;
  348. if (float.TryParse(feeValue, out feeValueParsed))
  349. Fees.Add(feeTypeParsed, feeValueParsed);
  350. else
  351. throw new FormatException();
  352. // Done reading this element
  353. reader.Read();
  354. }
  355. break;
  356. case "Attributes":
  357. // Make sure we have attributes
  358. if (!string.IsNullOrEmpty(elementAsString))
  359. {
  360. // Create a new list if it doesn't exist
  361. if (Attributes == null)
  362. Attributes = new List<TeeTimeAttributeEnum>();
  363. // Loop through each attribute and add it to the attribute list!
  364. foreach (var attr in elementAsString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
  365. {
  366. try
  367. {
  368. // Attempt to parse the attribute
  369. TeeTimeAttributeEnum attrParsed =
  370. (TeeTimeAttributeEnum)Enum.Parse(typeof(TeeTimeAttributeEnum), attr, true);
  371. if (StringExtension.IsNumber(attrParsed.ToString(), false))
  372. {
  373. throw new FormatException();
  374. }
  375. // Add to the list
  376. Attributes.Add(attrParsed);
  377. }
  378. catch
  379. {
  380. throw new FormatException();
  381. }
  382. }
  383. }
  384. break;
  385. case "Misc":
  386. if (!string.IsNullOrEmpty(elementAsString))
  387. MiscData = elementAsString;
  388. break;
  389. case "TeeTime":
  390. // End reading this element
  391. reader.ReadEndElement();
  392. breakRead = true;
  393. break;
  394. // Do nothing on any other attribute
  395. default: break;
  396. }
  397. }
  398. }
  399. public void WriteXml(System.Xml.XmlWriter writer)
  400. {
  401. throw new NotImplementedException();
  402. }
  403. #endregion
  404. #region Post Parameters
  405. public Dictionary<string, string> GetPostParamters()
  406. {
  407. return GetPostParamters(default(int?));
  408. }
  409. public Dictionary<string, string> GetPostParamters(int? index)
  410. {
  411. string prefix = "teetime.";
  412. // Create our result
  413. Dictionary<string, string> result = new Dictionary<string, string>();
  414. result.Add(StringExtension.Prefix("websiteid", prefix, index), WebSiteId.ToString());
  415. result.Add(StringExtension.Prefix("courseid", prefix, index), CourseId.ToString());
  416. result.Add(StringExtension.Prefix("time", prefix, index), Time.ToString(Extension.StringExtension.DateTimeFormatShort));
  417. result.Add(StringExtension.Prefix("players", prefix, index), ((int)Players).ToString());
  418. result.Add(StringExtension.Prefix("currency", prefix, index), Currency.ToString());
  419. // Add our savings
  420. if (Savings.HasValue)
  421. result.Add(StringExtension.Prefix("savings", prefix, index), Savings.Value.ToString());
  422. // Convert our attributes to filters
  423. if (Attributes != null && Attributes.Count > 0)
  424. {
  425. StringBuilder sbAttributes = new StringBuilder();
  426. foreach (var item in Attributes)
  427. sbAttributes.AppendFormat("{0},", ((int)item).ToString());
  428. // Add without the trailing comma
  429. result.Add(StringExtension.Prefix("attributes", prefix, index), sbAttributes.ToString(0, sbAttributes.Length - 1));
  430. }
  431. // Convert our fees
  432. if (Fees != null && Fees.Count > 0)
  433. {
  434. string feePrefix = "fee.";
  435. int i = 1;
  436. foreach (var item in Fees)
  437. {
  438. string keyPrefix = StringExtension.Prefix(StringExtension.Prefix("key", feePrefix, i), prefix, index);
  439. string valuePrefix = StringExtension.Prefix(StringExtension.Prefix("value", feePrefix, i), prefix, index);
  440. result.Add(keyPrefix, item.Key.ToString());
  441. result.Add(valuePrefix, item.Value.ToString());
  442. i++;
  443. }
  444. }
  445. if (!string.IsNullOrEmpty(MiscData))
  446. result.Add(StringExtension.Prefix("miscdata", prefix, index), MiscData);
  447. // Return the params
  448. return result;
  449. }
  450. #endregion
  451. public TeeTime() { }
  452. public TeeTime(TeeTime input) : this()
  453. {
  454. if (input == null)
  455. return;
  456. this.Attributes = input.Attributes;
  457. this.CourseId = input.CourseId;
  458. this.Created = input.Created;
  459. this.Currency = input.Currency;
  460. this.Deleted = input.Deleted;
  461. this.Fees = input.Fees;
  462. this.MiscData = input.MiscData;
  463. this.Players = input.Players;
  464. this.Savings = input.Savings;
  465. this.TeeTimeId = input.TeeTimeId;
  466. this.Time = input.Time;
  467. this.TotalPricePerPlayer = input.TotalPricePerPlayer;
  468. this.Updated = input.Updated;
  469. this.WebSiteId = input.WebSiteId;
  470. }
  471. }
  472. }