00001 using System;
00002 using System.Collections;
00003 using System.Collections.Generic;
00004 using System.Text;
00005 using Foodolini.Database;
00006 using System.Diagnostics;
00007
00008 namespace Foodolini.BusinessLogic
00009 {
00010 public partial class Ingredient
00011 {
00025 private class NutritionDictionary : IDictionary<Nutrient, double>
00026 {
00035 private Dictionary<long, NutritionalValue> cachedValues = new Dictionary<long, NutritionalValue>();
00036
00040 private Dictionary<long, NutritionalValue> changedValues = new Dictionary<long, NutritionalValue>();
00041
00045 private Dictionary<long, NutritionalValue> deletedValues = new Dictionary<long, NutritionalValue>();
00046
00053 public NutritionDictionary(long foodDescriptionId){
00054 if(foodDescriptionId != 0){
00055 var query = Settings.Repo.Where<NutritionalValue>("FoodDescriptionId = " + foodDescriptionId);
00056 foreach(NutritionalValue entry in query)
00057 this.cachedValues.Add(entry.NutritionDefinitionId, entry);
00058 }
00059 }
00060
00072 public void Save(long foodDescriptionId){
00073
00074
00075 foreach(NutritionalValue val in this.cachedValues.Values){
00076 if(val.FoodDescriptionId != foodDescriptionId){
00077 Debug.Fail("This NutritionDictionary was created for another Ingredient!");
00078 val.FoodDescriptionId = foodDescriptionId;
00079 Settings.Repo.Add<NutritionalValue>(val);
00080 }
00081 }
00082
00083
00084 foreach(NutritionalValue val in this.changedValues.Values){
00085
00086 if(val.NutritionalValueId != 0 && val.FoodDescriptionId == foodDescriptionId){
00087 Settings.Repo.Update<NutritionalValue>(val);
00088 }else{
00089 Debug.Assert(val.FoodDescriptionId == 0, "This NutritionDictionary was created for another Ingredient!");
00090
00091
00092 val.FoodDescriptionId = foodDescriptionId;
00093 Settings.Repo.Add<NutritionalValue>(val);
00094 }
00095
00096 this.cachedValues.Add(val.NutritionDefinitionId, val);
00097 }
00098
00099 this.changedValues.Clear();
00100
00101 foreach(NutritionalValue val in this.deletedValues.Values){
00102
00103 if(val.NutritionalValueId != 0 && val.FoodDescriptionId == foodDescriptionId)
00104 Settings.Repo.Delete<NutritionalValue>(val);
00105 else
00106 Debug.Assert(val.FoodDescriptionId == foodDescriptionId, "This NutritionDictionary was created for another Ingredient!");
00107 }
00108
00109 this.deletedValues.Clear();
00110 }
00111
00118 public void Delete(long foodDescriptionId){
00119
00120 foreach(NutritionalValue val in this.cachedValues.Values){
00121 if(val.FoodDescriptionId == foodDescriptionId){
00122 Settings.Repo.Delete<NutritionalValue>(val);
00123 val.FoodDescriptionId = 0;
00124 }else
00125 Debug.Assert(val.FoodDescriptionId == 0, "This NutritionDictionary was created for another Ingredient!");
00126 this.changedValues.Add(val.NutritionDefinitionId, val);
00127 }
00128
00129 this.cachedValues.Clear();
00130
00131 foreach(NutritionalValue val in this.changedValues.Values){
00132 if(val.FoodDescriptionId == foodDescriptionId){
00133 Settings.Repo.Delete<NutritionalValue>(val);
00134 val.FoodDescriptionId = 0;
00135 }else
00136 Debug.Assert(val.FoodDescriptionId == 0, "This NutritionDictionary was created for another Ingredient!");
00137 }
00138
00139 foreach(NutritionalValue val in this.deletedValues.Values){
00140 if(val.FoodDescriptionId == foodDescriptionId)
00141 Settings.Repo.Delete<NutritionalValue>(val);
00142 else
00143 Debug.Assert(val.FoodDescriptionId == 0, "This NutritionDictionary was created for another Ingredient!");
00144 }
00145
00146 this.deletedValues.Clear();
00147 }
00148
00158 private void SetValue(long defId, double amount){
00159 NutritionalValue val = null;
00160
00161 if(this.cachedValues.TryGetValue(defId, out val)){
00162 val.Value = amount;
00163 this.changedValues.Add(defId, val);
00164 this.cachedValues.Remove(defId);
00165
00166 } else if(this.changedValues.TryGetValue(defId, out val)){
00167 val.Value = amount;
00168
00169 } else if(this.deletedValues.TryGetValue(defId, out val)){
00170 val.Value = amount;
00171 this.changedValues.Add(defId, val);
00172 this.deletedValues.Remove(defId);
00173
00174 } else{
00175 val = new NutritionalValue();
00176 val.FoodDescriptionId = 0;
00177 val.NutritionDefinitionId = defId;
00178 val.Value = amount;
00179 this.changedValues.Add(defId, val);
00180 }
00181 }
00182
00183 #region IDictionary<Nutrient, double> implementation
00188 public void Add(Nutrient key, double value){
00189 this.SetValue(key.Id, value);
00190 }
00191
00201 public bool ContainsKey(Nutrient key){
00202 return this.cachedValues.ContainsKey(key.Id) || this.changedValues.ContainsKey(key.Id);
00203 }
00204
00205 public bool Remove(Nutrient key){
00206 NutritionalValue val = null;
00207 if(this.cachedValues.TryGetValue(key.Id, out val)){
00208
00209 if(val.NutritionDefinitionId != 0)
00210 this.deletedValues.Add(key.Id, val);
00211 this.cachedValues.Remove(key.Id);
00212 return true;
00213 }
00214 if(this.changedValues.TryGetValue(key.Id, out val)){
00215
00216 if(val.NutritionDefinitionId != 0)
00217 this.deletedValues.Add(key.Id, val);
00218 this.changedValues.Remove(key.Id);
00219 return true;
00220 }
00221 return false;
00222 }
00223
00224 public bool TryGetValue(Nutrient key, out double value){
00225 return TryGetValue(key.Id, out value);
00226 }
00227
00228 public bool TryGetValue(long id, out double value){
00229 NutritionalValue val = null;
00230 if(this.cachedValues.TryGetValue(id, out val)){
00231 value = val.Value;
00232 return true;
00233 }
00234 if(this.changedValues.TryGetValue(id, out val)){
00235 value = val.Value;
00236 return true;
00237 }
00238 value = new double();
00239 return false;
00240 }
00241
00242 public double this[Nutrient key]{
00243 get{
00244 double val;
00245 if(this.TryGetValue(key, out val))
00246 return val;
00247 throw new KeyNotFoundException(key.TagName + " was not found in the dictionary.");
00248 }
00249 set { this.SetValue(key.Id, value); }
00250 }
00251
00252 #region NutritionDefinitionCollection
00253 private class NutritionDefinitionCollection : ICollection<Nutrient>
00254 {
00255 private NutritionDictionary owner;
00256 public NutritionDefinitionCollection(NutritionDictionary owner){
00257 this.owner = owner;
00258 }
00259
00260 #region IEnumerable<Nutrient> implementation
00261 public IEnumerator<Nutrient> GetEnumerator(){
00262 foreach(long id in owner.cachedValues.Keys)
00263 yield return Nutrient.CreateNutritionDefinition(id);
00264 foreach(long id in owner.changedValues.Keys)
00265 yield return Nutrient.CreateNutritionDefinition(id);
00266 }
00267 #endregion
00268
00269 #region IEnumerable implementation
00270 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
00271 {
00272 return this.GetEnumerator();
00273 }
00274 #endregion
00275
00276 #region ICollection<Nutrient> implementation
00277 public void Add(Nutrient item){
00278 throw new NotSupportedException("This is a read-only collection, modify the NutritionDictionary instead!");
00279 }
00280
00281 public void Clear(){
00282 throw new NotSupportedException("This is a read-only collection, modify the NutritionDictionary instead!");
00283 }
00284
00285 public bool Contains(Nutrient item){
00286 return this.owner.ContainsKey(item);
00287 }
00288
00289 public void CopyTo(Nutrient[] array, int arrayIndex){
00290 if(arrayIndex < 0)
00291 throw new ArgumentOutOfRangeException("arrayIndex", "arrayIndex cannot be less than 0");
00292 foreach(Nutrient def in this)
00293 array[arrayIndex++] = def;
00294 }
00295
00296 public bool Remove(Nutrient item){
00297 throw new NotSupportedException("This is a read-only collection, modify the NutritionDictionary instead!");
00298 }
00299
00300 public int Count{
00301 get { return this.owner.Count; }
00302 }
00303
00304 public bool IsReadOnly{
00305 get { return true; }
00306 }
00307 #endregion
00308 }
00309 #endregion
00310
00311 public ICollection<Nutrient> Keys{
00312 get { return new NutritionDefinitionCollection(this); }
00313 }
00314
00315 #region NutritionValueCollection
00316 private class NutritionValueCollection : ICollection<double>
00317 {
00318 private NutritionDictionary owner;
00319 public NutritionValueCollection(NutritionDictionary owner){
00320 this.owner = owner;
00321 }
00322
00323 #region IEnumerable<double> implementation
00324 public IEnumerator<double> GetEnumerator(){
00325 foreach(var val in owner.cachedValues.Values)
00326 yield return val.Value;
00327 foreach(var val in owner.changedValues.Values)
00328 yield return val.Value;
00329 }
00330 #endregion
00331
00332 #region IEnumerable implementation
00333 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
00334 {
00335 return this.GetEnumerator();
00336 }
00337 #endregion
00338
00339 #region ICollection<double> implementation
00340 public void Add(double item){
00341 throw new NotSupportedException("This is a read-only collection, modify the NutritionDictionary instead!");
00342 }
00343
00344 public void Clear(){
00345 throw new NotSupportedException("This is a read-only collection, modify the NutritionDictionary instead!");
00346 }
00347
00348 public bool Contains(double item){
00349 foreach(double val in this){
00350 if(val == item)
00351 return true;
00352 }
00353 return false;
00354 }
00355
00356 public void CopyTo(double[] array, int arrayIndex){
00357 if(arrayIndex < 0)
00358 throw new ArgumentOutOfRangeException("arrayIndex", "arrayIndex cannot be less than 0");
00359 foreach(double val in this)
00360 array[arrayIndex++] = val;
00361 }
00362
00363 public bool Remove(double item){
00364 throw new NotSupportedException("This is a read-only collection, modify the NutritionDictionary instead!");
00365 }
00366
00367 public int Count{
00368 get { return this.owner.Count; }
00369 }
00370
00371 public bool IsReadOnly{
00372 get { return true; }
00373 }
00374 #endregion
00375 }
00376 #endregion
00377
00378 public ICollection<double> Values{
00379 get { return new NutritionValueCollection(this); }
00380 }
00381 #endregion
00382
00383 #region IEnumerable<KeyValuePair<Nutrient, double>> implementation
00384 public IEnumerator<KeyValuePair<Nutrient, double>> GetEnumerator(){
00385 foreach(KeyValuePair<long, NutritionalValue> pair in this.cachedValues)
00386 yield return new KeyValuePair<Nutrient, double>(Nutrient.CreateNutritionDefinition(pair.Key), pair.Value.Value);
00387 }
00388 #endregion
00389
00390 #region IEnumerable implementation
00391 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
00392 {
00393 return this.GetEnumerator();
00394 }
00395 #endregion
00396
00397 #region ICollection<KeyValuePair<Nutrient, double>> implementation
00398 public void Add(KeyValuePair<Nutrient, double> item){
00399 this.SetValue(item.Key.Id, item.Value);
00400 }
00401
00402 public void Clear(){
00403 List<long> ids = new List<long>(this.cachedValues.Keys);
00404 foreach(var id in ids)
00405 this.Remove(Nutrient.CreateNutritionDefinition(id));
00406 ids = new List<long>(this.changedValues.Keys);
00407 foreach(var id in ids)
00408 this.Remove(Nutrient.CreateNutritionDefinition(id));
00409 }
00410
00411 public bool Contains(KeyValuePair<Nutrient, double> item){
00412 double val;
00413 return this.TryGetValue(item.Key, out val) && val == item.Value;
00414 }
00415
00416 public void CopyTo(KeyValuePair<Nutrient, double>[] array, int arrayIndex){
00417 if(arrayIndex < 0)
00418 throw new ArgumentOutOfRangeException("arrayIndex", "arrayIndex cannot be less than 0");
00419 foreach(KeyValuePair<Nutrient, double> pair in this)
00420 array[arrayIndex++] = pair;
00421 }
00422
00423 public bool Remove(KeyValuePair<Nutrient, double> item){
00424 NutritionalValue val = null;
00425 if(this.cachedValues.TryGetValue(item.Key.Id, out val)){
00426 if(val.Value == item.Value)
00427 return this.Remove(item.Key);
00428 }
00429 if(this.changedValues.TryGetValue(item.Key.Id, out val)){
00430 if(val.Value == item.Value)
00431 return this.Remove(item.Key);
00432 }
00433 return false;
00434 }
00435
00436
00437 public int Count{
00438 get { return this.cachedValues.Count + this.changedValues.Count; }
00439 }
00440
00441 public bool IsReadOnly{
00442 get { return false; }
00443 }
00444 #endregion
00445 }
00446 }
00447 }