package com.airlock.iam.admin.application.configuration.generic;

import com.airlock.iam.admin.api.domain.model.token.generic.GenericToken;
import com.airlock.iam.admin.api.domain.model.token.generic.GenericTokenAttributeMapping;
import com.airlock.iam.base.misc.date.Dates;
import com.airlock.iam.plugin.api.annotation.config.ConfigurationValidator;
import com.airlock.iam.plugin.api.annotation.config.Plugin;
import com.airlock.iam.plugin.api.annotation.property.StringProperty;
import com.airlock.iam.plugin.api.config.ConfigurationContext;
import com.airlock.iam.plugin.api.config.ConfigurationEnvironment;
import com.airlock.iam.plugin.api.config.Environment;
import com.airlock.iam.plugin.api.config.PluginConfiguration;
import com.airlock.iam.plugin.api.exception.ConfigurationException;
import com.airlock.iam.plugin.api.exception.PropertyConstraintViolationException;
import com.airlock.iam.plugin.api.exception.PropertyTypeMismatchException;
import com.airlock.iam.plugin.api.valuereader.StringPropertyValueReader;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;

@Plugin(
   description = "Filters and maps attributes from the outside to the generic token and vice versa.\n<p>All token attributes must be considered optional.</p>\n<p>This plugin is designed to work only with the token-based repository that is shipped with IAM.\nFor custom repository implementations, custom attribute mappings are needed.</p>",
   displayName = "Token-based Attribute Mapping"
)
public final class TokenBasedAttributeMapping implements GenericTokenAttributeMappingConfig {
   private static final Pattern ATTRIBUTE_PATTERN = Pattern.compile("[a-zA-Z0-9_-]+");
   @StringProperty(description = "The serial ID of this token.", displayName = "Serial ID", optional = true, suggestedValues = "serialId")
   private String serialId;
   @StringProperty(description = "Indicates whether this token is enabled. This is a read-only property.", optional = true, suggestedValues = "enabled")
   private String enabled;
   @StringProperty(description = "The activation date of this token. This is a read-only property.", optional = true, suggestedValues = "activationDate")
   private String activationDate;
   @StringProperty(description = "Date as of which the token is valid.", optional = true, suggestedValues = "validFrom")
   private String validFrom;
   @StringProperty(description = "Expiration date of this token.", optional = true, suggestedValues = "validTo")
   private String validTo;
   @StringProperty(description = "The activation date of this token. This is a read-only property.", optional = true, suggestedValues = "generationDate")
   private String generationDate;
   @StringProperty(description = "Date of first usage. This is a read-only property.", optional = true, suggestedValues = "firstUsageDate")
   private String firstUsageDate;
   @StringProperty(description = "Date of latest usage. This is a read-only property.", optional = true, suggestedValues = "latestUsageDate")
   private String latestUsageDate;
   @StringProperty(description = "Total number of usages. This is a read-only property.", optional = true, suggestedValues = "totalUsages")
   private String totalUsages;
   @StringProperty(description = "The tracking ID of this token.", displayName = "Tracking ID", optional = true, suggestedValues = "trackingId")
   private String trackingId;
   @StringProperty(
      description = "An array with the IDs of the other assignees of this token (excluding the current user).",
      optional = true,
      suggestedValues = "otherAssignees"
   )
   private String otherAssignees;
   @StringProperty(description = "The actual data of this token.", optional = true)
   private String data;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement1;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement2;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement3;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement4;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement5;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement6;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement7;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement8;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement9;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement10;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement11;
   @StringProperty(description = "A general purpose data field.", optional = true)
   private String genericDataElement12;

   private Optional<String> getMappingForSerialId() {
      return Optional.ofNullable(this.serialId);
   }

   @Override
   public Optional<String> getMappingForEnabled() {
      return Optional.ofNullable(this.enabled);
   }

   private Optional<String> getMappingForActivationDate() {
      return Optional.ofNullable(this.activationDate);
   }

   private Optional<String> getMappingForValidFrom() {
      return Optional.ofNullable(this.validFrom);
   }

   private Optional<String> getMappingForValidTo() {
      return Optional.ofNullable(this.validTo);
   }

   private Optional<String> getMappingForGenerationDate() {
      return Optional.ofNullable(this.generationDate);
   }

   private Optional<String> getMappingForFirstUsageDate() {
      return Optional.ofNullable(this.firstUsageDate);
   }

