void SetFirstFailure(Specification specification)
 {
   if (_firstFail == null)
   {
     _firstFail = specification;
   }
 }
 void SetFirstNotImplemented(Specification specification)
 {
   if (_firstNotImplemented == null)
   {
     _firstNotImplemented = specification;
   }
 }
    public void Visit(Run run)
    {
      _firstFail = null;
      _lastFail = null;

      run.Assemblies.Each(Visit);

      run.NextFailed = _firstFail;
    }
    public void Visit(Run run)
    {
      _firstNotImplemented = null;
      _lastNotImplemented = null;

      run.Assemblies.Each(Visit);

      run.NextNotImplemented = _firstNotImplemented;
    }
    public void Visit(Run run)
    {
      _firstIgnored = null;
      _lastIgnored = null;

      run.Assemblies.Each(Visit);

      run.NextIgnored = _firstIgnored;
    }
    public static Specification LinkNotImplementedTo(this Specification specification, Specification linkTo)
    {
      if (linkTo != null)
      {
        specification.PreviousNotImplemented = linkTo;
        linkTo.NextNotImplemented = specification;
      }

      return specification;
    }
    public static Specification LinkFailureTo(this Specification specification, Specification linkTo)
    {
      if (linkTo != null)
      {
        specification.PreviousFailed = linkTo;
        linkTo.NextFailed = specification;
      }

      return specification;
    }
    public static Specification LinkIgnoredTo(this Specification specification, Specification linkTo)
    {
      if (linkTo != null)
      {
        specification.PreviousIgnored = linkTo;
        linkTo.NextIgnored = specification;
      }

      return specification;
    }
    public void Visit(Specification specification)
    {
      if (IsImplemented(specification))
      {
        return;
      }

      _lastNotImplemented = specification.LinkNotImplementedTo(_lastNotImplemented);
      SetFirstNotImplemented(specification);
    }
    public void Visit(Specification specification)
    {
      if (IsSuccessful(specification))
      {
        return;
      }

      _lastFail = specification.LinkFailureTo(_lastFail);
      SetFirstFailure(specification);
    }
    public void Visit(Specification specification)
    {
      if (!HasSupplements(specification))
      {
        return;
      }

      CreatePathForResources();

      var images = ImageSupplementsOf(specification);
      var html = HtmlSupplementsOf(specification);
      var files = images.Union(html);

      var replaced = files.Select(x =>
        {
          try
          {
            string destinationFileName = CopySupplementToResources(x.ItemValue);
            return x.UpdateItemValue(destinationFileName);
          }
          catch (Exception ex)
          {
            var message = String.Format("Failed to copy supplement {0}\r\n{1}", x.ItemValue, ex);
            var key = TextSupplementPrefix + x.ItemKey + "-error";
            while (specification.Supplements[x.Name].ContainsKey(key))
            {
              key += "-error";
            }
            
            return x.UpdateItemKeyAndValue(key, message);
          }
        });

      replaced.ToList().Each(x =>
        {
          if (x.ItemKey != x.UpdatedItemKey)
          {
            specification.Supplements[x.Name].Remove(x.ItemKey);
            specification.Supplements[x.Name].Add(x.UpdatedItemKey, null);
          }

          specification.Supplements[x.Name][x.UpdatedItemKey] = x.UpdatedItemValue;
        });
    }
 static bool HasSupplements(Specification specification)
 {
   return specification.Supplements.Any();
 }
 static IEnumerable<Supplement> SupplementsWithKey(Specification specification, string key)
 {
   return specification.Supplements.Keys
     .SelectMany(name => specification
                           .Supplements.SelectMany(x => x.Value)
                           .Where(x => x.Key.StartsWith(key))
                           .Select(x => new Supplement { Name = name, ItemKey = x.Key, ItemValue = x.Value }));
 }
 static IEnumerable<Supplement> HtmlSupplementsOf(Specification specification)
 {
   return SupplementsWithKey(specification, HtmlSupplementPrefix);
 }
 static bool IsImplemented(Specification specification)
 {
   return specification.Status != Status.NotImplemented;
 }
 static bool IsFailing(Specification specification)
 {
   return specification.Status != Status.Failing;
 }
 static bool IsRun(Specification specification)
 {
   return specification.Status != Status.Ignored;
 }
 Specification AssignId(Specification node)
 {
   node.Id = _nextId.ToString(CultureInfo.InvariantCulture);
   _nextId++;
   return node;
 }
 public void Visit(Specification specification)
 {
 }
 static bool IsSuccessful(Specification specification)
 {
   return specification.Status != Status.Failing;
 }