import "../library/common.eol";
import "../library/helper.eol";
import "../library/debug.eol";

context Entity {
  //[There are no constraints specified.]
}

context Event {
  //[There are no constraints specified.]
}

context PICS {
  //[There are no constraints specified.]
}

context StructuredTestObjective {
  //[There are no constraints specified.]
}

context PICSReference {
  //Combining Multiple 'PICSReference's 
  constraint MultiplePICS {
    check: self.container().picsReference->size() < 2 
      or self.container().picsReference->forAll(p | 
        self.container().picsReference->at(0) = p
        or (not p.comment->isEmpty()
            and (p.comment->first().body = 'and'
                or p.comment->first().body = 'or')))
    message:   self.prefix() + 
               "A 'Comment' with body containing an 'and' or 'or' shall be attached to the 'PICSReference' as a Boolean operand if there are two or more 'PICSReference's and it is not the first 'PICSReference'."
  }

}

context InitialConditions {
  //[There are no constraints specified.]
}

context ExpectedBehaviour {
  //[There are no constraints specified.]
}

context FinalConditions {
  //[There are no constraints specified.]
}

context EventSequence {
  //[There are no constraints specified.]
}

context RepeatedEventSequence {
  //Either 'repetitions', or 'interval' or neither shall be specified
  constraint RepetitionOrInterval {
    check:     self.repetitions.oclIsUndefined() or self.interval.oclIsUndefined()
    message:   self.prefix() + 
               "At most one of the optional properties 'repetitions' or 'interval' shall be defined."
  }

  //The 'repetitions' 'Value' shall be countable and positive
  constraint RepetitionCount {
    check:     true //This constraint cannot be expressed in OCL
    message:   self.prefix() + 
               "The expression assigned to the 'repetitions' property shall evaluate to a positive and countable 'Value'."
  }

  //The 'interval' 'Value' shall be countable and positive
  constraint RepetitionInterval {
    check:     true //This constraint cannot be expressed in OCL
    message:   self.prefix() + 
               "The expression assigned to the 'repetitions' property shall evaluate to a positive and countable 'Value'"
  }

}

context EventOccurrence {
  //Combining Multiple 'EventOccurrence's
  constraint MultipleEventOccurrences {
    check: self.container().oclIsTypeOf(EventSpecificationTemplate)
      or self.container().events->size() < 2 
      or self.container().events->forAll(o | 
      self.container().events->at(0) = o
      or (not o.comment->isEmpty()
      and (o.comment->first().body = 'and'
      or o.comment->first().body = 'or')))
    message:   self.prefix() + 
               "A 'Comment' with body containing an 'and' or 'or' shall be attached to the 'EventOccurrence' as an operand if there are two or more 'EventOccurrence's and it is not the first 'EventOccurrence'."
  }

}

context EventOccurrenceSpecification {
  //[There are no constraints specified.]
}

context EntityReference {
  //An 'Entity' or a 'ComponentInstance' shall be referenced.
  constraint EntityOrComponentInstance {
    check: (not self.entity.oclIsUndefined() and self.component.oclIsUndefined())
      or (self.entity.oclIsUndefined() and not self.component.oclIsUndefined())
    message:   self.prefix() + 
               "There shall be a reference to an 'Entity' or a 'ComponentInstance' but not both."
  }

}

context EventReference {
  //[There are no constraints specified.]
}

context Value {
  //[There are no constraints specified.]
}

context LiteralValue {
  //[There are no constraints specified.]
}

context Content {
  //No nested 'Content's if 'Value' is provided 
  constraint ContentOrValue {
    check:     self.content->isEmpty() or self.value.oclIsUndefined()
    message:   self.prefix() + 
               "Either nested 'Content's or 'Value' may be specified within 'Content', but not both."
  }

}

context LiteralValueReference {
  //Referenced 'LiteralValue' visibility
  constraint VisibleValue {
    check: self.getTestObjective().contains(self.content) 
      and self.getTestObjective().indexOf(self.content) < self.getTestObjective().indexOf(self)
    message:   self.prefix() + 
               "Only 'LiteralValue's defined within previous 'EventOccurrence's of the containing 'StructuredTestObjective' may be referenced."
  }

}

context ContentReference {
  //Referenced 'Content' visibility
  constraint VisibleContent {
    check: self.getTestObjective().contains(self.content) 
      and self.getTestObjective().indexOf(self.content) < self.getTestObjective().indexOf(self)
    message:   self.prefix() + 
               "Only 'Content' defined within previous 'EventOccurrence's of the containing 'StructuredTestObjective' may be referenced."
  }

}

context DataReference {
  //'DataUse' restrictions within 'DataReference'
  constraint DataReferenceContents {
    check: self.content.oclIsTypeOf(StaticDataUse)
	  and self.content.argument->forAll(a | a.dataUse.oclIsKindOf(StaticDataUse))
	  and self.content.argument->closure(a | a.dataUse.argument)->forAll(a|a.dataUse.oclIsKindOf(StaticDataUse))
    message:   self.prefix() + 
               "Only 'StaticDataUse' may be used directly or indirectly in 'ParameterBinding's of the 'StaticDataUse' within a 'DataReference'."
  }
  
  constraint DataReferenceReduction {
    check: self.content.reduction->isEmpty()
    message:   self.prefix() + 
               "No 'reduction' within 'DataReference', The 'reduction' property of 'StaticDataUse' inherited from 'DataUse' shall not be used within a 'DataReference'."
  }
  //TODO: this is not processed correctly -> update spec or extractor?
  //    -> manually fixed above for now
  //[and self.content.argument->forAll(a | a.dataUse.oclIsKindOf(StaticDataUse))]
  //[and self.content.argument->closure(a |]
  //[a.dataUse.argument)->forAll(a|a.dataUse.oclIsKindOf(StaticDataUse))]
  //[No 'reduction' within 'DataReference', The 'reduction' property of 'StaticDataUse' inherited from 'DataUse' shall not be used within a 'DataReference'., inv: DataReferenceReduction:]
  //[self.content.reduction->isEmpty()]
}