   private Optional<String> getMappingForLatestUsageDate() {
      return Optional.ofNullable(this.latestUsageDate);
   }

   private Optional<String> getMappingForTotalUsages() {
      return Optional.ofNullable(this.totalUsages);
   }

   private Optional<String> getMappingForTrackingId() {
      return Optional.ofNullable(this.trackingId);
   }

   private Optional<String> getMappingForOtherAssignees() {
      return Optional.ofNullable(this.otherAssignees);
   }

   private Optional<String> getMappingForData() {
      return Optional.ofNullable(this.data);
   }

   private Optional<String> getMappingForGenericDataElement1() {
      return Optional.ofNullable(this.genericDataElement1);
   }

   private Optional<String> getMappingForGenericDataElement2() {
      return Optional.ofNullable(this.genericDataElement2);
   }

   private Optional<String> getMappingForGenericDataElement3() {
      return Optional.ofNullable(this.genericDataElement3);
   }

   private Optional<String> getMappingForGenericDataElement4() {
      return Optional.ofNullable(this.genericDataElement4);
   }

   private Optional<String> getMappingForGenericDataElement5() {
      return Optional.ofNullable(this.genericDataElement5);
   }

   private Optional<String> getMappingForGenericDataElement6() {
      return Optional.ofNullable(this.genericDataElement6);
   }

   private Optional<String> getMappingForGenericDataElement7() {
      return Optional.ofNullable(this.genericDataElement7);
   }

   private Optional<String> getMappingForGenericDataElement8() {
      return Optional.ofNullable(this.genericDataElement8);
   }

   private Optional<String> getMappingForGenericDataElement9() {
      return Optional.ofNullable(this.genericDataElement9);
   }

   private Optional<String> getMappingForGenericDataElement10() {
      return Optional.ofNullable(this.genericDataElement10);
   }

   private Optional<String> getMappingForGenericDataElement11() {
      return Optional.ofNullable(this.genericDataElement11);
   }

   private Optional<String> getMappingForGenericDataElement12() {
      return Optional.ofNullable(this.genericDataElement12);
   }

