package org.slc.sli.ingestion.handler;

import java.util.Arrays;
import java.util.List;

import org.springframework.context.MessageSource;
import org.springframework.dao.DuplicateKeyException;

import org.slc.sli.domain.Entity;
import org.slc.sli.domain.Repository;
import org.slc.sli.ingestion.transformation.SimpleEntity;
import org.slc.sli.ingestion.validation.ErrorReport;
import org.slc.sli.validation.EntityValidationException;
import org.slc.sli.validation.ValidationError;

/**
 * Handles the persisting of Entity objects
 *
 * @author dduran
 *         Modified by Thomas Shewchuk (PI3 US811)
 *         - 2/1/2010 Added record DB lookup and update capabilities, and support for association
 *         entities.
 *
 */
public class EntityPersistHandler extends AbstractIngestionHandler<SimpleEntity, Entity> {

    // private static final Logger LOG = LoggerFactory.getLogger(EntityPersistHandler.class);

    private Repository<Entity> entityRepository;

    private MessageSource messageSource;

    @Override
    Entity doHandling(SimpleEntity entity, ErrorReport errorReport) {
        try {
            return persist(entity);
        } catch (EntityValidationException ex) {
            reportErrors(ex.getValidationErrors(), entity, errorReport);
        } catch (DuplicateKeyException ex) {
            reportErrors(ex.getRootCause().getMessage(), entity, errorReport);
        }

        return null;
    }

    /**
     * Persist entity in the data store.
     *
     * @param entity
     *            Entity to be persisted
     * @return Persisted entity
     * @throws EntityValidationException
     *             Validation Exception
     */
    private Entity persist(SimpleEntity entity) throws EntityValidationException {
        if (entity.getEntityId() != null) {

            if (!entityRepository.update(entity.getType(), entity)) {
                // TODO: exception should be replace with some logic.
                throw new RuntimeException("Record was not updated properly.");
            }

            return entity;
        } else {
            return entityRepository.create(entity.getType(), entity.getBody(), entity.getMetaData(), entity.getType());
        }
    }

    private void reportErrors(List<ValidationError> errors, SimpleEntity entity, ErrorReport errorReport) {
        for (ValidationError err : errors) {

            String message = "ERROR: There has been a data validation error when saving an entity" + "\n" +
                             "       Error      " + err.getType().name() + "\n" +
                             "       Entity     " + entity.getType() + "\n" +
                             "       Instance   " + entity.getRecordNumber() + "\n" +
                             "       Field      " + err.getFieldName() + "\n" +
                             "       Value      " + err.getFieldValue() + "\n" +
                             "       Expected   " + Arrays.toString(err.getExpectedTypes()) + "\n";
            errorReport.error(message, this);
        }
    }

    /**
     * Generic error reporting function.
     *
     * @param errorMessage
     *            Error message reported by entity.
     * @param entity
     *            Entity reporting error.
     * @param errorReport
     *            Reference to error report to log error message in.
     */
    private void reportErrors(String errorMessage, SimpleEntity entity, ErrorReport errorReport) {
        String assembledMessage = "Entity (" + entity.getType() + ") reports failure: " + errorMessage;
        errorReport.error(assembledMessage, this);
    }

    protected String getFailureMessage(String code, Object... args) {
        return messageSource.getMessage(code, args, "#?" + code + "?#", null);
    }

    public void setEntityRepository(Repository<Entity> entityRepository) {
        this.entityRepository = entityRepository;
    }

    public MessageSource getMessageSource() {
        return messageSource;
    }

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }
}

@@ -2351,25 +2351,24 @@
 : errors) %7B%0A
-%0A
             
@@ -2388,220 +2388,56 @@
 e = 
-%22ERROR: There has been a data validation error when saving an entity%22 + %22%5Cn%22 +%0A                             %22       Error      %22 + err.getType().name() + %22%5Cn%22 +%0A                             %22       Entity     %22 +
+getFailureMessage(%22DAL_%22 + err.getType().name(),
  ent
@@ -2449,29 +2449,18 @@
 etType()
- + %22%5Cn%22 +%0A   
+,%0A
         
@@ -2475,202 +2475,53 @@
     
-      %22       Instance   %22 + entity.getRecordNumber() + %22%5Cn%22 +%0A                             %22       Field      %22 + err.getFieldName() + %22%5Cn%22 +%0A                             %22       Value      %22 +
+entity.getRecordNumber(), err.getFieldName(),
  err
@@ -2540,21 +2540,10 @@
 ue()
- + %22%5Cn%22 +%0A   
+,%0A
     
@@ -2561,37 +2561,8 @@
     
-       %22       Expected   %22 +
  Arr
@@ -2601,15 +2601,9 @@
 s())
- + %22%5Cn%22
+)
 ;%0A  

revert change on error message