<commit_before>/*
 * MIT License
 *
 * Copyright (c) 2014 Klemm Software Consulting, <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.kscs.util.plugins.xjc;

import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.xml.namespace.QName;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import com.kscs.util.jaxb.Buildable;
import com.kscs.util.jaxb.PropertyTree;
import com.kscs.util.plugins.xjc.codemodel.ClassName;
import com.kscs.util.plugins.xjc.codemodel.GenerifiedClass;
import com.kscs.util.plugins.xjc.outline.DefinedInterfaceOutline;
import com.kscs.util.plugins.xjc.outline.DefinedPropertyOutline;
import com.kscs.util.plugins.xjc.outline.DefinedTypeOutline;
import com.kscs.util.plugins.xjc.outline.PropertyOutline;
import com.kscs.util.plugins.xjc.outline.ReferencedClassOutline;
import com.kscs.util.plugins.xjc.outline.TypeOutline;
import com.sun.codemodel.JAssignmentTarget;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JConditional;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JFieldRef;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JForEach;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JType;
import com.sun.codemodel.JTypeVar;
import com.sun.codemodel.JVar;
import com.sun.tools.xjc.model.CClassInfo;
import com.sun.tools.xjc.model.CElementInfo;
import com.sun.tools.xjc.model.nav.NClass;
import com.sun.tools.xjc.model.nav.NType;
import com.sun.tools.xjc.outline.Aspect;
import com.sun.xml.bind.v2.model.core.TypeInfo;

import static com.kscs.util.plugins.xjc.base.PluginUtil.nullSafe;

/**
 * Helper class to generate fluent builder classes in two steps
 */
class BuilderGenerator {
	public static final String PRODUCT_VAR_NAME = "_product";
	public static final String PARENT_BUILDER_TYPE_PARAMETER_NAME = "_B";
	public static final String PRODUCT_TYPE_PARAMETER_NAME = "_P";
	public static final String OTHER_PARAM_NAME = "_other";
	public static final String OTHER_VAR_NAME = "_my";
	public static final String PARENT_BUILDER_PARAM_NAME = "_parentBuilder";
	public static final String STORED_VALUE_PARAM_NAME = "_storedValue";
	public static final String NEW_BUILDER_VAR_NAME = "_newBuilder";
	public static final String COPY_FLAG_PARAM_NAME = "_copy";
	private static final String ITEM_VAR_NAME = "_item";
	private final PluginContext pluginContext;
	private final JDefinedClass definedClass;
	private final GenerifiedClass builderClass;
	private final DefinedTypeOutline typeOutline;
	private final Map<String, BuilderOutline> builderOutlines;
	private final JFieldVar parentBuilderField;
	private final JAssignmentTarget storedValueField;
	private final boolean implement;
	private final BuilderGeneratorSettings settings;
	private final ResourceBundle resources;

	BuilderGenerator(final PluginContext pluginContext, final Map<String, BuilderOutline> builderOutlines, final BuilderOutline builderOutline, final BuilderGeneratorSettings settings) {
		this.pluginContext = pluginContext;
		this.settings = settings;
		this.builderOutlines = builderOutlines;
		this.typeOutline = (DefinedTypeOutline)builderOutline.getClassOutline();
		this.definedClass = this.typeOutline.getImplClass();
		this.builderClass = new GenerifiedClass(builderOutline.getDefinedBuilderClass(), BuilderGenerator.PARENT_BUILDER_TYPE_PARAMETER_NAME);
		this.resources = ResourceBundle.getBundle(BuilderGenerator.class.getName());
		this.implement = !this.builderClass.raw.isInterface();
		if (builderOutline.getClassOutline().getSuperClass() == null) {
			final JMethod endMethod = this.builderClass.raw.method(JMod.PUBLIC, this.builderClass.typeParam, this.settings.getEndMethodName());
			if (this.implement) {
				this.parentBuilderField = this.builderClass.raw.field(JMod.PROTECTED | JMod.FINAL, this.builderClass.typeParam, BuilderGenerator.PARENT_BUILDER_PARAM_NAME);
				endMethod.body()._return(JExpr._this().ref(this.parentBuilderField));
				this.storedValueField = this.settings.isCopyAlways() ? null : this.builderClass.raw.field(JMod.PROTECTED | JMod.FINAL, this.definedClass, BuilderGenerator.STORED_VALUE_PARAM_NAME);
			} else {
				this.parentBuilderField = null;
				this.storedValueField = null;
			}
		} else {
			this.parentBuilderField = null;
			this.storedValueField = this.implement ? JExpr.ref(BuilderGenerator.STORED_VALUE_PARAM_NAME) : null;
		}
		if (this.implement) {
			generateCopyConstructor(false);
			if (this.settings.isGeneratingPartialCopy()) {
				generateCopyConstructor(true);
			}
		}
	}

