@Chapter
    @PartNumber { Part A }
    @PartTitle { The NRC Nurse Rostering Model }
    @Title { NRC Archives and Solution Groups }
    @Tag { archives }
@Begin
@LP
The subject of this part is the NRC nurse rostering model.  As
explained in the introduction, the NRC model is an intermediate
model, lying between the source models, which are existing nurse
rostering models such as the First International Timetabling
Competition model, and the target model, XESTT.  By calling
the functions defined in this part, a converter can convert
instances and solutions in its model into the intermediate
model; and then one call on @C { NrcArchiveWrite } converts
that into XESTT and writes it as an XESTT archive.
@PP
This chapter describes types @C { NRC_ARCHIVE } and @C { NRC_SOLN_GROUP },
representing archives (sets of instances and solution groups)
and solution groups (sets of solutions) in the intermediate model.
Nurse rostering data formats do not seem to have features for grouping
instances and solutions, beyond, say, the use of a zip file containing
several instances.  So these features of NRC are copied directly from
the corresponding XESTT features.
@BeginSections

@Section
   @Title { Archives }
   @Tag { archives.archives }
@Begin
@LP
An archive is a collection of instances together with groups of
solutions to those instances.  There may be any number of instances
and solution groups.  To create a new, empty archive, call
@ID @C {
NRC_ARCHIVE NrcArchiveMake(char *id, HA_ARENA_SET as);
}
Here @C { id } is an identifier for the archive, and @C { as }
is an arena set, used to gain efficient access to heap memory.
You can safely pass @C { NULL } for arena set; to find out how
to pass a non-@C { NULL } value, and why you might want to do
that, read the KHE User's Guide.  Function
@ID @C {
char *NrcArchiveId(NRC_ARCHIVE archive);
}
returns the Id attribute.
@PP
Archive metadata may be set and retrieved by calling
@ID @C {
void NrcArchiveSetMetaData(NRC_ARCHIVE archive, char *name,
  char *contributor, char *date, char *description, char *remarks);
void NrcArchiveMetaData(NRC_ARCHIVE archive, char **name,
  char **contributor, char **date, char **description, char **remarks);
}
where @C { remarks }, being optional, may be @C { NULL }.
@PP
Initially an archive contains no instances and no solution groups.
Solution groups are added automatically as they are created, because
every solution group lies in exactly one archive.  An instance may
be added to an archive by calling
@ID @C {
bool NrcArchiveAddInstance(NRC_ARCHIVE archive, NRC_INSTANCE ins);
}
@C { NrcArchiveAddInstance } returns @C { true } if it succeeds in
adding @C { ins } to @C { archive }, and @C { false } otherwise,
which can only be because @C { archive } already contains an instance
with the same Id as @C { ins }.  The instance will appear after any
instances already present.  An instance may be deleted from an archive
(but not destroyed) by calling
@ID @C {
void NrcArchiveDeleteInstance(NRC_ARCHIVE archive, NRC_INSTANCE ins);
}
@C { NrcArchiveDeleteInstance } aborts if @C { ins } is not in
@C { archive }.  If there are any solutions for @C { ins } in
@C { archive }, they are deleted too.  The gap left by deleting the
instance is filled by shuffling subsequent instances up one place.
@PP
To visit the instances of an archive, call
@ID @C {
int NrcArchiveInstanceCount(NRC_ARCHIVE archive);
NRC_INSTANCE NrcArchiveInstance(NRC_ARCHIVE archive, int i);
}
The first returns the number of instances in @C { archive },
and the second returns the @C { i }'th of those instances,
counting from 0 as usual in C.  There is also
@ID @C {
bool NrcArchiveRetrieveInstance(NRC_ARCHIVE archive, char *id,
  NRC_INSTANCE *ins);
}
If @C { archive } contains an instance with the given @C { id },
this function sets @C { ins } to that instance and returns
@C { true }; otherwise it leaves @C { *ins } untouched and
returns @C { false }.  In the same way,
@ID @C {
int NrcArchiveSolnGroupCount(NRC_ARCHIVE archive);
NRC_SOLN_GROUP NrcArchiveSolnGroup(NRC_ARCHIVE archive, int i);
bool NrcArchiveRetrieveSolnGroup(NRC_ARCHIVE archive, char *id,
  NRC_SOLN_GROUP *soln_group);
}
visit the solution groups of an archive, and retrieve a solution
group by @C { id }.
@End @Section