context EventSpecificationTemplate {
  //[There are no constraints specified.]
}

context EventTemplateOccurrence {
  //'EntityReference' of referenced 'EventSpecificationTemplate'
  constraint EntityTemplateOccurrenceConsistency {
    check:     self.entityBinding->forAll(b | 
              (not b.templateEntity.entity.oclIsUndefined() 
           and (b.templateEntity.entity = 
                    self.eventTemplate.eventSpecification.entityReference.entity))
           or (not b.templateEntity.component.oclIsUndefined() 
           and (b.templateEntity.component = 
                    self.eventTemplate.eventSpecification.entityReference.component)
           or self.eventTemplate.eventSpecification.oppositeEntityReference->exists(e | 
                  (not b.templateEntity.entity.oclIsUndefined() 
               and (e.entity = b.templateEntity.entity))
               or (not b.templateEntity.component.oclIsUndefined() 
               and (e.component = b.templateEntity.component)))))
    message:   self.prefix() + 
               "If 'EntityBinding's are provided, the 'Entity's or 'ComponentInstance's referenced in the 'templateEntity' properties shall also be referenced by one of the 'EntityReferences' in the 'EventOccurrenceSpecification' of the 'EventSpecificationTemplate' referenced in the 'EventTemplateOccurrence'."
  }

}

context EntityBinding {
  //[There are no constraints specified.]
}

//TODO: Mismatch TestObjectiveVariant in Ecore vs StructuredTestObjectiveVariant in Part 4
context TestObjectiveVariant {
  //[There are no constraints specified.]
}

context Variants {
  //[There are no constraints specified.]
}

context VariantBinding {
  //Referenced 'Value' of 'VariantBinding'
  constraint VariantBindingValues {
    check:     self.value.oclIsTypeOf(LiteralValueReference) implies
          self.value.oclAsType(LiteralValueReference).content.getTestObjective() = self.getTestObjective()
          and 
//          or //TODO: this may need to be fixed in the spec 
          self.value.oclIsKindOf(ContentReference) implies
          self.value.oclAsType(ContentReference).content.getTestObjective() = self.getTestObjective()
    message:   self.prefix() + 
               "If the 'value' property references a 'LiteralValue' or 'Content' element, the referenced element shall be contained in the 'StructuredTestObjective' containing the 'VariantBinding'."
  }

}

//TODO: why is everything appearing twice? from graphical syntax?
context Entity {
  //[There are no constraints specified.]
}

context Event {
  //[There are no constraints specified.]
}

context PICS {
  //[There are no constraints specified.]
}

context Comment {
  //[Default comment label, The Qualifier label only applies to 'Comment's that do not match the conditions for any of the other qualifier labels.]
}

context StructuredTestObjective {
  //[Spaces in the 'name' of an 'Element' and the 'body' of a 'Comment' , A 'name' of an 'Element' or a 'body' of a 'Comment' shall be enclosed in single or double quotes when the corresponding 'Element' or 'Comment' is contained within a 'PICSReference' or an 'EventSequence'.]
}

context EventSequence {
  //[There are no constraints specified.]
}

context RepeatedEventSequence {
  //[There are no constraints specified.]
}

context EventOccurrence {
  //[There are no constraints specified.]
}

context EventOccurrenceSpecification {
  //[There are no constraints specified.]
}

context EntityReference {
  //[There are no constraints specified.]
}

context EventReference {
  //[There are no constraints specified.]
}

context Value {
  //[There are no constraints specified.]
}

context LiteralValue {
  //[There are no constraints specified.]
}

context Content {
  //[There are no constraints specified.]
}

context LiteralValueReference {
  //[There are no constraints specified.]
}

context ContentReference {
  //[There are no constraints specified.]
}

context DataReference {
  //[There are no constraints specified.]
}

context StaticDataUse {
  //[There are no constraints specified.]
}

context AnyValue {
  //[There are no constraints specified.]
}

context AnyValueOrOmit {
  //[There are no constraints specified.]
}

context OmitValue {
  //[There are no constraints specified.]
}

context DataInstanceUse {
  //[There are no constraints specified.]
}

context ParameterBinding {
  //[There are no constraints specified.]
}

context TimeLabel {
  //[There are no constraints specified.]
}

context TimeConstraint {
  //[There are no constraints specified.]
}

context EventSpecificationTemplate {
  //[There are no constraints specified.]
}

context EventTemplateOccurrence {
  //[There are no constraints specified.]
}

context EntityBinding {
  //[There are no constraints specified.]
}

//TODO: Mismatch TestObjectiveVariant in Ecore vs StructuredTestObjectiveVariant in Part 4
context TestObjectiveVariant {
  //[There are no constraints specified.]
}

context Variants {
  //[There are no constraints specified.]
}

context VariantBinding {
  //[There are no constraints specified.]
}