   @Override
   public GenericTokenAttributeMapping getMapping() {
      Map<String, MappingEntry> mappings = new HashMap<>();
      this.getMappingForSerialId().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "serialId")));
      this.getMappingForEnabled()
         .ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(true, "active", value -> value == null ? Boolean.FALSE : (Boolean)value)));
      this.getMappingForActivationDate().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(true, "activationDate", Dates::toDate)));
      this.getMappingForValidFrom().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "validFrom", Dates::toDate)));
      this.getMappingForValidTo().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "validTo", Dates::toDate)));
      this.getMappingForGenerationDate().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(true, "generationDate", Dates::toDate)));
      this.getMappingForFirstUsageDate().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(true, "firstUsageDate", Dates::toDate)));
      this.getMappingForLatestUsageDate().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(true, "latestUsageDate", Dates::toDate)));
      this.getMappingForTotalUsages().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(true, "totalUsages")));
      this.getMappingForTrackingId().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "trackingId")));
      this.getMappingForOtherAssignees().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(true, "otherAssignees")));
      this.getMappingForData().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "tokenData")));
      this.getMappingForGenericDataElement1().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement1")));
      this.getMappingForGenericDataElement2().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement2")));
      this.getMappingForGenericDataElement3().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement3")));
      this.getMappingForGenericDataElement4().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement4")));
      this.getMappingForGenericDataElement5().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement5")));
      this.getMappingForGenericDataElement6().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement6")));
      this.getMappingForGenericDataElement7().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement7")));
      this.getMappingForGenericDataElement8().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement8")));
      this.getMappingForGenericDataElement9().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement9")));
      this.getMappingForGenericDataElement10().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement10")));
      this.getMappingForGenericDataElement11().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement11")));
      this.getMappingForGenericDataElement12().ifPresent(mapping -> mappings.put(mapping, this.mappingEntry(false, "genericDataElement12")));
      return new TokenAttributeMapping(mappings);
   }

   private MappingEntry mappingEntry(boolean readOnly, String fieldName) {
      return this.mappingEntry(readOnly, fieldName, v -> v);
   }

   private <T> MappingEntry mappingEntry(boolean readOnly, final String fieldName, final Function<Object, T> valueConverter) {
      return new MappingEntry(readOnly) {
         @Override
         void setAttributeValueOnToken(Object value, GenericToken token) {
            token.putAttribute(fieldName, valueConverter.apply(value));
         }

         @Override
         Object getAttributeValueFromToken(GenericToken token) {
            return token.getAttribute(fieldName);
         }
      };
   }

   @ConfigurationValidator
   public static void validateFields(PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context, Environment validationEnvironment) throws ConfigurationException {
      Set<String> attributeNames = new HashSet<>();

      for (Field field : TokenBasedAttributeMapping.class.getDeclaredFields()) {
         if (field.getAnnotation(StringProperty.class) != null) {
            String attributeName = checkAttributeNameFormat(field.getName(), config, env, context);
            if (attributeName != null && !attributeNames.add(attributeName)) {
               throw new PropertyConstraintViolationException(
                  field.getName(),
                  config,
                  env,
                  context,
                  String.format("The attribute names must be unique. An attribute with name '%s' already exists.", attributeName)
               );
            }
         }
      }
   }

   private static String checkAttributeNameFormat(String propertyName, PluginConfiguration config, ConfigurationEnvironment env, ConfigurationContext context) throws PropertyConstraintViolationException, PropertyTypeMismatchException {
      String fieldValue = StringPropertyValueReader.effectiveStringConfigValue(config, propertyName, env, context);
      if (StringUtils.isEmpty(fieldValue)) {
         return null;
      } else if (!ATTRIBUTE_PATTERN.matcher(fieldValue).matches()) {
         throw new PropertyConstraintViolationException(
            propertyName, config, env, context, String.format("The attribute name must match the pattern %s.", ATTRIBUTE_PATTERN.pattern())
         );
      } else {
         return fieldValue;
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   public static TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder builder() {
      return new TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   public TokenBasedAttributeMapping() {
   }

   @SuppressFBWarnings(justification = "generated code")
   public TokenBasedAttributeMapping(
      String serialId,
      String enabled,
      String activationDate,
      String validFrom,
      String validTo,
      String generationDate,
      String firstUsageDate,
      String latestUsageDate,
      String totalUsages,
      String trackingId,
      String otherAssignees,
      String data,
      String genericDataElement1,
      String genericDataElement2,
      String genericDataElement3,
      String genericDataElement4,
      String genericDataElement5,
      String genericDataElement6,
      String genericDataElement7,
      String genericDataElement8,
      String genericDataElement9,
      String genericDataElement10,
      String genericDataElement11,
      String genericDataElement12
   ) {
      this.serialId = serialId;
      this.enabled = enabled;
      this.activationDate = activationDate;
      this.validFrom = validFrom;
      this.validTo = validTo;
      this.generationDate = generationDate;
      this.firstUsageDate = firstUsageDate;
      this.latestUsageDate = latestUsageDate;
      this.totalUsages = totalUsages;
      this.trackingId = trackingId;
      this.otherAssignees = otherAssignees;
      this.data = data;
      this.genericDataElement1 = genericDataElement1;
      this.genericDataElement2 = genericDataElement2;
      this.genericDataElement3 = genericDataElement3;
      this.genericDataElement4 = genericDataElement4;
      this.genericDataElement5 = genericDataElement5;
      this.genericDataElement6 = genericDataElement6;
      this.genericDataElement7 = genericDataElement7;
      this.genericDataElement8 = genericDataElement8;
      this.genericDataElement9 = genericDataElement9;
      this.genericDataElement10 = genericDataElement10;
      this.genericDataElement11 = genericDataElement11;
      this.genericDataElement12 = genericDataElement12;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class TokenBasedAttributeMappingBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String serialId;
      @SuppressFBWarnings(justification = "generated code")
      private String enabled;
      @SuppressFBWarnings(justification = "generated code")
      private String activationDate;
      @SuppressFBWarnings(justification = "generated code")
      private String validFrom;
      @SuppressFBWarnings(justification = "generated code")
      private String validTo;
      @SuppressFBWarnings(justification = "generated code")
      private String generationDate;
      @SuppressFBWarnings(justification = "generated code")
      private String firstUsageDate;
      @SuppressFBWarnings(justification = "generated code")
      private String latestUsageDate;
      @SuppressFBWarnings(justification = "generated code")
      private String totalUsages;
      @SuppressFBWarnings(justification = "generated code")
      private String trackingId;
      @SuppressFBWarnings(justification = "generated code")
      private String otherAssignees;
      @SuppressFBWarnings(justification = "generated code")
      private String data;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement1;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement2;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement3;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement4;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement5;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement6;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement7;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement8;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement9;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement10;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement11;
      @SuppressFBWarnings(justification = "generated code")
      private String genericDataElement12;

      @SuppressFBWarnings(justification = "generated code")
      TokenBasedAttributeMappingBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder serialId(String serialId) {
         this.serialId = serialId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder enabled(String enabled) {
         this.enabled = enabled;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder activationDate(String activationDate) {
         this.activationDate = activationDate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder validFrom(String validFrom) {
         this.validFrom = validFrom;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder validTo(String validTo) {
         this.validTo = validTo;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder generationDate(String generationDate) {
         this.generationDate = generationDate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder firstUsageDate(String firstUsageDate) {
         this.firstUsageDate = firstUsageDate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder latestUsageDate(String latestUsageDate) {
         this.latestUsageDate = latestUsageDate;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder totalUsages(String totalUsages) {
         this.totalUsages = totalUsages;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder trackingId(String trackingId) {
         this.trackingId = trackingId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder otherAssignees(String otherAssignees) {
         this.otherAssignees = otherAssignees;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder data(String data) {
         this.data = data;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement1(String genericDataElement1) {
         this.genericDataElement1 = genericDataElement1;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement2(String genericDataElement2) {
         this.genericDataElement2 = genericDataElement2;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement3(String genericDataElement3) {
         this.genericDataElement3 = genericDataElement3;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement4(String genericDataElement4) {
         this.genericDataElement4 = genericDataElement4;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement5(String genericDataElement5) {
         this.genericDataElement5 = genericDataElement5;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement6(String genericDataElement6) {
         this.genericDataElement6 = genericDataElement6;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement7(String genericDataElement7) {
         this.genericDataElement7 = genericDataElement7;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement8(String genericDataElement8) {
         this.genericDataElement8 = genericDataElement8;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement9(String genericDataElement9) {
         this.genericDataElement9 = genericDataElement9;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement10(String genericDataElement10) {
         this.genericDataElement10 = genericDataElement10;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement11(String genericDataElement11) {
         this.genericDataElement11 = genericDataElement11;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder genericDataElement12(String genericDataElement12) {
         this.genericDataElement12 = genericDataElement12;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public TokenBasedAttributeMapping build() {
         return new TokenBasedAttributeMapping(
            this.serialId,
            this.enabled,
            this.activationDate,
            this.validFrom,
            this.validTo,
            this.generationDate,
            this.firstUsageDate,
            this.latestUsageDate,
            this.totalUsages,
            this.trackingId,
            this.otherAssignees,
            this.data,
            this.genericDataElement1,
            this.genericDataElement2,
            this.genericDataElement3,
            this.genericDataElement4,
            this.genericDataElement5,
            this.genericDataElement6,
            this.genericDataElement7,
            this.genericDataElement8,
            this.genericDataElement9,
            this.genericDataElement10,
            this.genericDataElement11,
            this.genericDataElement12
         );
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "TokenBasedAttributeMapping.TokenBasedAttributeMappingBuilder(serialId="
            + this.serialId
            + ", enabled="
            + this.enabled
            + ", activationDate="
            + this.activationDate
            + ", validFrom="
            + this.validFrom
            + ", validTo="
            + this.validTo
            + ", generationDate="
            + this.generationDate
            + ", firstUsageDate="
            + this.firstUsageDate
            + ", latestUsageDate="
            + this.latestUsageDate
            + ", totalUsages="
            + this.totalUsages
            + ", trackingId="
            + this.trackingId
            + ", otherAssignees="
            + this.otherAssignees
            + ", data="
            + this.data
            + ", genericDataElement1="
            + this.genericDataElement1
            + ", genericDataElement2="
            + this.genericDataElement2
            + ", genericDataElement3="
            + this.genericDataElement3
            + ", genericDataElement4="
            + this.genericDataElement4
            + ", genericDataElement5="
            + this.genericDataElement5
            + ", genericDataElement6="
            + this.genericDataElement6
            + ", genericDataElement7="
            + this.genericDataElement7
            + ", genericDataElement8="
            + this.genericDataElement8
            + ", genericDataElement9="
            + this.genericDataElement9
            + ", genericDataElement10="
            + this.genericDataElement10
            + ", genericDataElement11="
            + this.genericDataElement11
            + ", genericDataElement12="
            + this.genericDataElement12
            + ")";
      }
   }
}
