package se.cambio.openehr.controller.terminology.plugins;
import org.apache.log4j.Logger;
import org.openehr.rm.datatypes.text.CodePhrase;
import org.openehr.rm.datatypes.text.DvCodedText;
import se.cambio.cm.model.facade.terminology.vo.TerminologyNodeVO;
import se.cambio.openehr.controller.terminology.TerminologyServiceImpl;
import se.cambio.openehr.util.exceptions.*;
import se.cambio.openehr.util.misc.CSVReader;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
public class CSVTerminologyServicePlugin implements TerminologyServicePlugin {
private String _terminologyId = null;
private Map<String, ArrayList<String>> _parentsMap = null;
private Map<String, ArrayList<String>> _childrenMap = null;
private Map<String, String> _descriptionsMap = null;
public CSVTerminologyServicePlugin(String terminologyId){
_terminologyId = terminologyId;
}
public void init(InputStream is) throws InternalErrorException{
try {
CSVReader csvReader = new CSVReader(new BufferedReader(new InputStreamReader(is, "UTF-8")));
_parentsMap = new HashMap<String, ArrayList<String>>();
_childrenMap = new HashMap<String, ArrayList<String>>();
getDescriptionsMap().clear();
csvReader.readHeaders();
while (csvReader.readRecord()) {
String id = csvReader.get("id");
String description = csvReader.get("text");
String parent = csvReader.get("parent");
log.debug("id: " + id + ", description: " + description);
if (id != null && !id.isEmpty() && description != null
&& !description.isEmpty()) {
getDescriptionsMap().put(id, description);
if (parent != null && !parent.isEmpty()) {
// Add parent
ArrayList<String> parents = new ArrayList<String>();
parents.add(parent);
ArrayList<String> hierarchy = _parentsMap.get(parent);
if (hierarchy != null) {
parents.addAll(hierarchy);
}
_parentsMap.put(id, parents);
// Add child to parent
ArrayList<String> children = _childrenMap.get(parent);
if (children == null) {
children = new ArrayList<String>();
_childrenMap.put(parent, children);
}
children.add(id);
}
}
}
log.debug("Total " + getDescriptionsMap().size() + " term(s) loaded..");
} catch (Exception e) {
Logger.getLogger(TerminologyServiceImpl.class).warn(
"Failed to initialize the terminology service '"
+ _terminologyId + "'", e);
throw new InternalErrorException(e);
}
}
public String getTerminologyId() {
return _terminologyId;
}
public boolean isSubclassOf(CodePhrase a, CodePhrase b)
throws UnsupportedTerminologyException, InvalidCodeException {
checkTerminologySupported(a);
checkTerminologySupported(b);
return checkSubclassOf(a, b);
}
public boolean isSubclassOf(CodePhrase code, Set<CodePhrase> codes)
throws UnsupportedTerminologyException, InvalidCodeException {
checkTerminologySupported(code);
boolean ret = false;
for (CodePhrase cp : codes) {
if( ! code.getTerminologyId().equals(cp.getTerminologyId())) {
// simply ignore instead of stopping the rest codes
continue;
}
try{
if (checkSubclassOf(code, cp)) {
ret = true;
break;
}
}catch(InvalidCodeException e){
Logger.getLogger(CSVTerminologyServicePlugin.class).warn("InvalidCodeException: checkSubclassOf('"+code+"','"+cp.getCodeString()+"') ignored. "+e.getMessage());
}
}
return ret;
}
public TerminologyNodeVO retrieveAllSubclasses(CodePhrase concept, CodePhrase language)
throws UnsupportedTerminologyException,
UnsupportedLanguageException, InvalidCodeException {
String code = concept.getCodeString();
return retrieveAllSubclasses(code, language);
}
private TerminologyNodeVO retrieveAllSubclasses(String code, CodePhrase language)
throws UnsupportedTerminologyException, UnsupportedLanguageException {
// TODO Memory eater!VVVV
TerminologyNodeVO node = getNodeForCode(code, language);
ArrayList<String> children = _childrenMap.get(code);
if (children != null) {
for (String childCode : children) {
TerminologyNodeVO nodeAux = retrieveAllSubclasses(childCode, language);
if (nodeAux != null) {
node.addChild(nodeAux);
}
}
}
return node;
}
public List<TerminologyNodeVO> retrieve(String expression, CodePhrase language)
throws UnsupportedTerminologyException,
UnsupportedLanguageException {
// TODO Auto-generated method stub
return null;
}
public List<TerminologyNodeVO> retrieveAll(String terminologyId, CodePhrase language)
throws UnsupportedTerminologyException,
UnsupportedLanguageException {
if (_terminologyId.equals(terminologyId)){
ArrayList<TerminologyNodeVO> allNodes = new ArrayList<TerminologyNodeVO>();
for (String code : _descriptionsMap.keySet()) {
if (!code.isEmpty() && _parentsMap.get(code)==null){
//if (code.equals("138875005")){
TerminologyNodeVO node = retrieveAllSubclasses(code, language);
allNodes.add(node);
//}
}
}
//System.out.println("allNodes="+allNodes.size());
return allNodes;
}else{
throw new UnsupportedTerminologyException(terminologyId+ " not supported");
}
}
private TerminologyNodeVO getNodeForCode(String code, CodePhrase language)
throws UnsupportedTerminologyException, UnsupportedLanguageException{
String desc = retrieveTerm(code, language);
if (desc == null) {
desc = code;
}
return new TerminologyNodeVO(new DvCodedText(desc, new CodePhrase(_terminologyId, code)));
}
public boolean hasPropertyOfValue(CodePhrase concept, CodePhrase property,
CodePhrase value) throws UnsupportedTerminologyException,
UnknownPropertyException {
// TODO Auto-generated method stub
return false;
}
public List<DvCodedText> retrieveAllPossibleValues(CodePhrase property,
CodePhrase language) throws UnsupportedTerminologyException,
UnknownPropertyException, UnsupportedLanguageException {
// TODO Auto-generated method stub
return null;
}
public boolean isTerminologySupported(String terminologyId) {
return _terminologyId.equalsIgnoreCase(terminologyId);
}
private boolean checkSubclassOf(CodePhrase a, CodePhrase b)
throws UnsupportedTerminologyException, InvalidCodeException {
if (isValidTerminologyCode(a) && isValidTerminologyCode(b)) {
String as = a.getCodeString();
String bs = b.getCodeString();
return checkSubclassOf(as,bs);
} else {
throw new UnsupportedTerminologyException(a.getTerminologyId() + " not supported");
}
}
protected boolean checkSubclassOf(String as, String bs)
throws UnsupportedTerminologyException, InvalidCodeException {
if (invalidCode(as)) {
throw new InvalidCodeException("Invalid " + _terminologyId
+ " code: " + as);
}
if (invalidCode(bs)) {
throw new InvalidCodeException("Invalid " + _terminologyId
+ " code: " + bs);
}
if (as.equals(bs)) {
return true;
} else {
ArrayList<String> parents = _parentsMap.get(as);
return (parents != null && parents.contains(bs));
}
}
private void checkTerminologySupported(CodePhrase code)
throws UnsupportedTerminologyException {
checkTerminologySupported(code.getTerminologyId().getValue());
}
private void checkTerminologySupported(String terminology)
throws UnsupportedTerminologyException {
if (!isTerminologySupported(terminology)) {
throw new UnsupportedTerminologyException(terminology
+ " not supported");
}
}
protected boolean invalidCode(String code) {
return getDescriptionsMap().get(code) == null;
}
public Map<String, String> getDescriptionsMap() {
if (_descriptionsMap == null) {
_descriptionsMap = new HashMap<String, String>();
}
return _descriptionsMap;
}
public void registerDescription(String code, String description) {
getDescriptionsMap().put(code, description);
}
protected String getDescription(String code) {
return getDescriptionsMap().get(code);
}
private boolean isValidTerminologyCode(CodePhrase code) {
return isTerminologySupported(code.getTerminologyId().getValue());
}
public String retrieveTerm(CodePhrase concept, CodePhrase language)
throws UnsupportedTerminologyException,
UnsupportedLanguageException {
return retrieveTerm(concept.getCodeString(), language);
}
protected String retrieveTerm(String code, CodePhrase language)
throws UnsupportedTerminologyException,
UnsupportedLanguageException {
return getDescription(code);
}
private static Logger log = Logger.getLogger(CSVTerminologyServicePlugin.class);
public Collection<String> getSupportedTerminologies() {
Collection<String> supportedTerminologies = new ArrayList<String>();
supportedTerminologies.add(_terminologyId);
return supportedTerminologies;
}
public boolean isValidCodePhrase(CodePhrase codePhrase) {
return isValidTerminologyCode(codePhrase) && !invalidCode(codePhrase.getCodeString());
}
}
/*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 2.0/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 2.0 (the 'License'); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an 'AS IS' basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
*
* The Initial Developers of the Original Code are Iago Corbal and Rong Chen.
* Portions created by the Initial Developer are Copyright (C) 2012-2013
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Software distributed under the License is distributed on an 'AS IS' basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* ***** END LICENSE BLOCK *****
*/