	void generateBuilderMember(final PropertyOutline propertyOutline, final JBlock initBody, final JVar productParam) {
		final JType fieldType = propertyOutline.getRawType();
		if (propertyOutline.isCollection()) {
			if (propertyOutline.getRawType().isArray()) {
				generateArrayProperty(initBody, productParam, propertyOutline, fieldType.elementType(), this.builderClass.type);
			} else {
				final List<JClass> typeParameters = ((JClass)fieldType).getTypeParameters();
				final JClass elementType = typeParameters.get(0);
				generateCollectionProperty(initBody, productParam, propertyOutline, elementType);
				if (propertyOutline.getChoiceProperties().size() > 1) {
					generateCollectionChoiceProperty(propertyOutline);
				}
			}
		} else {
			generateSingularProperty(initBody, productParam, propertyOutline);
			if (propertyOutline.getChoiceProperties().size() > 1) {
				//throw new UnsupportedOperationException("Singular Properties with multiple references not currently supported.");
				generateSingularChoiceProperty(propertyOutline);
			}
		}
	}

	private void generateSingularChoiceProperty(final PropertyOutline propertyOutline) {
		for (final PropertyOutline.TagRef typeInfo : propertyOutline.getChoiceProperties()) {
			final CClassInfo classInfo = (CClassInfo)typeInfo.getTypeInfo();
			final QName elementName = typeInfo.getTagName();
			final JClass elementType = classInfo.toType(this.pluginContext.outline, Aspect.EXPOSED);
			final String fieldName = this.pluginContext.outline.getModel().getNameConverter().toVariableName(elementName.getLocalPart());
			final String propertyName = this.pluginContext.outline.getModel().getNameConverter().toPropertyName(elementName.getLocalPart());
			final BuilderOutline childBuilderOutline = getBuilderDeclaration(elementType);
			final BuilderOutline choiceChildBuilderOutline = getBuilderDeclaration(propertyOutline.getElementType());
			if (childBuilderOutline == null) {
				final JMethod withMethod = this.builderClass.raw.method(JMod.PUBLIC, this.builderClass.type, PluginContext.WITH_METHOD_PREFIX + propertyName);
				final JVar param = withMethod.param(JMod.FINAL, elementType, fieldName);
				generateWithMethodJavadoc(withMethod, param);
				if (this.implement) {
					final JFieldVar builderField = this.builderClass.raw.field(JMod.PRIVATE, elementType, fieldName);
					withMethod.body().assign(JExpr._this().ref(builderField), param);
					withMethod.body()._return(JExpr._this());
				}
			} else {
				final JClass builderFieldElementType = childBuilderOutline.getBuilderClass().narrow(this.builderClass.type);
				final JClass builderWithMethodReturnType = childBuilderOutline.getBuilderClass().narrow(this.builderClass.type.wildcard());
				final JMethod withValueMethod = this.builderClass.raw.method(JMod.PUBLIC, this.builderClass.type, PluginContext.WITH_METHOD_PREFIX + propertyName);
				final JVar param = withValueMethod.param(JMod.FINAL, elementType, fieldName);
				generateWithMethodJavadoc(withValueMethod, param);
				final JMethod withBuilderMethod = this.builderClass.raw.method(JMod.PUBLIC, builderWithMethodReturnType, PluginContext.WITH_METHOD_PREFIX + propertyName);
				generateBuilderMethodJavadoc(withBuilderMethod, "with", fieldName);
				if (this.implement) {
					final JFieldVar builderField = this.builderClass.raw.field(JMod.PRIVATE, builderFieldElementType, fieldName);
					withValueMethod.body().assign(JExpr._this().ref(builderField), nullSafe(param, JExpr._new(builderFieldElementType).arg(JExpr._this()).arg(param)));
					withValueMethod.body()._return(JExpr._this());
					withBuilderMethod.body()._return(JExpr._this().ref(builderField).assign(JExpr._new(builderFieldElementType).arg(JExpr._this()).arg(JExpr._null())));
				}
			}
		}
	}

