public static Instance Run(ControllerConfiguration context, Guid targetKey)
        {
            var instancesController = new Instances(context);

            var searchEmpty = instancesController.SearchInstances(targetKey);
            Debug.Assert(searchEmpty.TotalCount == 0);
            Debug.Assert(searchEmpty.Instances.Count() == 0);

            var testInstance = new Instance() { TargetKey = targetKey };
            instancesController.CreateInstance(testInstance);
            var createdInstance = instancesController.GetInstance(testInstance.Key);
            Debug.Assert(testInstance.Key == createdInstance.Key);
            Debug.Assert(testInstance.Name == createdInstance.Name);
            Debug.Assert(testInstance.TargetKey == createdInstance.TargetKey);

            var searchSingle = instancesController.SearchInstances(targetKey);
            Debug.Assert(searchSingle.TotalCount == 1);
            Debug.Assert(searchSingle.Instances.Count() == 1);
            Debug.Assert(searchSingle.Instances.First().Key == createdInstance.Key);
            Debug.Assert(searchSingle.Instances.First().Name == createdInstance.Name);

            createdInstance.Tags.Add("Foo", "Bar");
            instancesController.UpdateInstance(createdInstance);

            var taggedInstance = instancesController.GetInstance(createdInstance.Key);
            Debug.Assert(taggedInstance.Tags.Count == 1);
            Debug.Assert(taggedInstance.Tags.ContainsKey("Foo"));
            Debug.Assert(taggedInstance.Tags["Foo"] == "Bar");

            taggedInstance.Name = "Updated Test Instance";
            instancesController.UpdateInstance(taggedInstance);

            var renamedInstance = instancesController.GetInstance(taggedInstance.Key);
            Debug.Assert(renamedInstance.Name == taggedInstance.Name);

            var searchRenamed = instancesController.SearchInstances(targetKey);
            Debug.Assert(searchRenamed.TotalCount == 1);
            Debug.Assert(searchRenamed.Instances.First().Name == renamedInstance.Name);

            taggedInstance.Name = "Test Instance";
            instancesController.UpdateInstance(taggedInstance);

            SearchAndDelete(targetKey, instancesController, taggedInstance);

            return testInstance;
        }
        public ActionResult AddTag(Guid id, string name, string value)
        {
            var instances = new Instances();
            var instance = instances.GetInstance(id);
            if (instance.Tags.ContainsKey(name))
                throw new HttpException(406, "Tag name already exists");

            instance.Tags.Add(name, value);
            instances.UpdateInstance(instance);
            if (Request.IsAjaxRequest())
                return Json(null);
            else
                return RedirectToAction("EditTags", new { id = id });
        }
        //
        // GET: /Instances/ConfirmDelete/5
        public ActionResult ConfirmDelete(Guid id)
        {
            var instances = new Instances();
            var targets = new Targets();
            var groups = new Groups();

            var instance = instances.GetInstance(id);
            var target = targets.GetTarget(instance.TargetKey);
            var group = groups.GetGroup(target.GroupKey);

            var model = new InstanceDetails()
            {
                Instance = instance,
                Target = target,
                Group = group,
            };

            return View(model);
        }
        //
        // GET: /Logs/
        public ActionResult Index(Guid iid, string m = null, int c = 50)
        {
            var logs = new Logs();
            var instances = new Instances();
            var targets = new Targets();
            var groups = new Groups();

            var logPage = logs.GetLogEntryPage(iid, m, c);
            var instance = instances.GetInstance(iid);
            var target = targets.GetTarget(instance.TargetKey);
            var group = groups.GetGroup(target.GroupKey);

            var model = new LogIndex()
            {
                LogEntryPage = logPage,
                Instance = instance,
                Target = target,
                Group = group,
            };

            return View(model);
        }
        public ActionResult Details(Guid iid, long t, LogStatus s)
        {
            var logs = new Logs();
            var instances = new Instances();
            var targets = new Targets();
            var groups = new Groups();

            var log = logs.GetLogEntry(iid, new DateTime(t, DateTimeKind.Utc), s);
            var instance = instances.GetInstance(iid);
            var target = targets.GetTarget(instance.TargetKey);
            var group = groups.GetGroup(target.GroupKey);

            var model = new LogDetails()
            {
                LogEntry = log,
                Instance = instance,
                Target = target,
                Group = group,
            };

            return View(model);
        }
        public JsonResult UpdateTag(Guid id, string oldName, string name, string value)
        {
            var instances = new Instances();
            var instance = instances.GetInstance(id);
            if (!instance.Tags.ContainsKey(oldName))
                throw new HttpException(404, "Tag not found");

            if (oldName == name)
            {
                instance.Tags[name] = value;
            }
            else if (instance.Tags.ContainsKey(name))
            {
                throw new HttpException(406, "Tag name already exists");
            }
            else
            {
                instance.Tags.Remove(oldName);
                instance.Tags.Add(name, value);
            }
            instances.UpdateInstance(instance);
            return Json(null);
        }
        public JsonResult RemoveTag(Guid id, string name)
        {
            var instances = new Instances();
            var instance = instances.GetInstance(id);
            if (!instance.Tags.ContainsKey(name))
                throw new HttpException(404, "Tag not found");

            instance.Tags.Remove(name);
            instances.UpdateInstance(instance);
            return Json(null);
        }
        public ActionResult Edit(Guid id, string name)
        {
            var instances = new Instances();
            var instance = instances.GetInstance(id);
            instance.Name = name;

            if (string.IsNullOrWhiteSpace(name)) ModelState.AddModelError("name", "Name is required.");

            if (ModelState.IsValid)
            {
                try
                {
                    instances.UpdateInstance(instance);

                    return RedirectToAction("Details", new { id = instance.Key });
                }
                catch (Exception ex)
                {
                    ModelState.AddModelError("Error", ex);
                }
            }

            var targets = new Targets();
            var groups = new Groups();

            var target = targets.GetTarget(instance.TargetKey);
            var group = groups.GetGroup(target.GroupKey);

            var model = new InstanceDetails()
            {
                Instance = instance,
                Target = target,
                Group = group,
            };

            return View(model);
        }
        public ActionResult Delete(Guid id, FormCollection collection)
        {
            var instances = new Instances();
            var instance = instances.GetInstance(id);
            try
            {
                instances.DeleteInstance(id);

                return RedirectToAction("Index", new { tid = instance.TargetKey });
            }
            catch(Exception ex)
            {
                ModelState.AddModelError("Error", ex);
            }

            var targets = new Targets();
            var groups = new Groups();

            var target = targets.GetTarget(instance.TargetKey);
            var group = groups.GetGroup(target.GroupKey);

            var model = new InstanceDetails()
            {
                Instance = instance,
                Target = target,
                Group = group,
            };

            return View("ConfirmDelete", model);
        }