<commit_before>package io.asfjava.ui.core.schema;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;

import io.asfjava.ui.core.FormDefinitionGeneratorFactory;
import io.asfjava.ui.core.form.Tab;
import io.asfjava.ui.dto.UiForm;

public final class UiFormSchemaGenerator {

	private static UiFormSchemaGenerator instance;

	public UiForm generate(Class<? extends Serializable> formDto) throws JsonMappingException {
		Field[] declaredFields = formDto.getDeclaredFields();
		ObjectMapper mapper = new ObjectMapper();

		JsonSchemaGenerator schemaGen = initSchemaGen(mapper);
		JsonSchema schema = generateSchema(formDto, schemaGen);
		Map<Field, JsonNode> nodes = initFieldFormDefinition(mapper, declaredFields);

		handlerGroupedFields();

		ObjectNode tabbedFields = handleTabbedFields(mapper, declaredFields, nodes);

		ArrayNode formDefinition = mapper.createArrayNode();
		formDefinition.add(tabbedFields);
		nodes.entrySet().stream().forEach(nodesElement -> formDefinition.add(nodesElement.getValue()));

		return new UiForm(schema, formDefinition);
	}

	private void handlerGroupedFields() {
		// TODO Grouping fieldset must handle it

	}

	private ObjectNode handleTabbedFields(ObjectMapper mapper, Field[] declaredFields, Map<Field, JsonNode> nodes) {
		Predicate<? super Field> checkTabAnnotation = field -> field.isAnnotationPresent(Tab.class);
		Comparator<? super Field> tabIndexComparator = (field1, field2) -> Integer
				.compare(field1.getAnnotation(Tab.class).index(), field2.getAnnotation(Tab.class).index());

		Map<String, List<JsonNode>> groupedFieldsByTab = new LinkedHashMap<>();

		Arrays.stream(declaredFields).filter(checkTabAnnotation).sorted(tabIndexComparator)
				.forEach(field -> groupFieldsByTab(nodes, field, groupedFieldsByTab));

		ArrayNode tabs = mapper.createArrayNode();

		groupedFieldsByTab.entrySet().stream().forEachOrdered(tabElements -> {
			ObjectNode tabNode = mapper.createObjectNode();
			tabNode.put("title", tabElements.getKey());
			ArrayNode tabItems = mapper.createArrayNode();
			tabElements.getValue().stream().forEach(tabItems::add);
			tabNode.put("items", tabItems);
			tabs.add(tabNode);
		});

		ObjectNode tabsNode = mapper.createObjectNode();
		tabsNode.put("type", "tabs");
		tabsNode.put("tabs", tabs);
		return tabsNode;

	}

	private Map<Field, JsonNode> initFieldFormDefinition(ObjectMapper mapper, Field[] declaredFields) {
		Map<Field, JsonNode> nodes = new HashMap<>();
		Arrays.stream(declaredFields).forEach(field -> buildFormDefinition(nodes, mapper, field));
		return nodes;
	}

	private JsonSchema generateSchema(Class<? extends Serializable> formDto, JsonSchemaGenerator schemaGen)<commit_msg>add new @index annotation<commit_after>package io.asfjava.ui.core.schema;

import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;

import io.asfjava.ui.core.FormDefinitionGeneratorFactory;
import io.asfjava.ui.core.form.Index;
import io.asfjava.ui.core.form.Tab;
import io.asfjava.ui.dto.UiForm;

public final class UiFormSchemaGenerator {

	private static UiFormSchemaGenerator instance;

	public UiForm generate(Class<? extends Serializable> formDto) throws JsonMappingException {
		Field[] declaredFields = formDto.getDeclaredFields();
		ObjectMapper mapper = new ObjectMapper();

		JsonSchemaGenerator schemaGen = initSchemaGen(mapper);
		JsonSchema schema = generateSchema(formDto, schemaGen);
		Map<Field, JsonNode> nodes = initFieldFormDefinition(mapper, declaredFields);

		handlerGroupedFields();

		ObjectNode tabbedFields = handleTabbedFields(mapper, declaredFields, nodes);

		ArrayNode formDefinition = mapper.createArrayNode();
		formDefinition.add(tabbedFields);
		nodes.entrySet().stream().forEach(nodesElement -> formDefinition.add(nodesElement.getValue()));

		return new UiForm(schema, formDefinition);
	}

	private void handlerGroupedFields() {
		// TODO Grouping fieldset must handle it

	}

	private ObjectNode handleTabbedFields(ObjectMapper mapper, Field[] declaredFields, Map<Field, JsonNode> nodes) {
		Predicate<? super Field> checkTabAnnotation = field -> field.isAnnotationPresent(Tab.class);
		Comparator<? super Field> tabIndexComparator = (field1, field2) -> Integer
				.compare(field1.getAnnotation(Tab.class).index(), field2.getAnnotation(Tab.class).index());

		Map<String, List<JsonNode>> groupedFieldsByTab = new LinkedHashMap<>();

		Arrays.stream(declaredFields).filter(checkTabAnnotation).sorted(tabIndexComparator)
				.forEach(field -> groupFieldsByTab(nodes, field, groupedFieldsByTab));

		ArrayNode tabs = mapper.createArrayNode();

		groupedFieldsByTab.entrySet().stream().forEachOrdered(tabElements -> {
			ObjectNode tabNode = mapper.createObjectNode();
			tabNode.put("title", tabElements.getKey());
			ArrayNode tabItems = mapper.createArrayNode();
			tabElements.getValue().stream().forEach(tabItems::add);
			tabNode.put("items", tabItems);
			tabs.add(tabNode);
		});

		ObjectNode tabsNode = mapper.createObjectNode();
		tabsNode.put("type", "tabs");
		tabsNode.put("tabs", tabs);
		return tabsNode;

	}

	private Map<Field, JsonNode> initFieldFormDefinition(ObjectMapper mapper, Field[] declaredFields) {
		Map<Field, JsonNode> nodes = new LinkedHashMap<>();
		
		Predicate<? super Field> checkIndexAnnotation = field -> field.isAnnotationPresent(Index.class);
		Comparator<? super Field> fieldIndexComparator = (field1, field2) -> Integer
				.compare(field1.getAnnotation(Index.class).value(), field2.getAnnotation(Index.class).value());

		Arrays.stream(declaredFields).filter(checkIndexAnnotation).sorted(fieldIndexComparator)
				.forEachOrdered(field -> buildFormDefinition(nodes, mapper, field));
		
		return nodes;
	}

	private JsonSchema generateSchema(Class<? extends Serializable> formDto, JsonSchemaGenerator schemaGen)
{'fraction_non_alphanumeric': 0.11588890455378542, 'fraction_numerical': 0.0016918088256027068, 'mean_word_length': 6.3360910031023785, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 14}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3316011', 'n_tokens_mistral': 2201, 'n_tokens_neox': 2019, 'n_words': 398}