public void AdvanceAllBarcodes(IRepositoryFactory repositoryFactory, UserJob userJob, Stage stage)
        {
            var barcodes = userJob.UserJobPlates.SelectMany(a => a.Barcodes).Where(a => a.Stage == stage && !a.Done);

            if (barcodes.Any())
            {
                foreach(var bc in barcodes)
                {
                    AdvanceStage(repositoryFactory, bc, userJob);
                }
            }
        }
        public void AdvanceStage(IRepositoryFactory repositoryFactory, Barcode barcode, UserJob userJob)
        {
            // barcode is complete and cannot be advanced
            if (barcode.Stage.IsComplete) return;

            var jobType = userJob.JobType;
            var stage = barcode.Stage;
            var plate = barcode.UserJobPlate;

            // by default only insert one new barcode
            var subPlates = 1;

            // jobs with large plate, gets broken down to 4 barcodes
            if (_largeplateJobs.Contains(jobType.Id) && userJob.PlateType == PlateTypes.ThreeEightyFour && stage.Order == 2)
            {
                subPlates = 4;
            }

            Primer primer1 = barcode.Primer;
            Primer primer2 = null;
            var directional = false;

            // if it's directional, you need a forward and back for each sub plate to generate
            if (_directionalJobs.Contains(jobType.Id))
            {
                // bacterial clone, 2nd stage, take the direction
                if (jobType.Id == (int)JobTypeIds.BacterialClone && stage.Order == 3 && userJob.UserJobBacterialClone.SequenceDirection == SequenceDirection.Backward)
                {
                    directional = true;
                    primer1 = userJob.UserJobBacterialClone.Primer1;
                    primer2 = userJob.UserJobBacterialClone.Primer2;
                }

                // frankly, I think this was old code that isn't used any more
                // pcr and purified dna take the direction at 1st stage
                if ((jobType.Id == (int)JobTypeIds.PCRProduct || jobType.Id == (int)JobTypeIds.PurifiedDna) && stage.Order == 2 && userJob.UserJobDna.SequenceDirection == SequenceDirection.Backward)
                {
                    directional = true;
                    primer1 = userJob.UserJobDna.Primer1;
                    primer2 = userJob.UserJobDna.Primer2;
                }
            }

            // load the next stage
            var nextStage = jobType.Stages.First(a => a.Order == stage.Order + 1);

            for (var i = 0; i < subPlates; i++)
            {
                // write the first plate
                var newBarcode1 = new Barcode() { SourceBarcode = barcode, Stage = nextStage, Primer = primer1, SubPlateId = i + 1};
                plate.AddBarcode(newBarcode1);

                if (directional)
                {
                    var newBarcode2 = new Barcode() { SourceBarcode = barcode, Stage = nextStage, Primer = primer2, SubPlateId = i + 1 };
                    plate.AddBarcode(newBarcode2);
                }
            }

            barcode.Done = true;

            repositoryFactory.UserJobPlateRepository.EnsurePersistent(plate);

            userJob.LastUpdate = DateTime.Now;
            repositoryFactory.UserJobRepository.EnsurePersistent(userJob);
        }
        private bool SaveUserRunSubmission(SequencingPostModel postModel)
        {
            ValidateUserRunSubmission(postModel);

            if (ModelState.IsValid)
            {
                var userJob = new UserJob();
                var userJobUserRun = new UserJobUserRun();

                AutoMapper.Mapper.Map(postModel, userJob);
                AutoMapper.Mapper.Map(postModel, userJobUserRun);
                userJob.UserJobUserRun = userJobUserRun;
                userJob.User = GetCurrentUser(true);
                userJob.RechargeAccount = postModel.RechargeAccount;

                AddPlates(postModel.PlateNames, userJob, userJob.JobType);

                _repositoryFactory.UserJobRepository.EnsurePersistent(userJob);

                return true;
            }

            return false;
        }
        private bool SaveSublibrarySubmission(SequencingPostModel postModel)
        {
            ValidateSublibrarySubmission(postModel);

            if (ModelState.IsValid)
            {
                var userJob = new UserJob();
                var userJobSublibrary = new UserJobSublibrary();

                AutoMapper.Mapper.Map(postModel, userJob);
                AutoMapper.Mapper.Map(postModel, userJobSublibrary);
                userJob.UserJobSublibrary = userJobSublibrary;
                userJob.User = GetCurrentUser(true);
                userJob.RechargeAccount = postModel.RechargeAccount;

                AddPlates(new List<string>() {userJob.Name}, userJob, userJob.JobType);

                _repositoryFactory.UserJobRepository.EnsurePersistent(userJob);

                return true;
            }

            return false;
        }
        private bool SaveBacterialClone(SequencingPostModel postModel)
        {
            ValidateBacterialClone(postModel);

            if (ModelState.IsValid)
            {
                var userJob = new UserJob();
                var userJobBacterialClone = new UserJobBacterialClone();

                AutoMapper.Mapper.Map(postModel, userJob);
                AutoMapper.Mapper.Map(postModel, userJobBacterialClone);
                userJob.UserJobBacterialClone = userJobBacterialClone;
                userJob.User = GetCurrentUser(true);
                userJob.RechargeAccount = postModel.RechargeAccount;

                AddPlates(postModel.PlateNames, userJob, userJob.JobType);

                if (postModel.Strain != null && postModel.Strain.IsOther())
                {
                    var strain = new Strain() { Name = postModel.NewStrain, Bacteria = postModel.Bacteria, Supplied = false };
                    userJob.UserJobBacterialClone.Strain = strain;
                }

                _repositoryFactory.UserJobRepository.EnsurePersistent(userJob);

                return true;
            }

            return false;
        }
        /// <summary>
        /// Adds the plates necessary for the original submission
        /// </summary>
        /// <param name="plateNames"></param>
        /// <param name="userJob"></param>
        private void AddPlates(List<string> plateNames, UserJob userJob, JobType jobType)
        {
            // figure out the stage
            Stage stage = null;

            switch(jobType.Id)
            {
                case (int)JobTypeIds.BacterialClone:
                    stage = _repositoryFactory.StageRepository.GetNullableById(StageIds.BcWebSubmittedPlates);
                    break;
                case (int)JobTypeIds.PCRProduct:
                    stage = _repositoryFactory.StageRepository.GetNullableById(StageIds.PcrWebSubmittedPlates);
                    break;
                case (int)JobTypeIds.UserRunSequencing:
                    stage = _repositoryFactory.StageRepository.GetNullableById(StageIds.UrsWebSubmittedPlates);
                    break;
                case (int)JobTypeIds.PurifiedDna:
                    stage = _repositoryFactory.StageRepository.GetNullableById(StageIds.PdWebSubmittedPlates);
                    break;
                case (int)JobTypeIds.Sublibrary:
                    stage = _repositoryFactory.StageRepository.GetNullableById(StageIds.SlWebSubmittedPlates);
                    break;
            }

            if (stage == null)
            {
                throw new ArgumentException("JobType");
            }

            foreach(var name in plateNames)
            {
                var plate = new UserJobPlate() {Name = name};
                var barcode = new Barcode() {Stage = stage};

                plate.AddBarcode(barcode);
                userJob.AddUserJobPlates(plate);
            }
        }