/// <summary> /// Puts the given job into the end of the production line. /// </summary> /// <param name="productName">The name of the product to enqueue.</param> /// <param name="jobID">The ID of the job to enqueue.</param> /// <returns>True if enqueing the job was successful; otherwise false.</returns> public bool EnqueueJob(string productName, int jobID) { if (productName == null) { throw new ArgumentNullException("productName"); } if (jobID < 0) { throw new ArgumentOutOfRangeException("jobID", "Production job ID must be non-negative!"); } if (!this.products.ContainsKey(productName)) { throw new InvalidOperationException(string.Format("Product '{0}' cannot be produced at this production line!", productName)); } if (this.itemCount.Read() == this.Capacity) { throw new InvalidOperationException("This production line has reached its capacity!"); } if (!this.CheckOwnerPlayer()) { this.RemoveAllJobs(); return(false); } /// Create a job and try to lock the resources of the owner player. ProductionJob job = this.CreateJob(productName, jobID); if (!job.LockResources()) { /// Unable to lock the necessary resources -> abort the job and cancel. job.Dispose(); return(false); } /// If there is no other job in the line, try to start the created job. if (this.itemCount.Read() == 0) { if (!job.Start()) { /// Unable to start the job -> abort the job and cancel. job.Dispose(); return(false); } } /// Job created -> enqueue it. this.jobs[this.CalculatePhysicalIndex(this.itemCount.Read())].Write(job); this.itemCount.Write(this.itemCount.Read() + 1); return(true); }
/// <summary> /// Removes the given job from the production line. /// </summary> /// <param name="jobID">The ID of the job to remove.</param> /// <remarks>If there is no job with the given ID then this function has no effect.</remarks> public void RemoveJob(int jobID) { if (jobID < 0) { throw new ArgumentOutOfRangeException("jobID", "Production job ID must be non-negative!"); } if (!this.CheckOwnerPlayer()) { this.RemoveAllJobs(); return; } int indexOfRemovedJob = -1; for (int index = 0; index < this.itemCount.Read(); index++) { int physicalIndex = this.CalculatePhysicalIndex(index); if (indexOfRemovedJob == -1 && this.jobs[physicalIndex].Read().ID == jobID) { /// Job found -> abort and remove it from the line. this.jobs[physicalIndex].Read().Dispose(); this.jobs[physicalIndex].Write(null); indexOfRemovedJob = index; } /// Replace the current item with the next item if the job has already been removed. if (indexOfRemovedJob != -1 && index < this.itemCount.Read() - 1) { int physicalIndexOfNext = this.CalculatePhysicalIndex(index + 1); this.jobs[physicalIndex].Write(this.jobs[physicalIndexOfNext].Read()); this.jobs[physicalIndexOfNext].Write(null); } } /// If the job has been removed, decrement the itemCount. if (indexOfRemovedJob != -1) { this.itemCount.Write(this.itemCount.Read() - 1); } /// If the first job has been removed, try to start the next job. if (indexOfRemovedJob == 0 && this.itemCount.Read() > 0) { ProductionJob nextJob = this.jobs[this.CalculatePhysicalIndex(0)].Read(); nextJob.Start(); } }
/// <summary> /// Continues the current production job. /// </summary> public void ContinueProduction() { if (this.itemCount.Read() == 0) { throw new InvalidOperationException("This production line is inactive!"); } if (!this.CheckOwnerPlayer()) { this.RemoveAllJobs(); return; } ProductionJob currentJob = this.jobs[this.CalculatePhysicalIndex(0)].Read(); if (currentJob.IsStarted) { /// Current job has been started -> continue it. if (currentJob.Continue()) { /// Current job finished working -> remove it from the line. currentJob.Dispose(); this.jobs[this.CalculatePhysicalIndex(0)].Write(null); this.startIndex.Write((this.startIndex.Read() + 1) % this.Capacity); this.itemCount.Write(this.itemCount.Read() - 1); /// If we still have jobs in the line, try to start the next one. if (this.itemCount.Read() > 0) { ProductionJob nextJob = this.jobs[this.CalculatePhysicalIndex(0)].Read(); nextJob.Start(); } } } else { /// Try to start the current job. currentJob.Start(); } }