public void Craft(string fdname, int num)
        {
            int index = list.FindIndex(x => x.fdname.Equals(fdname, StringComparison.InvariantCultureIgnoreCase));

            if (index >= 0)
            {
                MaterialCommodities mc = list[index];
                mc.count    = Math.Max(mc.count - num, 0);
                list[index] = mc;
            }
        }
 public void Clear(bool commodity)
 {
     for (int i = 0; i < list.Count; i++)
     {
         MaterialCommodities mc = list[i];
         if (commodity == (mc.category == MaterialCommodities.CommodityCategory))
         {
             mc.count = 0;
             list[i]  = mc;
         }
     }
 }
        public void Set(string cat, string fdname, int num, double price, SQLiteConnectionUser conn, bool ignorecatonsearch = false)
        {
            int index = EnsurePresent(cat, fdname, conn);
            MaterialCommodities mc = list[index];

            mc.count = num;
            if (price > 0)
            {
                mc.price = price;
            }

            list[index] = mc;
        }
        // ignore cat is only used if you don't know what it is
        public void Change(string cat, string fdname, int num, long price, SQLiteConnectionUser conn, bool ignorecatonsearch = false)
        {
            int index = EnsurePresent(cat, fdname, conn, ignorecatonsearch);
            MaterialCommodities mc = list[index];

            double costprev = mc.count * mc.price;
            double costnew  = num * price;

            mc.count = Math.Max(mc.count + num, 0);;

            if (mc.count > 0 && num > 0)                    // if bought (defensive with mc.count)
            {
                mc.price = (costprev + costnew) / mc.count; // price is now a combination of the current cost and the new cost. in case we buy in tranches
            }
            list[index] = mc;
        }
        // ifnorecatonsearch is used if you don't know if its a material or commodity.. for future use.

        private int EnsurePresent(string cat, string fdname, SQLiteConnectionUser conn, bool ignorecatonsearch = false)
        {
            int index = list.FindIndex(x => x.fdname.Equals(fdname, StringComparison.InvariantCultureIgnoreCase) && (ignorecatonsearch || x.category.Equals(cat, StringComparison.InvariantCultureIgnoreCase)));

            if (index >= 0)
            {
                return(index);
            }
            else
            {
                MaterialCommodityDB mcdb = MaterialCommodityDB.EnsurePresent(cat, fdname, conn); // get a MCDB of this
                MaterialCommodities mc   = new MaterialCommodities(mcdb);                        // make a new entry
                list.Add(mc);
                return(list.Count - 1);
            }
        }
        //return maximum can make, how many made, needed string.

        static public Tuple <int, int, string> HowManyLeft(List <MaterialCommodities> list, Recipe r, List <MaterialCommodities> shoppinglist = null, int tomake = 0)
        {
            int           max    = int.MaxValue;
            StringBuilder needed = new StringBuilder(64);

            for (int i = 0; i < r.ingredients.Length; i++)
            {
                string ingredient = r.ingredients[i];

                int mi   = list.FindIndex(x => x.shortname.Equals(ingredient));
                int got  = (mi > 0) ? list[mi].scratchpad : 0;
                int sets = got / r.count[i];

                max = Math.Min(max, sets);

                int need = r.count[i] * tomake;

                if (got < need)
                {
                    if (shoppinglist != null)
                    {
                        int shopentry = shoppinglist.FindIndex(x => x.shortname.Equals(ingredient));
                        if (shopentry >= 0)
                        {
                            shoppinglist[shopentry].scratchpad += (need - got);
                        }
                        else
                        {
                            MaterialCommodityDB db = MaterialCommodityDB.GetCachedMaterialByShortName(ingredient);
                            if (db != null)                                           // MUST be there, its well know, but will check..
                            {
                                MaterialCommodities mc = new MaterialCommodities(db); // make a new entry
                                mc.scratchpad = (need - got);
                                shoppinglist.Add(mc);
                            }
                        }
                    }

                    string dispName;
                    if (mi > 0)
                    {
                        dispName = (list[mi].category == MaterialCommodityDB.MaterialEncodedCategory || list[mi].category == MaterialCommodityDB.MaterialManufacturedCategory) ? " " + list[mi].name : list[mi].shortname;
                    }
                    else
                    {
                        MaterialCommodityDB db = MaterialCommodityDB.GetCachedMaterialByShortName(ingredient);
                        dispName = (db.category == MaterialCommodityDB.MaterialEncodedCategory || db.category == MaterialCommodityDB.MaterialManufacturedCategory) ? " " + db.name : db.shortname;
                    }
                    string s = (need - got).ToStringInvariant() + dispName;
                    if (needed.Length == 0)
                    {
                        needed.Append("Need:" + s);
                    }
                    else
                    {
                        needed.Append("," + s);
                    }
                }
            }

            int made = 0;

            if (max > 0 && tomake > 0)             // if we have a set, and use it up
            {
                made = Math.Min(max, tomake);      // can only make this much
                StringBuilder usedstr = new StringBuilder(64);

                for (int i = 0; i < r.ingredients.Length; i++)
                {
                    int mi = list.FindIndex(x => x.shortname.Equals(r.ingredients[i]));
                    System.Diagnostics.Debug.Assert(mi != -1);
                    int used = r.count[i] * made;
                    list[mi].scratchpad -= used;
                    string dispName = (list[mi].category == MaterialCommodityDB.MaterialEncodedCategory || list[mi].category == MaterialCommodityDB.MaterialManufacturedCategory) ? " " + list[mi].name : list[mi].shortname;
                    usedstr.AppendPrePad(used.ToStringInvariant() + dispName, ",");
                }

                needed.AppendPrePad("Used: " + usedstr.ToString(), ", ");
            }

            return(new Tuple <int, int, string>(max, made, needed.ToNullSafeString()));
        }