/* return true if all conditions are met:
         *  a) any bills outstanding
         *  b) status is 'Idle'
         *  c) the usual reservation and forbidden checks pass
         */
        public override bool HasJobOnThing(Pawn pawn, Thing aThing, bool forced = false)
        {
            Building_GrowerBase_WorkTable grower = aThing as Building_GrowerBase_WorkTable;
            IBillGiver      billGiver            = aThing as IBillGiver;
            BillProcessor   processor            = grower.billProc;
            LocalTargetInfo target = aThing;

            if (grower == null || billGiver == null)
            {
                return(false);
            }

            if (grower.status == CrafterStatus.Crafting || grower.status == CrafterStatus.Finished)
            {
                JobFailReason.Is(GrowerBusyTrans);

                return(false);
            }

            if (!processor.AnyPendingRequests)
            {
                JobFailReason.Is(NoBillsQueuedTrans);
                return(false);
            }

            //check if the grower's cached ingredients search found ingredients for any bill
            if (grower.billProc.anyBillIngredientsAvailable == false)
            {
                JobFailReason.Is(NoIngredientsTrans);
                return(false);
            }

            if (aThing.IsBurning())
            {
                JobFailReason.Is(IsBurningTrans);
                return(false);
            }

            if (aThing.IsForbidden(pawn))
            {
                return(false);
            }

            if (!ThingIsUsableBillGiver(aThing))
            {
                return(false);
            }

            string reason = "";

            //if the grower isn't growing anything, loop through the billstack and check for any bill the pawn can do
            if (grower.billProc.ActiveBill == null)
            {
                if (GetBillPawnCanDo(pawn, grower, out reason) == null)
                {
                    JobFailReason.Is(reason);
                    return(false);
                }
            }

            else if (!PawnCanDoThisBill(pawn, grower.billProc.ActiveBill, target, out reason))
            {
                JobFailReason.Is(reason);
                return(false);
            }

            return(true);
        }//end HasJobOnThing()
 public Building_GrowerBase_WorkTable()
 {
     ingredientContainer = new ThingOwner <Thing>(this, false, LookMode.Deep);
     billProc            = new BillProcessor(this);
 }
        }//end HasJobOnThing()

        public override Job JobOnThing(Pawn p, Thing t, bool forced = false)
        {
            IBillGiver billGiver = t as IBillGiver;
            Building_GrowerBase_WorkTable grower = t as Building_GrowerBase_WorkTable;
            BillProcessor processor = grower.billProc;

            //if null is returned from this function, the game will throw an error. Instead,
            //return this simple wait job to avoid unnecessary errors.
            Job returnJobOnFailure = new Job(JobDefOf.Wait, 5);

            //check if there are any pending requests (unfulfilled bills)
            if (!processor.AnyPendingRequests)
            {
                QEEMod.TryLog("AnyPendingRequests is false inside JobOnThing()!");
                return(returnJobOnFailure);
            }

            //check if there are ingredients available for those bills
            if (processor.ingredientsAvailableNow.Count <= 0)
            {
                QEEMod.TryLog("ingredientsAvailableNow.Count is 0 inside JobOnThing()!");
                return(returnJobOnFailure);
            }

            //get the reference to the currently active bill
            Bill theBill = processor.ActiveBill;

            if (theBill == null)
            {
                QEEMod.TryLog("Attempt to get ActiveBill failed inside JobOnThing()!");
                return(returnJobOnFailure);
            }

            //get the cached ingredient that's available. This Thing is not always going to be used in the Job,
            //but we know there's at least one stack of this Thing available on the map
            Thing cachedThing;

            grower.billProc.ingredientsAvailableNow.TryGetValue(theBill.GetUniqueLoadID(), out cachedThing);
            if (cachedThing == null)
            {
                QEEMod.TryLog("Attempt to retrieve cached ingredients failed for " + theBill.GetUniqueLoadID());
                return(returnJobOnFailure);
            }

            //get the nearest Thing to the Pawn with the same ThingDef
            int   countForVat = 0;
            Thing thingToFill = IngredientUtility.ThingPawnShouldRetrieveForBill(theBill, p, ref countForVat);

            if (thingToFill == null)
            {
                grower.billProc.anyBillIngredientsAvailable = false;
                QEEMod.TryLog("ThingPawnShouldRetrieveForBill() is null for " + theBill.GetUniqueLoadID());

                return(returnJobOnFailure);
            }

            //all checks have passed! Return the Job and notify the grower that it's time to start Filling
            grower.Notify_FillingStarted(theBill);

            Job returnJob = new Job(QEJobDefOf.QE_LoadGrowerJob, t, thingToFill);

            returnJob.count = countForVat;
            returnJob.bill  = theBill;
            return(returnJob);
        }//end JobOnThing()