package org.opencds.cqf.cql.engine.elm.execution;

import org.opencds.cqf.cql.engine.debug.SourceLocator;
import org.opencds.cqf.cql.engine.exception.CqlException;
import org.opencds.cqf.cql.engine.execution.Context;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MessageEvaluator extends org.cqframework.cql.elm.execution.Message {

    static final Logger logger = LoggerFactory.getLogger(MessageEvaluator.class);

    public Object message(Context context, SourceLocator sourceLocator, Object source, Boolean condition, String code, String severity, String message) {
        if (severity == null) {
            severity = "message";
        }

        if (condition) {
            StringBuilder messageBuilder = new StringBuilder();
            if (code != null) {
                messageBuilder.append(code).append(": ");
            }
            switch (severity.toLowerCase()) {
                case "message": {
                    String finalMessage = messageBuilder.append(message).toString();
                    context.logDebugMessage(sourceLocator, finalMessage);
                    logger.info(finalMessage); break;
                }
                case "warning": {
                    String finalMessage = messageBuilder.append(message).toString();
                    context.logDebugWarning(sourceLocator, finalMessage);
                    logger.warn(finalMessage); break;
                }
                case "trace": {
                    String finalMessage = messageBuilder.append(message).append(String.format("%n%s", stripPHI(source))).toString();
                    context.logDebugTrace(sourceLocator, finalMessage);
                    logger.debug(finalMessage); break;
                }
                case "error": {
                    String finalMessage = messageBuilder.append(message).append(String.format("%n%s", stripPHI(source))).toString();
                    // NOTE: debug logging happens through exception-handling
                    logger.error(finalMessage);
                    throw new CqlException(finalMessage);
                }
            }
        }
        return source;
    }

    private static Object stripPHI(Object source) {
        // TODO
        return source;
    }

    @Override
    protected Object internalEvaluate(Context context) {
        Object source = getSource().evaluate(context);
        Boolean condition = (Boolean) getCondition().evaluate(context);
        String code = (String) getCode().evaluate(context);
        String severity = (String) getSeverity().evaluate(context);
        String message = (String) getMessage().evaluate(context);

        return message(context, SourceLocator.fromNode(this, context.getCurrentLibrary()),
                source, condition, code, severity, message
        );
    }
}

@@ -44,16 +44,133 @@
 ution;%0A%0A
+import java.util.Optional;%0Aimport java.util.function.Supplier;%0A%0Aimport org.opencds.cqf.cql.engine.data.DataProvider;%0A
 import o
@@ -1686,32 +1686,41 @@
 %25n%25s%22, stripPHI(
+context, 
 source))).toStri
@@ -1717,32 +1717,32 @@
 ))).toString();%0A
-
                 
@@ -2013,16 +2013,25 @@
 tripPHI(
+context, 
 source))
@@ -2316,85 +2316,385 @@
 ate 
-static Object stripPHI(Object source) %7B%0A        // TODO%0A        return source
+String stripPHI(Context context, Object source) %7B%0A        Optional%3CDataProvider%3E dataProvider = Optional.ofNullable(context.resolveDataProvider(source.getClass().getPackage().getName(), false));%0A%0A        return dataProvider.map(DataProvider::phiObfuscationSupplier).map(Supplier::get)%0A                .map(obfuscator -%3E obfuscator.obfuscate(source))%0A                .orElse(%22%22)
 ;%0A  

implement stripPHI functionality