package org.weasis.dicom.qr.manisfest;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Tag;
import org.dcm4che3.net.service.QueryRetrieveLevel;
import org.weasis.core.api.media.data.MediaSeriesGroup;
import org.weasis.core.api.util.StringUtil;
import org.weasis.dicom.codec.TagD;
import org.weasis.dicom.codec.wado.WadoParameters;
import org.weasis.dicom.codec.wado.WadoParameters.HttpTag;
import org.weasis.dicom.explorer.DicomModel;
import org.weasis.dicom.op.CFind;
import org.weasis.dicom.param.AdvancedParams;
import org.weasis.dicom.param.DicomNode;
import org.weasis.dicom.param.DicomParam;
import org.weasis.dicom.param.DicomState;
import org.weasis.dicom.qr.manisfest.xml.TagUtil;
public class ManifestBuilder {
// Manifest 2.5
public static final String TAG_DOCUMENT_ROOT = "manifest"; //$NON-NLS-1$
public static final String SCHEMA =
"xmlns=\"http://www.weasis.org/xsd/2.5\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""; //$NON-NLS-1$
public static final String TAG_ARC_QUERY = "arcQuery"; //$NON-NLS-1$
public static final String ARCHIVE_ID = "arcId"; //$NON-NLS-1$
public static final String BASE_URL = "baseUrl"; //$NON-NLS-1$
// Manifest 1
public static final String TAG_HTTP_TAG = "httpTag"; //$NON-NLS-1$
public static final String ADDITIONNAL_PARAMETERS = "additionnalParameters"; //$NON-NLS-1$
public static final String OVERRIDE_TAGS = "overrideDicomTagsList"; //$NON-NLS-1$
public static final String WEB_LOGIN = "webLogin"; //$NON-NLS-1$
public static final String TAG_DOCUMENT_MSG = "Message"; //$NON-NLS-1$
public static final String MSG_ATTRIBUTE_TITLE = "title"; //$NON-NLS-1$
public static final String MSG_ATTRIBUTE_DESC = "description"; //$NON-NLS-1$
public static final String MSG_ATTRIBUTE_LEVEL = "severity"; //$NON-NLS-1$
private final StringBuilder manifest;
private final List<Patient> patients;
public ManifestBuilder() {
this.manifest = new StringBuilder();
this.patients = new ArrayList<>();
}
public String getCharsetEncoding() {
return "UTF-8"; //$NON-NLS-1$
}
public String xmlManifest(WadoParameters wadoParameters, ViewerMessage message) {
if (wadoParameters == null || (patients.isEmpty() && message == null)) {
return null;
}
manifest.append("<?xml version=\"1.0\" encoding=\"" + getCharsetEncoding() + "\" ?>"); //$NON-NLS-1$ //$NON-NLS-2$
manifest.append("\n<"); //$NON-NLS-1$
manifest.append(TAG_DOCUMENT_ROOT);
manifest.append(" "); //$NON-NLS-1$
manifest.append(SCHEMA);
manifest.append(">"); //$NON-NLS-1$
manifest.append("\n<"); //$NON-NLS-1$
manifest.append(TAG_ARC_QUERY);
manifest.append(" "); //$NON-NLS-1$
TagUtil.addXmlAttribute(ARCHIVE_ID, "localWadoRetrieve", manifest); //$NON-NLS-1$
TagUtil.addXmlAttribute(BASE_URL, wadoParameters.getWadoURL(), manifest);
TagUtil.addXmlAttribute(WEB_LOGIN, wadoParameters.getWebLogin(), manifest);
TagUtil.addXmlAttribute(WadoParameters.TAG_WADO_ONLY_SOP_UID, wadoParameters.isRequireOnlySOPInstanceUID(),
manifest);
TagUtil.addXmlAttribute(ADDITIONNAL_PARAMETERS, wadoParameters.getAdditionnalParameters(), manifest);
TagUtil.addXmlAttribute(OVERRIDE_TAGS, wadoParameters.getOverrideDicomTagsList(), manifest);
manifest.append(">"); //$NON-NLS-1$
buildHttpTags(wadoParameters.getHttpTaglist());
buildViewerMessage(message);
buildPatient();
manifest.append("\n</"); //$NON-NLS-1$
manifest.append(TAG_ARC_QUERY);
manifest.append(">"); //$NON-NLS-1$
manifest.append("\n</"); //$NON-NLS-1$
manifest.append(TAG_DOCUMENT_ROOT);
manifest.append(">\n"); // Requires end of line //$NON-NLS-1$
return manifest.toString();
}
private void buildPatient() {
Collections.sort(patients, (o1, o2) -> o1.getPatientName().compareTo(o2.getPatientName()));
for (Patient patient : patients) {
manifest.append(patient.toXml());
}
}
private void buildHttpTags(List<HttpTag> list) {
if (list != null) {
for (WadoParameters.HttpTag tag : list) {
manifest.append("\n<"); //$NON-NLS-1$
manifest.append(TAG_HTTP_TAG);
manifest.append(" key=\""); //$NON-NLS-1$
manifest.append(tag.getKey());
manifest.append("\" value=\""); //$NON-NLS-1$
manifest.append(tag.getValue());
manifest.append("\" />"); //$NON-NLS-1$
}
}
}
private void buildViewerMessage(ViewerMessage message) {
if (message != null) {
manifest.append("\n<"); //$NON-NLS-1$
manifest.append(TAG_DOCUMENT_MSG);
manifest.append(" "); //$NON-NLS-1$
TagUtil.addXmlAttribute(MSG_ATTRIBUTE_TITLE, message.title, manifest);
TagUtil.addXmlAttribute(MSG_ATTRIBUTE_DESC, message.message, manifest);
TagUtil.addXmlAttribute(MSG_ATTRIBUTE_LEVEL, message.level.name(), manifest);
manifest.append("/>"); //$NON-NLS-1$
}
}
public static class ViewerMessage {
public enum eLevel {
INFO, WARN, ERROR;
}
private final String message;
private final String title;
private final eLevel level;
public ViewerMessage(String title, String message, eLevel level) {
this.title = title;
this.message = message;
this.level = level;
}
public String getMessage() {
return message;
}
public String getTitle() {
return title;
}
public eLevel getLevel() {
return level;
}
}
public void fillSeries(AdvancedParams advancedParams, DicomNode callingNode, DicomNode calledNode, DicomModel model,
List<String> studies) {
for (String studyUID : studies) {
DicomParam[] keysSeries = {
// Matching Keys
new DicomParam(Tag.StudyInstanceUID, studyUID),
// Return Keys
CFind.SeriesInstanceUID, CFind.Modality, CFind.SeriesNumber, CFind.SeriesDescription };
DicomState state =
CFind.process(advancedParams, callingNode, calledNode, 0, QueryRetrieveLevel.SERIES, keysSeries);
List<Attributes> seriesRSP = state.getDicomRSP();
if (seriesRSP != null && !seriesRSP.isEmpty()) {
MediaSeriesGroup studyGroup = model.getStudyNode(studyUID);
MediaSeriesGroup patientGroup = model.getParent(studyGroup, DicomModel.patient);
Patient patient = getPatient(patientGroup);
Study study = getStudy(patient, studyGroup);
for (Attributes seriesDataset : seriesRSP) {
fillInstance(advancedParams, callingNode, calledNode, seriesDataset, study);
}
}
}
}
private Patient getPatient(MediaSeriesGroup patientGroup) {
String id = TagD.getTagValue(patientGroup, Tag.PatientID, String.class);
String ispid = TagD.getTagValue(patientGroup, Tag.IssuerOfPatientID, String.class);
for (Patient p : patients) {
if (p.hasSameUniqueID(id, ispid)) {
return p;
}
}
Patient p = new Patient(id, ispid);
p.setPatientName(TagD.getTagValue(patientGroup, Tag.PatientName, String.class));
// Only set birth date, birth time is often not consistent (00:00)
p.setPatientBirthDate(
TagD.formatDicomDate(TagD.getTagValue(patientGroup, Tag.PatientBirthDate, LocalDate.class)));
p.setPatientSex(TagD.getTagValue(patientGroup, Tag.PatientSex, String.class));
patients.add(p);
return p;
}
private Study getStudy(Patient patient, MediaSeriesGroup studyGroup) {
String uid = TagD.getTagValue(studyGroup, Tag.StudyInstanceUID, String.class);
Study s = patient.getStudy(uid);
if (s == null) {
s = new Study(uid);
s.setStudyDescription(TagD.getTagValue(studyGroup, Tag.StudyDescription, String.class));
s.setStudyDate(TagD.formatDicomDate(TagD.getTagValue(studyGroup, Tag.StudyDate, LocalDate.class)));
s.setStudyTime(TagD.formatDicomTime(TagD.getTagValue(studyGroup, Tag.StudyTime, LocalTime.class)));
s.setAccessionNumber(TagD.getTagValue(studyGroup, Tag.AccessionNumber, String.class));
s.setStudyID(TagD.getTagValue(studyGroup, Tag.StudyID, String.class));
s.setReferringPhysicianName(TagD.getTagValue(studyGroup, Tag.ReferringPhysicianName, String.class));
patient.addStudy(s);
}
return s;
}
private static Series getSeries(Study study, final Attributes seriesDataset) {
String uid = seriesDataset.getString(Tag.SeriesInstanceUID);
Series s = study.getSeries(uid);
if (s == null) {
s = new Series(uid);
s.setModality(seriesDataset.getString(Tag.Modality));
s.setSeriesNumber(seriesDataset.getString(Tag.SeriesNumber));
s.setSeriesDescription(seriesDataset.getString(Tag.SeriesDescription));
study.addSeries(s);
}
return s;
}
private void fillInstance(AdvancedParams advancedParams, DicomNode callingNode, DicomNode calledNode,
Attributes seriesDataset, Study study) {
String serieInstanceUID = seriesDataset.getString(Tag.SeriesInstanceUID);
if (StringUtil.hasText(serieInstanceUID)) {
DicomParam[] keysInstance = {
// Matching Keys
new DicomParam(Tag.StudyInstanceUID, study.getStudyInstanceUID()),
new DicomParam(Tag.SeriesInstanceUID, serieInstanceUID),
// Return Keys
CFind.SOPInstanceUID, CFind.InstanceNumber };
DicomState state =
CFind.process(advancedParams, callingNode, calledNode, 0, QueryRetrieveLevel.IMAGE, keysInstance);
List<Attributes> instances = state.getDicomRSP();
if (instances != null && !instances.isEmpty()) {
Series s = getSeries(study, seriesDataset);
for (Attributes instanceDataSet : instances) {
String sopUID = instanceDataSet.getString(Tag.SOPInstanceUID);
if (sopUID != null) {
SOPInstance sop = new SOPInstance(sopUID);
sop.setInstanceNumber(instanceDataSet.getString(Tag.InstanceNumber));
s.addSOPInstance(sop);
}
}
}
}
}
}