package com.acme.tif.validation;

import com.technia.tvc.core.TVCSystem;
import com.technia.tvc.core.res.DefaultResourceDefType;
import com.technia.tvc.core.res.ResourceDefType;
import com.technia.tvc.core.util.StringUtils;

import com.technia.tif.core.ValidationException;
import com.technia.tif.core.validation.ValidationContext;
import com.technia.tif.core.validation.Validator;

import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;

import javax.json.stream.JsonParser;

import org.leadpony.justify.api.JsonSchema;
import org.leadpony.justify.api.JsonValidationService;
import org.leadpony.justify.api.ProblemHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * An example class that validates JSON payload against JSON schema with Justify
 * JSON validator (0.10.0). The class expects property "schema" that should point 
 * out a TVC resource representing JSON schema definition. For example
 * "tvc:json/MySchema.json".
 * 
 * JSON Schema documentation: https://json-schema.org/
 * 
 * Justify: https://github.com/leadpony/justify (see instructions for required
 * dependencies and examples)
 *
 * To execute the class in TIF, the following JAR files needs to be placed under 
 * TIF_ROOT/modules/enovia/lib/custom: 
 * 
 * justify-0.10.0.jar
 * javax.json-1.1.4.jar (or other JSR-374 implementation)
 *
 * @author <a href="mailto:mikko.tuomela@technia.com">Mikko Tuomela</a>
 * @since 2019.1.0
 */
public class JustifyJSONValidator implements Validator {

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

    @Override
    /**
     * Main entry point of the validator.
     * 
     */
    public void validate(ValidationContext ctx) throws ValidationException {
        long start = System.currentTimeMillis();
        Path schemaPath = getSchemaResource(ctx);
        JsonValidationService service = JsonValidationService.newInstance();
        JsonSchema schema = service.readSchema(schemaPath);
        ProblemHandler handler = service.createProblemPrinter(logger::error);
        try (JsonParser parser = service.createParser(ctx.getInputStream(), schema, handler)) {
            while (parser.hasNext()) {
                parser.next();
            }
        } catch (Throwable t) {
            throw new ValidationException(t);
        }
        if (logger.isDebugEnabled()) {
            logger.debug("Payload validated in {} ms", (System.currentTimeMillis() - start));
        }
    }

    private Path getSchemaResource(ValidationContext ctx) throws ValidationException {
        try {
            String schemaResourceName = ctx.getProperty("schema");
            if (StringUtils.isBlank(schemaResourceName)) {
                throw new ValidationException("Property 'schema' not defined");
            }
            ResourceDefType dt = new DefaultResourceDefType("json");
            URL schemaFileUrl = TVCSystem.getInstance().getResourceLocator().getDefinitionResource(dt,
                    schemaResourceName);
            return Paths.get(schemaFileUrl.toURI());
        } catch (URISyntaxException e) {
            throw new ValidationException(e);
        }
    }

}