@Section
    @Title { Solution groups }
    @Tag { archives.soln_groups }
@Begin
@LP
A solution group is a set of solutions to instances of its
archive.  To create a solution group, call
@ID @C {
bool NrcSolnGroupMake(NRC_ARCHIVE archive, char *id,
  NRC_SOLN_GROUP *soln_group);
}
Parameter @C { archive } is compulsory.  The solution group will
be added to the archive.  Parameter @C { id } is an identifier for
the solution group.  If the operation is successful, then @C { true }
is returned with @C { *soln_group } set to the new solution group;
if it is unsuccessful (which can only be because @C { id } is already
the Id of a solution group of @C { archive }), then @C { false }
is returned with @C { *soln_group } set to @C { NULL }.  To
retrieve these attributes, call
@ID @C {
NRC_ARCHIVE NrcSolnGroupArchive(NRC_SOLN_GROUP soln_group);
char *NrcSolnGroupId(NRC_SOLN_GROUP soln_group);
}
Solution group metadata may be set and retrieved by calling
@ID @C {
void NrcSolnGroupSetMetaData(NRC_SOLN_GROUP soln_group,
  char *contributor, char *date, char *description, char *publication,
  char *remarks);
void NrcSolnGroupMetaData(NRC_SOLN_GROUP soln_group,
  char **contributor, char **date, char **description, char **publication,
  char **remarks);
}
where @C { publication } and @C { remarks }, being optional, may
be @C { NULL }.
@PP
Initially a solution group has no solutions.  These are added
and deleted by calling
@ID @C {
void NrcSolnGroupAddSoln(NRC_SOLN_GROUP soln_group, NRC_SOLN soln);
void NrcSolnGroupDeleteSoln(NRC_SOLN_GROUP soln_group, NRC_SOLN soln);
}
A solution can only be added when its instance lies in the solution
group's archive.
@PP
To visit the solutions of a solution group, call
@ID @C {
int NrcSolnGroupSolnCount(NRC_SOLN_GROUP soln_group);
NRC_SOLN NrcSolnGroupSoln(NRC_SOLN_GROUP soln_group, int i);
}
Solutions have no Ids, so there is no @C { NrcSolnGroupRetrieveSoln }
function.  When solution @C { i } is deleted,
@C { NrcSolnGroupSolnCount } decreases by 1, solution @C { i+1 }
becomes solution @C { i }, and so on.
@End @Section

@Section
   @Title { Writing archives }
   @Tag { archives.write }
@Begin
@LP
To convert an archive to XESTT format and write it to a file, call
@ID @C {
void NrcArchiveWrite(NRC_ARCHIVE archive, bool with_reports, FILE *fp);
}
File @C { fp } must be open for writing UTF-8 characters, and it remains
open after the call returns.  If @C { with_reports } is @C { true },
each written solution contains a @C { Report } section evaluating the
solution.  The initial tag will be @C { <EmployeeScheduleArchive> }.
@PP
@C { NrcArchiveWrite } converts the NRC archive into a KHE archive
and writes that archive using @C { KheArchiveWrite }.
@PP
At present, NRC does not check that the names of its entities are
distinct.  If two entities with conflicting names are given to NRC,
they will be accepted at the time, but @C { NrcArchiveWrite } will
exit with an error message when the KHE conversion reports the problem.
# @C { KheArchiveWrite } writes an incomplete file and aborts with
# an error message when it encounters an event or event resource
# in a solution which is assigned a time or resource which
# contradicts a preassigned time or resource in the corresponding 
# event of the instance.  Missing ids, names, and meta-data also
# cause an abort with error message.
# @PP
# When writing solutions, @C { KheArchiveWrite } writes as little as
# possible.  It does not write an unassigned or preassigned solution
# event resource.  It does not write a solution event if its duration
# equals the duration of the corresponding instance event (alway true
# here), its time is unassigned or preassigned (again, always true here),
# and its solution event resources are not written according to the rule
# just given.
@End @Section

@EndSections
@End @Chapter
