package uk.gov.register.serialization;

import com.google.common.collect.Iterators;
import uk.gov.register.core.HashingAlgorithm;
import uk.gov.register.core.Register;
import uk.gov.register.util.HashValue;
import uk.gov.register.views.RegisterProof;

import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class RSFCreator {

    private final String EMPTY_ROOT_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
    private final RegisterProof emptyRegisterProof;

    private Map<Class, RegisterCommandMapper> registeredMappers;

    public RSFCreator() {
        this.registeredMappers = new HashMap<>();
        this.emptyRegisterProof = new RegisterProof(new HashValue(HashingAlgorithm.SHA256, EMPTY_ROOT_HASH));
    }

    public RegisterSerialisationFormat create(Register register) {
        try {
            Iterator<?> iterators = Iterators.concat(
                    Iterators.singletonIterator(emptyRegisterProof),
                    register.getItemIterator(),
                    register.getEntryIterator(),
                    Iterators.singletonIterator(register.getRegisterProof()));

            Iterator<RegisterCommand> commands = Iterators.transform(iterators, obj -> (RegisterCommand) registeredMappers.get(obj.getClass()).apply(obj));
            return new RegisterSerialisationFormat(commands);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    public RegisterSerialisationFormat create(Register register, int totalEntries1, int totalEntries2) {
        Iterator<?> iterators;

        if (totalEntries1 == totalEntries2) {
            iterators = Iterators.singletonIterator(register.getRegisterProof(totalEntries1));
        } else {

            RegisterProof previousRegisterProof = totalEntries1 == 0 ? emptyRegisterProof : register.getRegisterProof(totalEntries1);
            RegisterProof nextRegisterProof = register.getRegisterProof(totalEntries2);

            iterators = Iterators.concat(
                    Iterators.singletonIterator(previousRegisterProof),
                    register.getItemIterator(totalEntries1, totalEntries2),
                    register.getEntryIterator(totalEntries1, totalEntries2),
                    Iterators.singletonIterator(nextRegisterProof));
        }
        Iterator<RegisterCommand> commands = Iterators.transform(iterators, obj -> (RegisterCommand) registeredMappers.get(obj.getClass()).apply(obj));
        return new RegisterSerialisationFormat(commands);
    }

    public void register(RegisterCommandMapper commandMapper) {
        registeredMappers.put(commandMapper.getMapClass(), commandMapper);
    }
}

@@ -1304,37 +1304,25 @@
 ommand) 
-registered
+get
 Mapper
-s.get
 (obj.get
@@ -2515,29 +2515,17 @@
 nd) 
-registered
+get
 Mapper
-s.get
 (obj
@@ -2675,24 +2675,24 @@
 ndMapper) %7B%0A
-
         regi
@@ -2759,11 +2759,312 @@
 );%0A    %7D
+%0A%0A    private RegisterCommandMapper getMapper(Class objClass) %7B%0A        if (registeredMappers.containsKey(objClass)) %7B%0A            return registeredMappers.get(objClass);%0A        %7D else %7B%0A            throw new RuntimeException(%22Mapper not registered for class: %22 + objClass.getName());%0A        %7D%0A    %7D
 %0A%7D%0A

Handle unregistered types of mappers in RSFCreator