	private void generateCollectionChoiceProperty(final PropertyOutline propertyOutline) {
		for (final PropertyOutline.TagRef tagRef : propertyOutline.getChoiceProperties()) {
			final TypeInfo<NType,NClass> typeInfo = tagRef.getTypeInfo();
			final QName elementName = tagRef.getTagName();
			final JType elementType = typeInfo.getType().toType(this.pluginContext.outline, Aspect.EXPOSED);
			generateAddMethods(propertyOutline, elementName, elementType);
		}
	}

	private void generateAddMethods(final PropertyOutline propertyOutline,
	                                final QName elementName, final JType jType) {
		final JClass elementType = jType.boxify();
		final JClass iterableType = this.pluginContext.iterableClass.narrow(elementType.wildcard());
		final String fieldName = this.pluginContext.outline.getModel().getNameConverter().toVariableName(elementName.getLocalPart());<commit_msg>Add missing copy args to singularChoiceProperty<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2014 Klemm Software Consulting, <NAME>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.kscs.util.plugins.xjc;

import java.lang.reflect.Modifier;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import javax.xml.namespace.QName;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import com.kscs.util.jaxb.Buildable;
import com.kscs.util.jaxb.PropertyTree;
import com.kscs.util.plugins.xjc.codemodel.ClassName;
import com.kscs.util.plugins.xjc.codemodel.GenerifiedClass;
import com.kscs.util.plugins.xjc.outline.DefinedInterfaceOutline;
import com.kscs.util.plugins.xjc.outline.DefinedPropertyOutline;
import com.kscs.util.plugins.xjc.outline.DefinedTypeOutline;
import com.kscs.util.plugins.xjc.outline.PropertyOutline;
import com.kscs.util.plugins.xjc.outline.ReferencedClassOutline;
import com.kscs.util.plugins.xjc.outline.TypeOutline;
import com.sun.codemodel.JAssignmentTarget;
import com.sun.codemodel.JBlock;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JConditional;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JExpr;
import com.sun.codemodel.JExpression;
import com.sun.codemodel.JFieldRef;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JForEach;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
import com.sun.codemodel.JType;
import com.sun.codemodel.JTypeVar;
import com.sun.codemodel.JVar;
import com.sun.tools.xjc.model.CClassInfo;
import com.sun.tools.xjc.model.CElementInfo;
import com.sun.tools.xjc.model.nav.NClass;
import com.sun.tools.xjc.model.nav.NType;
import com.sun.tools.xjc.outline.Aspect;
import com.sun.xml.bind.v2.model.core.TypeInfo;

import static com.kscs.util.plugins.xjc.base.PluginUtil.nullSafe;

/**
 * Helper class to generate fluent builder classes in two steps
 */
class BuilderGenerator {
	public static final String PRODUCT_VAR_NAME = "_product";
	public static final String PARENT_BUILDER_TYPE_PARAMETER_NAME = "_B";
	public static final String PRODUCT_TYPE_PARAMETER_NAME = "_P";
	public static final String OTHER_PARAM_NAME = "_other";
	public static final String OTHER_VAR_NAME = "_my";
	public static final String PARENT_BUILDER_PARAM_NAME = "_parentBuilder";
	public static final String STORED_VALUE_PARAM_NAME = "_storedValue";
	public static final String NEW_BUILDER_VAR_NAME = "_newBuilder";
	public static final String COPY_FLAG_PARAM_NAME = "_copy";
	private static final String ITEM_VAR_NAME = "_item";
	private final PluginContext pluginContext;
	private final JDefinedClass definedClass;
	private final GenerifiedClass builderClass;
	private final DefinedTypeOutline typeOutline;
	private final Map<String, BuilderOutline> builderOutlines;
	private final JFieldVar parentBuilderField;
	private final JAssignmentTarget storedValueField;
	private final boolean implement;
	private final BuilderGeneratorSettings settings;
	private final ResourceBundle resources;

	BuilderGenerator(final PluginContext pluginContext, final Map<String, BuilderOutline> builderOutlines, final BuilderOutline builderOutline, final BuilderGeneratorSettings settings) {
		this.pluginContext = pluginContext;
		this.settings = settings;
		this.builderOutlines = builderOutlines;
		this.typeOutline = (DefinedTypeOutline)builderOutline.getClassOutline();
		this.definedClass = this.typeOutline.getImplClass();
		this.builderClass = new GenerifiedClass(builderOutline.getDefinedBuilderClass(), BuilderGenerator.PARENT_BUILDER_TYPE_PARAMETER_NAME);
		this.resources = ResourceBundle.getBundle(BuilderGenerator.class.getName());
		this.implement = !this.builderClass.raw.isInterface();
		if (builderOutline.getClassOutline().getSuperClass() == null) {
			final JMethod endMethod = this.builderClass.raw.method(JMod.PUBLIC, this.builderClass.typeParam, this.settings.getEndMethodName());
			if (this.implement) {
				this.parentBuilderField = this.builderClass.raw.field(JMod.PROTECTED | JMod.FINAL, this.builderClass.typeParam, BuilderGenerator.PARENT_BUILDER_PARAM_NAME);
				endMethod.body()._return(JExpr._this().ref(this.parentBuilderField));
				this.storedValueField = this.settings.isCopyAlways() ? null : this.builderClass.raw.field(JMod.PROTECTED | JMod.FINAL, this.definedClass, BuilderGenerator.STORED_VALUE_PARAM_NAME);
			} else {
				this.parentBuilderField = null;
				this.storedValueField = null;
			}
		} else {
			this.parentBuilderField = null;
			this.storedValueField = this.implement ? JExpr.ref(BuilderGenerator.STORED_VALUE_PARAM_NAME) : null;
		}
		if (this.implement) {
			generateCopyConstructor(false);
			if (this.settings.isGeneratingPartialCopy()) {
				generateCopyConstructor(true);
			}
		}
	}

	void generateBuilderMember(final PropertyOutline propertyOutline, final JBlock initBody, final JVar productParam) {
		final JType fieldType = propertyOutline.getRawType();
		if (propertyOutline.isCollection()) {
			if (propertyOutline.getRawType().isArray()) {
				generateArrayProperty(initBody, productParam, propertyOutline, fieldType.elementType(), this.builderClass.type);
			} else {
				final List<JClass> typeParameters = ((JClass)fieldType).getTypeParameters();
				final JClass elementType = typeParameters.get(0);
				generateCollectionProperty(initBody, productParam, propertyOutline, elementType);
				if (propertyOutline.getChoiceProperties().size() > 1) {
					generateCollectionChoiceProperty(propertyOutline);
				}
			}
		} else {
			generateSingularProperty(initBody, productParam, propertyOutline);
			if (propertyOutline.getChoiceProperties().size() > 1) {
				//throw new UnsupportedOperationException("Singular Properties with multiple references not currently supported.");
				generateSingularChoiceProperty(propertyOutline);
			}
		}
	}

	private void generateSingularChoiceProperty(final PropertyOutline propertyOutline) {
		for (final PropertyOutline.TagRef typeInfo : propertyOutline.getChoiceProperties()) {
			final CClassInfo classInfo = (CClassInfo)typeInfo.getTypeInfo();
			final QName elementName = typeInfo.getTagName();
			final JClass elementType = classInfo.toType(this.pluginContext.outline, Aspect.EXPOSED);
			final String fieldName = this.pluginContext.outline.getModel().getNameConverter().toVariableName(elementName.getLocalPart());
			final String propertyName = this.pluginContext.outline.getModel().getNameConverter().toPropertyName(elementName.getLocalPart());
			final BuilderOutline childBuilderOutline = getBuilderDeclaration(elementType);
			final BuilderOutline choiceChildBuilderOutline = getBuilderDeclaration(propertyOutline.getElementType());
			if (childBuilderOutline == null) {
				final JMethod withMethod = this.builderClass.raw.method(JMod.PUBLIC, this.builderClass.type, PluginContext.WITH_METHOD_PREFIX + propertyName);
				final JVar param = withMethod.param(JMod.FINAL, elementType, fieldName);
				generateWithMethodJavadoc(withMethod, param);
				if (this.implement) {
					final JFieldVar builderField = this.builderClass.raw.field(JMod.PRIVATE, elementType, fieldName);
					withMethod.body().assign(JExpr._this().ref(builderField), param);
					withMethod.body()._return(JExpr._this());
				}
			} else {
				final JClass builderFieldElementType = childBuilderOutline.getBuilderClass().narrow(this.builderClass.type);
				final JClass builderWithMethodReturnType = childBuilderOutline.getBuilderClass().narrow(this.builderClass.type.wildcard());
				final JMethod withValueMethod = this.builderClass.raw.method(JMod.PUBLIC, this.builderClass.type, PluginContext.WITH_METHOD_PREFIX + propertyName);
				final JVar param = withValueMethod.param(JMod.FINAL, elementType, fieldName);
				generateWithMethodJavadoc(withValueMethod, param);
				final JMethod withBuilderMethod = this.builderClass.raw.method(JMod.PUBLIC, builderWithMethodReturnType, PluginContext.WITH_METHOD_PREFIX + propertyName);
				generateBuilderMethodJavadoc(withBuilderMethod, "with", fieldName);
				if (this.implement) {
					final JFieldVar builderField = this.builderClass.raw.field(JMod.PRIVATE, builderFieldElementType, fieldName);
					withValueMethod.body().assign(JExpr._this().ref(builderField), nullSafe(param, JExpr._new(builderFieldElementType).arg(JExpr._this()).arg(param).arg(JExpr.FALSE)));
					withValueMethod.body()._return(JExpr._this());
					withBuilderMethod.body()._return(JExpr._this().ref(builderField).assign(JExpr._new(builderFieldElementType).arg(JExpr._this()).arg(JExpr._null()).arg(JExpr.FALSE)));
				}
			}
		}
	}

	private void generateCollectionChoiceProperty(final PropertyOutline propertyOutline) {
		for (final PropertyOutline.TagRef tagRef : propertyOutline.getChoiceProperties()) {
			final TypeInfo<NType,NClass> typeInfo = tagRef.getTypeInfo();
			final QName elementName = tagRef.getTagName();
			final JType elementType = typeInfo.getType().toType(this.pluginContext.outline, Aspect.EXPOSED);
			generateAddMethods(propertyOutline, elementName, elementType);
		}
	}

	private void generateAddMethods(final PropertyOutline propertyOutline,
	                                final QName elementName, final JType jType) {
		final JClass elementType = jType.boxify();
		final JClass iterableType = this.pluginContext.iterableClass.narrow(elementType.wildcard());
		final String fieldName = this.pluginContext.outline.getModel().getNameConverter().toVariableName(elementName.getLocalPart());
{'fraction_non_alphanumeric': 0.09678951367781155, 'fraction_numerical': 0.0007598784194528875, 'mean_word_length': 5.762042389210019, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 8}, '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': '7058156', 'n_tokens_mistral': 6631, 'n_tokens_neox': 6100, 'n_words': 1334}