/*
 * Copyright (c) 2015 Mockito contributors
 * This program is made available under the terms of the MIT License.
 */
package org.mockito.internal.util.reflection;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Sort fields in an order suitable for injection, by name with superclasses
 * moved after their subclasses.
 */
public class SuperTypesLastSorter {

    private SuperTypesLastSorter() {
    }

    /**
     * Return a new collection with the fields sorted first by name,
     * then with any fields moved after their supertypes.
     */
    public static List<Field> sortSuperTypesLast(Collection<? extends Field> unsortedFields) {
        List<Field> fields = new ArrayList<Field>(unsortedFields);

        Collections.sort(fields, compareFieldsByName);

        int i = 0;

        while (i < fields.size() - 1) {
            Field f = fields.get(i);
            Class<?> ft = f.getType();
            int newPos = i;
            for (int j = i + 1; j < fields.size(); j++) {
                Class<?> t = fields.get(j).getType();

                if (ft != t && ft.isAssignableFrom(t)) {
                    newPos = j;
                }
            }

            if (newPos == i) {
                i++;
            } else {
                fields.remove(i);
                fields.add(newPos, f);
            }
        }

        return fields;
    }


    private static final Comparator<Field> compareFieldsByName = new Comparator<Field>() {
        @Override
        public int compare(Field o1, Field o2) {
            return o1.getName().compareTo(o2.getName());
        }
    };
}
