import itertools


def enumerate_sqs(structure, subl_model, scale_volume=True, skip_on_failure=False):
    """
    Return a list of all of the concrete Structure objects from an abstract Structure and concrete sublattice model.
    Parameters
    ----------
    structure : AbstractSQS
        SQS object. Must be abstract.
    subl_model : [[str]]
        List of strings of species names, in the style of ESPEI `input.json`. This sublattice model
        can be of higher dimension than the SQS, e.g. a [["Al", "Fe", "Ni"]] for a fcc 75/25 binary SQS
        will generate the following Structures:
        Al0.75Fe0.25, Al0.75Ni0.25      Fe0.75Al0.25, Fe0.75Ni0.25      Ni0.75Al0.25, Ni0.75Fe0.25
        *Note that the ordering of species the sublattice model does not matter!*
    scale_volume : bool
        If True, scales the volume of the cell so the ions have at least their minimum atomic radii between them.
    skip_on_failure : bool
        If True, will skip if the sublattice model is lower order and return [] instead of raising

    Returns
    -------
    [PRLStructure]
        List of all concrete PRLStructure objects that can be created from the sublattice model.
    """
    if len(subl_model) != len(structure.sublattice_model):
        raise ValueError('Passed sublattice model ({}) does not agree with the passed structure ({})'.format(subl_model, structure.sublattice_model))
    possible_subls = []
    for subl, abstract_subl in zip(subl_model, structure.sublattice_model):
        subls = itertools.product(subl, repeat=len(abstract_subl))
        possible_subls.append(subls)
    unique_subl_models = itertools.product(*possible_subls)

    # create a list of unique concrete structures with the generated sublattice models
    unique_sqs = []
    unique_configurations_occupancies = []
    for model in unique_subl_models:
        proposed_sqs = structure.get_concrete_sqs(model, scale_volume)
        proposed_config_occupancy = (proposed_sqs.sublattice_configuration, proposed_sqs.sublattice_occupancies)
        if proposed_config_occupancy not in unique_configurations_occupancies:
            unique_configurations_occupancies.append(proposed_config_occupancy)
            unique_sqs.append(proposed_sqs)
    return unique_sqs