package org.schoellerfamily.gedbrowser.api.crud;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.schoellerfamily.gedbrowser.api.datamodel.ApiAttribute;
import org.schoellerfamily.gedbrowser.api.datamodel.ApiPerson;
import org.schoellerfamily.gedbrowser.datamodel.Person;
import org.schoellerfamily.gedbrowser.persistence.domain.PersonDocument;
import org.schoellerfamily.gedbrowser.persistence.mongo.gedconvert.GedObjectToGedDocumentMongoConverter;
import org.schoellerfamily.gedbrowser.persistence.mongo.loader.GedDocumentFileLoader;
import org.schoellerfamily.gedbrowser.persistence.mongo.repository.RepositoryManagerMongo;
import org.schoellerfamily.gedbrowser.persistence.repository.FindableDocument;

/**
 * @author Dick Schoeller
 */
public class PersonCrud
    extends OperationsEnabler<Person, PersonDocument>
    implements CrudOperations<Person, PersonDocument, ApiPerson> {
    /** Logger. */
    private final transient Log logger = LogFactory.getLog(getClass());

    /**
     * @param loader the file loader that we will use
     * @param toDocConverter the document converter
     * @param repositoryManager the repository manager
     */
    public PersonCrud(final GedDocumentFileLoader loader,
            final GedObjectToGedDocumentMongoConverter toDocConverter,
            final RepositoryManagerMongo repositoryManager) {
        super(loader, toDocConverter, repositoryManager);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public FindableDocument<Person, PersonDocument> getRepository() {
        return getRepositoryManager().getPersonDocumentRepository();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Class<Person> getGedClass() {
        return Person.class;
    }

    /**
     * Create a new person from the passed object.
     *
     * @param db the name of the db to access
     * @param person the data for the person
     * @return the person as created
     */
    public ApiPerson createPerson(final String db, final ApiPerson person) {
        logger.info("Entering create person in db: " + db);
        return create(readRoot(db), person, (i, id) -> new ApiPerson(i, id));
    }

    /**
     * @param db the name of the db to access
     * @return the list of persons
     */
    public List<ApiPerson> readPersons(final String db) {
        logger.info("Entering read /dbs/" + db + "/persons");
        return getD2dm().convert(read(db));
    }

    /**
     * @param db the name of the db to access
     * @param id the ID of the person
     * @return the person
     */
    public ApiPerson readPerson(final String db, final String id) {
        logger.info("Entering read /dbs/" + db + "/persons/" + id);
        return getD2dm().convert(read(db, id));
    }

    /**
     * @param db the name of the db to access
     * @param id the id of the person to update
     * @param person the data for the person
     * @return the person as created
     */
    public ApiPerson updatePerson(final String db, final String id,
            final ApiPerson person) {
        logger.info("Entering update person: " + id + " in db: " + db);
        if (!id.equals(person.getString())) {
            return null;
        }
        person.change();
        return update(readRoot(db), person);
    }

    /**
     * @param db the name of the db to access
     * @param id the ID of the person
     * @return the deleted person object
     */
    public ApiPerson deletePerson(final String db, final String id) {
        logger.info("Entering delete person: " + id + " from db: " + db);
        ApiPerson person = readPerson(db, id);
        person = unlinkFamc(db, person);
        person = unlinkFams(db, person);
        return delete(readRoot(db), id);
    }

    /**
     * @param db the dataset
     * @param person the person to modify
     * @return the modified person
     */
    private ApiPerson unlinkFamc(final String db, ApiPerson person) {
        final List<String> famcList = new ArrayList<>();
        for (final ApiAttribute a : person.getFamc()) {
            famcList.add(a.getString());
        }
        for (final String famc : famcList) {
            person = childCrud().unlinkChild(db, famc, person.getString());
        }
        return person;
    }

    /**
     * @param db the dataset
     * @param person the person to modify
     * @return the modified person
     */
    private ApiPerson unlinkFams(final String db, ApiPerson person) {
        final List<String> famsList = new ArrayList<>();
        for (final ApiAttribute a : person.getFams()) {
            famsList.add(a.getString());
        }
        for (final String fams : famsList) {
            person = spouseCrud().unlinkSpouseInFamily(db, fams, person.getString());
        }
        return person;
    }

    /**
     * @return a new child CRUD object
     */
    private ChildCrud childCrud() {
        return new ChildCrud(getLoader(), getConverter(),
                getRepositoryManager());
    }

    /**
     * @return a new spouse CRUD object
     */
    private SpouseCrud spouseCrud() {
        return new SpouseCrud(getLoader(), getConverter(),
                getRepositoryManager());
    }
}

@@ -3991,32 +3991,38 @@
 final String db,
+ final
  ApiPerson perso
@@ -4075,32 +4075,70 @@
  ArrayList%3C%3E();%0A
+        ApiPerson newPerson = person;%0A
         for (fin
@@ -4149,33 +4149,36 @@
 piAttribute a : 
-p
+newP
 erson.getFamc())
@@ -4280,33 +4280,36 @@
 ) %7B%0A            
-p
+newP
 erson = childCru
@@ -4324,16 +4324,37 @@
 nkChild(
+%0A                    
 db, famc
@@ -4355,17 +4355,20 @@
 , famc, 
-p
+newP
 erson.ge
@@ -4396,33 +4396,36 @@
 %0A        return 
-p
+newP
 erson;%0A    %7D%0A%0A  
@@ -4593,16 +4593,22 @@
 ring db,
+ final
  ApiPers
@@ -4669,32 +4669,70 @@
  ArrayList%3C%3E();%0A
+        ApiPerson newPerson = person;%0A
         for (fin
@@ -4751,17 +4751,20 @@
 ute a : 
-p
+newP
 erson.ge
@@ -4874,33 +4874,36 @@
 ) %7B%0A            
-p
+newP
 erson = spouseCr
@@ -4928,16 +4928,37 @@
 nFamily(
+%0A                    
 db, fams
@@ -4959,17 +4959,20 @@
 , fams, 
-p
+newP
 erson.ge
@@ -5008,17 +5008,20 @@
  return 
-p
+newP
 erson;%0A 

fix codeclimate issues