"""This module implements pre-questions' progressions.

Pre questions are chord progressions or notes played before the question is
played, so to affirmate the sound of the question's key.

For example a common cadence is chords I-IV-V-I from the diatonic scale, which
in a key of `C` is `CM-FM-GM-CM` and in a key of `A` is `AM-DM-EM-AM`.

Pre-question methods should be decorated with `register_prequestion_method`
decorator, so that they will be registered as a valid pre-question method.
"""

from .sequence import Sequence

from functools import wraps

PREQUESTION_METHODS = {}
# http://stackoverflow.com/questions/5910703/howto-get-all-methods-of-a-pyt\
# hon-class-with-given-decorator
# http://stackoverflow.com/questions/5707589/calling-functions-by-array-ind\
# ex-in-python/5707605#5707605


def register_prequestion_method(f, *args, **kwargs):
    """Decorator for prequestion method functions.

    Functions decorated with this decorator will be registered in the
    `PREQUESTION_METHODS` global dict.
    """

    @wraps(f)
    def decorator(*args, **kwargs):
        return f(*args, **kwargs)

    PREQUESTION_METHODS.update({f.__name__: f})

    return decorator


class PreQuestion:

    def __init__(self, method, question):
        """This class implements methods for different types of pre-question
        progressions.

        Args:
            method (str): The method used in the pre question.
            question (obj): Question object from which to generate the
            pre-question sequence.
        """

        self.METHOD = PREQUESTION_METHODS[method]
        self.question = question

    def __call__(self, *args, **kwargs):
        """Calls the resolution method and pass arguments to it.

        Returns a `birdears.Sequence` object with the pre-question generated by
        the method.
        """
        return self.METHOD(question=self.question, *args, **kwargs)


@register_prequestion_method
def none(question, *args, **kwargs):
    """Pre-question method that return an empty sequence with no delay.
    Args:
        question (obj): Question object from which to generate the
            pre-question sequence. (this is provided by the `Resolution` class
            when it is `__call__`ed)
    """
    return Sequence(elements=[], duration=0, delay=0, pos_delay=0)


@register_prequestion_method
def tonic_only(question, *args, **kwargs):
    """Pre-question method that only play's the question tonic note before the
    question.

    Args:
        question (object): Question object from which to generate the
            pre-question sequence. (this is provided by the `Resolution` class
            when it is `__call__`ed)
    """

    tonic_pitch = question.tonic_pitch

    duration = question.durations['preq']['duration']
    delay = question.durations['preq']['delay']
    pos_delay = question.durations['preq']['pos_delay']

    sequence = Sequence(elements=[tonic_pitch], duration=duration,
                        delay=delay, pos_delay=pos_delay)

    return sequence


@register_prequestion_method
def progression_i_iv_v_i(question, *args, **kwargs):
    """Pre-question method that play's a chord progression with triad chords
    built on the grades I, IV, V the I of the question key.

    Args:
        question (obj): Question object from which to generate the
            pre-question sequence. (this is provided by the `Resolution` class
            when it is `__call__`ed)
    """

    # tonic_pitch = question.tonic_pitch
    tonic_str = question.tonic_str
    mode = question.mode

    duration = question.durations['preq']['duration']
    delay = question.durations['preq']['delay']
    pos_delay = question.durations['preq']['pos_delay']

    degrees = [1, 4, 5, 1]

    sequence = Sequence(duration=duration, delay=delay,
                        pos_delay=pos_delay)

    sequence.make_chord_progression(tonic=tonic_str, mode=mode,
                                    degrees=degrees)

    return sequence
