public ActionResult Create(Marker marker) { if (ModelState.IsValid) { int userId = WebSecurity.GetUserId(User.Identity.Name); using (TransactionScope trans = new TransactionScope()) { try { var markerText = marker.Text.Trim(); bool isStart = false; bool isStop = false; bool setStartTime = false; bool setDuration = false; bool isDuration = false; int? durationDays = null; int? durationHours = null; int? durationMinutes = null; int? startTimeHours = null; int? startTimeMinutes = null; bool canCommit = true; // Store the Marker. var newMarker = new Marker(); newMarker.CreatedByUserId = userId; newMarker.CreatedUtc = DateTime.UtcNow; newMarker.Text = markerText; db.Markers.Add(newMarker); db.SaveChanges(); // Process the commands part first... // Is this a start or end? if (markerText.EndsWith("+")) { isStart = true; markerText = markerText.TrimEnd('+').Trim(); } else if (markerText.EndsWith("-")) { isStop = true; markerText = markerText.TrimEnd('-').Trim(); } var durationMatch = Regex.Match(markerText, "-[dD]:[0-9]{2,6}"); if (durationMatch.Success) { setDuration = true; // We have been given a duration indicator // so we'll create a completed marker instance with // Start/End equal to duration //2 chars == minutes //4 chars == hours.minutes //6 chars == days.hours.minutes } var timeMatch = Regex.Match(markerText, @"-[tT]:[0-2]{1}[0-9]{1}[0-5]{1}[0-9]{1}"); if (timeMatch.Success) { setStartTime = true; startTimeHours = System.Convert.ToInt32(timeMatch.Value.Substring(3, 2)); startTimeMinutes = System.Convert.ToInt32(timeMatch.Value.Substring(5, 2)); } // TODO Duration and Time commands // Keyword processing... // Parse the sections, keywords and the rest... //if (markerText.Contains(";")) { var markerParts = markerText .Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); // What if they haven't specified a ; char? // Do we consider it to be all Keywords // Or do we require a ; // Easier to require it than provide the functionality to clean up afterwards // if they are entering using a UI then we can ensure the proper structure // If they are entering via text then they should know better. // Alternatively, we could have a generic TEMP keyword that stuff could be assigned // to in the absense of a specific Keyword var keywordsText = markerParts[0].TrimStart().Trim(); string messageText = null; if (markerParts.Length > 1) { messageText = markerParts[1].TrimStart().Trim(); } var keywordParts = keywordsText .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .ToList(); int? parentId = null; var keywordInstances = new List<KeywordInstance>(); for (int i = 0; i < keywordParts.Count(); i++) { bool bottomOfTheStack = (i == keywordParts.Count() - 1); var currentKeywordText = keywordParts[i].TrimStart().Trim(); // Does this keyword already exist for this user? var currentKeyword = db.Keywords .SingleOrDefault(kw => kw.Text.ToLower() == currentKeywordText.ToLower() && kw.CreatedByUserId == userId); if (currentKeyword == null) { currentKeyword = new Keyword(); currentKeyword.CreatedByUserId = userId; currentKeyword.Text = currentKeywordText; currentKeyword.CreatedUtc = DateTime.UtcNow; db.Keywords.Add(currentKeyword); db.SaveChanges(); } // Is this keyword already in use? // ie. Is there already a Keyword Instance in use? var currentKeywordInstance = db.KeywordInstances .SingleOrDefault(kwi => kwi.KeywordId == currentKeyword.KeywordId && ((parentId == null && kwi.ParentInstanceId == null) || (kwi.ParentInstanceId == parentId))); if (currentKeywordInstance == null) { currentKeywordInstance = new KeywordInstance(); currentKeywordInstance.KeywordId = currentKeyword.KeywordId; currentKeywordInstance.CreatedUtc = DateTime.UtcNow; // if we have been told to start then all instances need to be running... currentKeywordInstance.IsRunning = isStart; currentKeywordInstance.ParentInstanceId = parentId; // Are we a parent? // If we are not at the bottom of the stack then yes we are. if (!bottomOfTheStack) { currentKeywordInstance.IsParent = true; } currentKeyword.KeywordInstances.Add(currentKeywordInstance); } else { if (isStart) { // TODO NB. Check that we're not already running. // We need to check this at the bottom of the stack // If it's already running then we don't want to reissue the // command. // Might need to do this on the way back up for parent instances. currentKeywordInstance.IsRunning = true; } // Are we a parent? // If we are not at the bottom of the stack then yes we are. if (!bottomOfTheStack) { currentKeywordInstance.IsParent = true; } // Are we stopping? // We will do this as a second pass to make sure we stop correctly. } // NB. If they do not specify the parentage of the keyword they // will end up with a separate instance of the keyword which // they can hook up later. // Are we to create an instance action? // For parents we are only concerned with Starts (if we are not already started) // For the instance at the bottom of the pile we will be concerned // with all. bool createInstanceAction = false; InstanceActionType instanceActionType = null; // Are we in the last keyword? if (bottomOfTheStack) { // Create a new Instance Action // else, note the id of this instance as the parent of the next. var newAction = new InstanceAction(); if (isStart) { instanceActionType = db.InstanceActionTypes .Single(ia => ia.TypeName == "Start"); createInstanceAction = true; } else if (!isStop) { instanceActionType = db.InstanceActionTypes .Single(ia => ia.TypeName == "Note"); createInstanceAction = true; } } else { if (isStart) { instanceActionType = db.InstanceActionTypes .Single(ia => ia.TypeName == "ChildStart"); createInstanceAction = true; // TODO Might need to do this on the way back up // after we've checked that this command is necessary // NB. Stops will be dealt with on the way back. } } if (createInstanceAction) { // Create a new Instance Action // else, note the id of this instance as the parent of the next. var newAction = new InstanceAction(); newAction.InstanceActionType = instanceActionType; newAction.Text = messageText; newAction.CreatedUtc = DateTime.UtcNow; newAction.MarkerId = newMarker.MarkerId; currentKeywordInstance.Actions.Add(newAction); } db.SaveChanges(); keywordInstances.Add(currentKeywordInstance); parentId = currentKeywordInstance.KeywordInstanceId; } // If we have been asked to stop then we have to back up // the hierarchy to check which ca be stopped. // If a parent instance still has running instances then we cannot stop // that parent. if (isStop) { StopKeywordInstance(keywordInstances.Last().KeywordInstanceId, false); } //} else { // Send it back // "Keywords not correctly specified.".Dump(); //} if (canCommit) { trans.Complete(); } // TODO ELSE let them know why such as duplicate start return RedirectToAction("Index", "Home"); } catch (Exception ex) { // Deal with it // Return a message saying that something has gone wrong throw new Exception("Could not complete action: " + ex.Message); } } } return View(marker); }
public ActionResult Edit(Marker marker) { if (ModelState.IsValid) { db.Entry(marker).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } return View(marker); }