/*******************************************************************************
* Copyright (c) 2016 Weasis Team and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas Roduit - initial API and implementation
*******************************************************************************/
package org.weasis.dicom.sr;
import java.awt.Color;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAccessor;
import java.util.Map;
import org.dcm4che3.data.Attributes;
import org.dcm4che3.data.Code;
import org.dcm4che3.data.Sequence;
import org.dcm4che3.data.Tag;
import org.weasis.core.api.media.data.MediaElement;
import org.weasis.core.api.media.data.Series;
import org.weasis.core.api.media.data.TagUtil;
import org.weasis.core.api.media.data.TagW;
import org.weasis.core.api.util.EscapeChars;
import org.weasis.core.api.util.StringUtil;
import org.weasis.core.ui.model.graphic.Graphic;
import org.weasis.core.ui.model.utils.exceptions.InvalidShapeException;
import org.weasis.dicom.codec.DicomSpecialElement;
import org.weasis.dicom.codec.TagD;
import org.weasis.dicom.codec.macro.SOPInstanceReference;
import org.weasis.dicom.codec.macro.SeriesAndInstanceReference;
import org.weasis.dicom.explorer.pr.PrGraphicUtil;
public class SRReader {
private final DicomSpecialElement dicomSR;
private final Attributes dcmItems;
public SRReader(Series series, DicomSpecialElement dicomSR) {
if (dicomSR == null) {
throw new IllegalArgumentException("Dicom parameter cannot be null"); //$NON-NLS-1$
}
this.dicomSR = dicomSR;
this.dcmItems = dicomSR.getMediaReader().getDicomObject();
}
public MediaElement getDicom() {
return dicomSR;
}
public Attributes getDcmobj() {
return dcmItems;
}
public SeriesAndInstanceReference getSeriesAndInstanceReference() {
if (dcmItems != null) {
return new SeriesAndInstanceReference(dcmItems);
}
return null;
}
public void readDocumentGeneralModule(StringBuilder html, Map<String, SRImageReference> map) {
if (dcmItems != null) {
SRDocumentContentModule content = new SRDocumentContentModule(dcmItems);
addCodeMeaning(html, content.getConceptNameCode(), "<h1>", "</h1>"); //$NON-NLS-1$ //$NON-NLS-2$
String instName = dcmItems.getString(Tag.InstitutionName);
String instDepName = dcmItems.getString(Tag.InstitutionalDepartmentName);
String stationName = dcmItems.getString(Tag.StationName);
LocalDateTime contentDateTime = TagD.dateTime(Tag.ContentDateAndTime, dcmItems);
if (instName != null) {
html.append(Messages.getString("SRReader.by")); //$NON-NLS-1$
html.append(" "); //$NON-NLS-1$
html.append(instName);
if (instDepName != null) {
html.append(" ("); //$NON-NLS-1$
html.append(instDepName);
html.append(")"); //$NON-NLS-1$
}
}
if (stationName != null) {
if (instName != null) {
html.append(" "); //$NON-NLS-1$
html.append(Messages.getString("SRReader.on")); //$NON-NLS-1$
html.append(" "); //$NON-NLS-1$
}
html.append(stationName);
}
if (contentDateTime != null) {
if (instName != null || stationName != null) {
html.append(", "); //$NON-NLS-1$
}
html.append(TagUtil.formatDateTime(contentDateTime));
}
if (instName != null || stationName != null || contentDateTime != null) {
html.append("<BR>"); //$NON-NLS-1$
}
html.append("<table border=\"0\" width=\"100%\" cellspacing=\"5\">"); //$NON-NLS-1$
html.append("<tr align=\"left\" valign=\"top\"><td width=\"33%\" >"); //$NON-NLS-1$
html.append("<font size=\"+1\">Patient</font>"); //$NON-NLS-1$
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.PatientName, html);
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.PatientID, html);
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.PatientBirthDate, html);
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.PatientSex, html);
html.append("</td><td width=\"33%\" >"); //$NON-NLS-1$
html.append("<font size=\"+1\">"); //$NON-NLS-1$
html.append(Messages.getString("SRReader.study")); //$NON-NLS-1$
html.append("</font>"); //$NON-NLS-1$
html.append("<BR>"); //$NON-NLS-1$
writeStudyDateTime(html);
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.StudyID, html);
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.AccessionNumber, html);
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.ReferringPhysicianName, html);
html.append("</td><td width=\"33%\" >"); //$NON-NLS-1$
html.append("<font size=\"+1\">"); //$NON-NLS-1$
html.append(Messages.getString("SRReader.report_status")); //$NON-NLS-1$
html.append("</font><BR>"); //$NON-NLS-1$
writeItem(Tag.CompletionFlag, html); // $NON-NLS-1$
html.append("<BR>"); //$NON-NLS-1$
writeItem(Tag.VerificationFlag, html); // $NON-NLS-1$
html.append("<BR>"); //$NON-NLS-1$
writeVerifyingObservers(html);
html.append("</td></tr>"); //$NON-NLS-1$
html.append("</table>"); //$NON-NLS-1$
html.append("<hr size=2>"); //$NON-NLS-1$
Sequence cts = content.getContent();
if (cts != null) {
for (int i = 0; i < cts.size(); i++) {
SRDocumentContent c = new SRDocumentContent(cts.get(i));
html.append("<BR>"); //$NON-NLS-1$
html.append("<B>"); //$NON-NLS-1$
String level = "1." + (i + 1); //$NON-NLS-1$
html.append(level);
html.append(" </B>"); //$NON-NLS-1$
Code code = c.getConceptNameCode();
addCodeMeaning(html, code, "<B>", "</B>"); //$NON-NLS-1$ //$NON-NLS-2$
convertContentToHTML(html, c, false, code == null, map, level);
html.append("<BR>"); //$NON-NLS-1$
addContent(html, c, map, level);
}
}
}
}
private static void convertContentToHTML(StringBuilder html, SRDocumentContent c, boolean continuous,
boolean noCodeName, Map<String, SRImageReference> map, String level) {
if (c != null) {
html.append("<A name=\""); //$NON-NLS-1$
html.append(level);
html.append("\"<></A>"); //$NON-NLS-1$
String type = c.getValueType();
if ("TEXT".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
convertTextToHTML(html, c.getTextValue());
} else if ("CODE".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
addCodeMeaning(html, c.getConceptCode(), null, null);
} else if ("PNAME".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
convertTextToHTML(html, TagD.getDicomPersonName(c.getPersonName()));
} else if ("NUM".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : " = "); //$NON-NLS-1$ //$NON-NLS-2$
Attributes val = c.getMeasuredValue();
if (val != null) {
html.append(val.getFloat(Tag.NumericValue, 0.0f));
Attributes item = val.getNestedDataset(Tag.MeasurementUnitsCodeSequence);
if (item != null) {
Code unit = new Code(item);
html.append(" "); //$NON-NLS-1$
html.append(EscapeChars.forHTML(unit.getCodeValue()));
}
}
} else if ("CONTAINER".equals(type)) { //$NON-NLS-1$
return;
} else if ("IMAGE".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
Attributes item = c.getAttributes().getNestedDataset(Tag.ReferencedSOPSequence);
if (item != null) {
SRImageReference imgRef = map.get(level);
if (imgRef == null) {
imgRef = new SRImageReference(level);
map.put(level, imgRef);
}
if (imgRef.getSopInstanceReference() == null) {
imgRef.setSopInstanceReference(new SOPInstanceReference(item));
}
html.append("<a href=\"http://"); //$NON-NLS-1$
html.append(level);
html.append("\" style=\"color:#FF9900\">"); //$NON-NLS-1$
html.append(Messages.getString("SRReader.show_img")); //$NON-NLS-1$
html.append("</a>"); //$NON-NLS-1$
}
} else if ("DATETIME".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
html.append(c.getDateTime());
} else if ("DATE".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
html.append(c.getDate());
} else if ("TIME".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
html.append(c.getTime());
} else if ("UIDREF".equals(type)) { //$NON-NLS-1$
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
convertTextToHTML(html, c.getUID());
} else if ("COMPOSITE".equals(type)) { //$NON-NLS-1$
Sequence sequenceElt = c.getAttributes().getSequence(Tag.ReferencedSOPSequence);
if (sequenceElt != null && !sequenceElt.isEmpty()) {
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
for (int i = 0; i < sequenceElt.size(); i++) {
SOPInstanceReference sopRef = new SOPInstanceReference(sequenceElt.get(i));
// TODO convert UID to text
html.append(sopRef.getReferencedSOPClassUID());
html.append(" (SOP Instance UID"); //$NON-NLS-1$
html.append(StringUtil.COLON_AND_SPACE);
html.append(sopRef.getReferencedSOPInstanceUID());
html.append(")"); //$NON-NLS-1$
}
}
} else if ("SCOORD".equals(type)) { //$NON-NLS-1$
Attributes graphicsItems = c.getAttributes();
Sequence sc = c.getContent();
if (sc != null) {
for (Attributes attributes : sc) {
SRDocumentContent c2 = new SRDocumentContent(attributes);
String id = getReferencedContentItemIdentifier(c2.getReferencedContentItemIdentifier());
if (id != null) {
SRImageReference imgRef = map.get(id);
if (imgRef == null) {
imgRef = new SRImageReference(id);
map.put(id, imgRef);
}
try {
Graphic graphic = PrGraphicUtil.buildGraphic(graphicsItems, Color.MAGENTA, false, 1, 1,
false, null, true);
if (graphic != null) {
imgRef.addGraphic(graphic);
}
} catch (InvalidShapeException e) {
e.printStackTrace();
}
html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
html.append("<a href=\"http://"); //$NON-NLS-1$
html.append(id);
html.append("\" style=\"color:#FF9900\">"); //$NON-NLS-1$
html.append(graphicsItems.getString(Tag.GraphicType));
html.append("</a>"); //$NON-NLS-1$
}
}
}
// } else if ("TCOORD".equals(type)) {
// html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE);
// // TODO
// } else if ("WAVEFORM".equals(type)) {
// html.append(continuous || noCodeName ? " " : StringUtil.COLON_AND_SPACE);
// // TODO
} else if (type != null) {
html.append("<i>"); //$NON-NLS-1$
html.append(type);
html.append(" "); //$NON-NLS-1$
html.append(Messages.getString("SRReader.tag_missing")); //$NON-NLS-1$
html.append("</i>"); //$NON-NLS-1$
}
int[] refs = c.getReferencedContentItemIdentifier();
if (refs != null) {
html.append(Messages.getString("SRReader.content_ref") + StringUtil.COLON_AND_SPACE); //$NON-NLS-1$
String id = getReferencedContentItemIdentifier(refs);
html.append("<a href=\"#"); //$NON-NLS-1$
html.append(id);
html.append("\">"); //$NON-NLS-1$
html.append(Messages.getString("SRReader.node")); //$NON-NLS-1$
html.append(" "); //$NON-NLS-1$
html.append(id);
html.append("</a>"); //$NON-NLS-1$
}
}
}
private static String getReferencedContentItemIdentifier(int[] refs) {
if (refs != null) {
StringBuilder r = new StringBuilder();
for (int j = 0; j < refs.length - 1; j++) {
r.append(refs[j]);
r.append('.');
}
if (refs.length - 1 >= 0) {
r.append(refs[refs.length - 1]);
}
return r.toString();
}
return null;
}
private static void addContent(StringBuilder html, SRDocumentContent c, Map<String, SRImageReference> map,
String level) {
Sequence cts = c.getContent();
if (cts != null) {
boolean continuity = "CONTINUOUS".equals(c.getContinuityOfContent()); //$NON-NLS-1$
if (!continuity) {
html.append("<OL>"); //$NON-NLS-1$
}
for (int i = 0; i < cts.size(); i++) {
SRDocumentContent srContent = new SRDocumentContent(cts.get(i));
html.append(continuity ? " " : "<LI>"); //$NON-NLS-1$ //$NON-NLS-2$
Code code = null;
if (!continuity) {
code = srContent.getConceptNameCode();
addCodeMeaning(html, code, "<B>", "</B>"); //$NON-NLS-1$ //$NON-NLS-2$
}
String level2 = level + "." + (i + 1); //$NON-NLS-1$
convertContentToHTML(html, srContent, continuity, code == null, map, level2);
addContent(html, srContent, map, level2);
html.append(continuity ? " " : "</LI>"); //$NON-NLS-1$ //$NON-NLS-2$
}
if (!continuity) {
html.append("</OL>"); //$NON-NLS-1$
}
}
}
private static void addCodeMeaning(StringBuilder html, Code code, String startTag, String endTag) {
if (code != null) {
if (startTag != null) {
html.append(startTag);
}
html.append(EscapeChars.forHTML(code.getCodeMeaning()));
if (endTag != null) {
html.append(endTag);
}
}
}
private static void convertTextToHTML(StringBuilder html, String text) {
if (text != null) {
String[] lines = EscapeChars.convertToLines(text);
if (lines.length > 0) {
html.append(EscapeChars.forHTML(lines[0]));
for (int i = 1; i < lines.length; i++) {
html.append("<BR>"); //$NON-NLS-1$
html.append(EscapeChars.forHTML(lines[i]));
}
}
}
}
private void writeItem(int tagID, StringBuilder html) {
TagW tag = TagD.getNullable(tagID, null);
if (tag != null && html != null && dcmItems != null) {
html.append("<B>"); //$NON-NLS-1$
html.append(tag.getDisplayedName());
html.append("</B>"); //$NON-NLS-1$
html.append(StringUtil.COLON_AND_SPACE);
html.append(tag.getFormattedTagValue(tag.getValue(dcmItems), null));
}
}
private void writeStudyDateTime(StringBuilder html) {
TagW tagDate = TagD.getNullable(Tag.StudyDate, null);
if (tagDate != null && html != null && dcmItems != null) {
LocalDateTime date = TagD.dateTime(Tag.StudyDateAndTime, dcmItems);
if (date != null) {
html.append("<B>"); //$NON-NLS-1$
html.append(tagDate.getDisplayedName());
html.append("</B>"); //$NON-NLS-1$
html.append(StringUtil.COLON_AND_SPACE);
html.append(TagUtil.formatDateTime(date));
}
}
}
private void writeVerifyingObservers(StringBuilder html) {
if (html != null && dcmItems != null) {
Sequence seq = dcmItems.getSequence(Tag.VerifyingObserverSequence);
if (seq != null && !seq.isEmpty()) {
html.append("<B>"); //$NON-NLS-1$
html.append(Messages.getString("SRReader.ver_observer")); //$NON-NLS-1$
html.append("</B>"); //$NON-NLS-1$
html.append(StringUtil.COLON);
html.append("<BR>"); //$NON-NLS-1$
for (Attributes v : seq) {
TemporalAccessor date = (TemporalAccessor) TagD.get(Tag.VerificationDateTime).getValue(v);
if (date != null) {
html.append(" * "); //$NON-NLS-1$
html.append(TagUtil.formatDateTime(date));
html.append(" - "); //$NON-NLS-1$
String name = TagD.getDicomPersonName(v.getString(Tag.VerifyingObserverName));
if (name != null) {
html.append(name);
html.append(", "); //$NON-NLS-1$
}
String org = v.getString(Tag.VerifyingOrganization);
if (org != null) {
html.append(org);
}
html.append("<BR>"); //$NON-NLS-1$
}
}
}
}
}
}