package com.github.skrethel.simple.config.retrofit.io;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.skrethel.simple.config.retrofit.exception.GetException;
import com.github.skrethel.simple.config.retrofit.schema.ConfigSchema;
import com.github.skrethel.simple.config.retrofit.schema.SchemaItem;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;


public class SchemaFileSource implements SchemaSource {

	private static final Logger LOGGER = Logger.getLogger(SchemaFileSource.class);

	private ValidatorFactory validatorFactory = Validation.byDefaultProvider()
		.configure()
		.buildValidatorFactory();
	private Validator validator = validatorFactory.getValidator();

	private String path;
	private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

	static  {
		OBJECT_MAPPER.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
	}

	public SchemaFileSource(String path) {
		this.path = path;

	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	@Override public ConfigSchema getSchema() throws GetException {
		File source = new File(path);
		try {
			ConfigSchema schema = OBJECT_MAPPER.readValue(source, ConfigSchema.class);
			validate(schema);
			return schema;
		} catch (IOException e) {
			LOGGER.debug("Cannot read schema data due to error " + e.getMessage(), e);
			throw new GetException("Cannot read schema", e);
		}
	}

	private void validate(ConfigSchema schema) throws GetException {

		ArrayList<String> violationMessages = new ArrayList<>();
		for (int i = 0; i < schema.size(); i++) {
			SchemaItem item = schema.get(i);
			Set<ConstraintViolation<SchemaItem>> violations = validator.validate(item);
			for (ConstraintViolation<SchemaItem> violation : violations) {
				violationMessages.add("Schema item " + (i + 1) +
					": " + violation.getPropertyPath() + ": " + violation.getMessage());
			}
		}
		if (violationMessages.isEmpty()) {
			return;
		}
		throw new GetException("Invalid input schema. Violations: " + StringUtils.join(violationMessages, ", "));
	}
}

@@ -658,24 +658,52 @@
 OException;%0A
+import java.io.InputStream;%0A
 import java.
@@ -1086,16 +1086,50 @@
 g path;%0A
+%09private InputStream inputStream;%0A
 %09private
@@ -1344,16 +1344,105 @@
 = path;%0A
+%09%7D%0A%0A%09public SchemaFileSource(InputStream inputStream) %7B%0A%09%09this.inputStream = inputStream;
 %0A%09%7D%0A%0A%09pu
@@ -1615,121 +1615,51 @@
 %7B%0A%09%09
-File source = new File(path);%0A%09%09try %7B%0A%09%09%09ConfigSchema schema = OBJECT_MAPPER.readValue(source, ConfigSchema.class
+try %7B%0A%09%09%09ConfigSchema schema = parseSchema(
 );%0A%09
@@ -1862,16 +1862,401 @@
 %09%09%7D%0A%09%7D%0A%0A
+%09private ConfigSchema parseSchema() throws IOException, GetException %7B%0A%09%09if (path != null) %7B%0A%09%09%09File source = new File(path);%0A%09%09%09return OBJECT_MAPPER.readValue(source, ConfigSchema.class);%0A%09%09%7D else if (inputStream != null) %7B%0A%09%09%09return OBJECT_MAPPER.readValue(inputStream, ConfigSchema.class);%0A%09%09%7D else %7B%0A%09%09%09throw new GetException(%22Invalid input: no path or stream specified%22);%0A%09%09%7D%0A%09%7D%0A%0A
 %09private

Add possibility to feed stream to SchemaFileSource