ble|ArrayAccess  $spec
     * @return FormInterface
     */
    public function configureForm(FormInterface $form, $spec)
    {
        $spec = $this->validateSpecification($spec, __METHOD__);
        $form = $this->configureFieldset($form, $spec);

        if (isset($spec['input_filter'])) {
            $this->prepareAndInjectInputFilter($spec['input_filter'], $form, __METHOD__);
        }

        if (isset($spec['validation_group'])) {
            $this->prepareAndInjectValidationGroup($spec['validation_group'], $form, __METHOD__);
        }

        return $form;
    }

    /**
     * Validate a provided specification
     *
     * Ensures we have an array, Traversable, or ArrayAccess object, and returns it.
     *
     * @param  array|Traversable|ArrayAccess $spec
     * @param  string $method Method invoking the validator
     * @return array|ArrayAccess
     * @throws Exception\InvalidArgumentException for invalid $spec
     */
    protected function validateSpecification($spec, $method)
    {
        if (is_array($spec)) {
            return $spec;
        }

        if ($spec instanceof Traversable) {
            $spec = ArrayUtils::iteratorToArray($spec);
            return $spec;
        }

        if (!$spec instanceof ArrayAccess) {
            throw new Exception\InvalidArgumentException(sprintf(
                '%s expects an array, or object implementing Traversable or ArrayAccess; received "%s"',
                $method,
                (is_object($spec) ? get_class($spec) : gettype($spec))
            ));
        }

        return $spec;
    }

    /**
     * Takes a list of element specifications, creates the elements, and injects them into the provided fieldset
     *
     * @param  array|Traversable|ArrayAccess $elements
     * @param  FieldsetInterface $fieldset
     * @param  string $method Method invoking this one (for exception messages)
     * @return void
     */
    protected function prepareAndInjectElements($elements, FieldsetInterface $fieldset, $method)
    {
        $elements = $this->validateSpecification($elements, $method);

        foreach ($elements as $elementSpecification) {
            $flags = isset($elementSpecification['flags']) ? $elementSpecification['flags'] : array();
            $spec  = isset($elementSpecification['spec'])  ? $elementSpecification['spec']  : array();

            if (!isset($spec['type'])) {
                $spec['type'] = 'Zend\Form\Element';
            }

            $element = $this->create($spec);
            $fieldset->add($element, $flags);
        }
    }

    /**
     * Takes a list of fieldset specifications, creates the fieldsets, and injects them into the master fieldset
     *
     * @param  array|Traversable|ArrayAccess $fieldsets
     * @param  FieldsetInterface $masterFieldset
     * @param  string $method Method invoking this one (for exception messages)
     * @return void
     */
    public function prepareAndInjectFieldsets($fieldsets, FieldsetInterface $masterFieldset, $method)
    {
        $fieldsets = $this->validateSpecification($fieldsets, $method);

        foreach ($fieldsets as $fieldsetSpecification) {
            $flags = isset($fieldsetSpecification['flags']) ? $fieldsetSpecification['flags'] : array();
            $spec  = isset($fieldsetSpecification['spec'])  ? $fieldsetSpecification['spec']  : array();

            $fieldset = $this->createFieldset($spec);
            $masterFieldset->add($fieldset, $flags);
        }
    }

    /**
     * Prepare and inject an object
     *
     * Takes a string indicating a class name, instantiates the class
     * by that name, and injects the class instance as the bound object.
     *
     * @param  string           $objectName
     * @param  FieldsetInterface $fieldset
     * @param  string           $method
     * @throws Exception\DomainException
     * @return void
     */
    protected function prepareAndInjectObject($objectName, FieldsetInterface $fieldset, $method)
    {
        if (!is_string($objectName)) {
            throw new Exception\DomainException(sprintf(
                '%s expects string class name; received "%s"',
                $method,
                (is_object($objectName) ? get_class($objectName) : gettype($objectName))
            ));
        }

        if (!class_exists($objectName)) {
            throw new Exception\DomainException(sprintf(
                '%s expects string class name to be a valid class name; received "%s"',
                $method,
                $objectName
            ));
        }

        $fieldset->setObject(new $objectName);
    }

    /**
     * Prepare and inject a named hydrator
     *
     * Takes a string indicating a hydrator class name (or a concrete instance), try first to instantiates the class
     * by pulling it from service manager, and injects the hydrator instance into the form.
     *
     * @param  string|array|Hydrator\HydratorInterface $hydratorOrName
     * @param  FieldsetInterface                       $fieldset
     * @param  string                                  $method
     * @return void
     * @throws Exception\DomainException If $hydratorOrName is not a string, does not resolve to a known class, or
     *                                   the class does not implement Hydrator\HydratorInterface
     */
    protected function prepareAndInjectHydrator($hydratorOrName, FieldsetInterface $fieldset, $method)
    {
        if (is_object($hydratorOrName) && $hydratorOrName instanceof Hydrator\HydratorInterface) {
            $fieldset->setHydrator($hydratorOrName);
            return;
        }

        if (is_array($hydratorOrName)) {
            if (!isset($hydratorOrName['type'])) {
                throw new Exception\DomainException(sprintf(
                    '%s expects array specification to have a type value',
                    $method
                ));
            }
            $hydratorOptions = (isset($hydratorOrName['options'])) ? $hydratorOrName['options'] : array();
            $hydratorOrName = $hydratorOrName['type'];
        } else {
            $hydratorOptions = array();
        }

        if (is_string($hydratorOrName)) {
            $hydrator = $this->getHydratorFromName($hydratorOrName);
        }

        if (!$hydrator instanceof Hydrator\HydratorInterface) {
            throw new Exception\DomainException(sprintf(
                '%s expects a valid implementation of Zend\Form\Hydrator\HydratorInterface; received "%s"',
                $method,
                $hydratorOrName
            ));
        }

        if (!empty($hydratorOptions) && $hydrator instanceof Hydrator\HydratorOptionsInterface) {
            $hydrator->setOptions($hydratorOptions);
        }

        $fieldset->setHydrator($hydrator);
    }

    /**
     * Prepare an input filter instance and inject in the provided form
     *
     * If the input filter specified is a string, assumes it is a class name,
     * and attempts to instantiate it. If the class does not exist, or does
     * not extend InputFilterInterface, an exception is raised.
     *
     * Otherwise, $spec is passed on to the attached InputFilter Factory
     * instance in order to create the input filter.
     *
     * @param  string|array|Traversable $spec
     * @param  FormInterface $form
     * @param  string $method
     * @return void
     * @throws Exception\DomainException for unknown InputFilter class or invalid InputFilter instance
     */
    protected function prepareAndInjectInputFilter($spec, FormInterface $form, $method)
    {
        if (is_string($spec)) {
            if (!class_exists($spec)) {
                throw new Exception\DomainException(sprintf(
                    '%s expects string input filter names to be valid class names; received "%s"',
                    $method,
                    $spec
                ));
            }
            $filter = new $spec;
            if (!$filter instanceof InputFilterInterface) {
                throw new Exception\DomainException(sprintf(
                    '%s expects a valid implementation of Zend\InputFilter\InputFilterInterface; received "%s"',
                    $method,
                    $spec
                ));
            }
            $form->setInputFilter($filter);
            return;
        }

        $factory = $this->getInputFilterFactory();
        $filter  = $factory->createInputFilter($spec);
        $form->setInputFilter($filter);
    }

    /**
     * Prepare a validation group and inject in the provided form
     *
     * Takes an array of elements names
     *
     * @param  string|array|Traversable $spec
     * @param  FormInterface $form
     * @param  string $method
     * @return void
     * @throws Exception\DomainException if validation group given is not an array
     */
    protected function prepareAndInjectValidationGroup($spec, FormInterface $form, $method)
    {
        if (!is_array($spec)) {
            if (!class_exists($spec)) {
                throw new Exception\DomainException(sprintf(
                    '%s expects an array for validation group; received "%s"',
                    $method,
                    $spec
                ));
            }
        }

        $form->setValidationGroup($spec);
    }

    /**
     * Try to pull hydrator from service manager, or instantiates it from its name
     *
     * @param  string $hydratorName
     * @return mixed
     * @throws Exception\DomainException
     */
    protected function getHydratorFromName($hydratorName)
    {
        $serviceLocator = $this->getFormElementManager()->getServiceLocator();

        if ($serviceLocator && $serviceLocator->has($hydratorName)) {
            return $serviceLocator->get($hydratorName);
        }

        if (!class_exists($hydratorName)) {
            throw new Exception\DomainException(sprintf(
                'Expects string hydrator name to be a valid class name; received "%s"',
                $hydratorName
            ));
        }

        $hydrator = new $hydratorName;
        return $hydrator;
    }
}