# transcript.py
# YOUR NAME HERE
# skeleton by Lillian Lee (LJL2) and Steve Marschner (SRM2), Feb 9 2014
# DATE YOU COMPLETED THIS HERE

"""Module providing a class and constants for representing transcripts.

"""

# List of valid "base" letter names.
# At this university, everybody is above average!
LETTER_LIST = ['B', 'A']

# List of valid modifiers to base letter grades.
MODIFIER_LIST = ['-','+']

def lettergrade_to_val(lg):
    """Returns: numerical value of letter grade lg.

    The usual numerical scheme is assumed: A+ -> 4.3, A -> 4.0, A- -> 3.7, etc.

    Precondition: lg is a 1 or 2-character string consisting of a "base" letter
    in LETTER_LIST optionally followed by a modifier in MODIFIER_LIST."""

    # if LETTER_LIST or MODIFIER_LIST change, the implementation of
    # this function must change.

    # get value of base letter. Trick: index in LETTER_LIST is shifted from value
    bv = LETTER_LIST.index(lg[0]) + 3
    # Trick with indexing in MODIFIER_LIST to get the modifier value
    return bv + ((MODIFIER_LIST.index(lg[1]) - .5)*.3/.5 if (len(lg) == 2) else 0)


class Titem(object):
    """A Titem is an 'item' on a transcript, like "CS1110 A+"

    Instance variables:
        course [string]: course name.  Always at least 1 character long.

        gradeval [float]: the numerical equivalent of the letter grade.
                          Valid letter grades are 1 or 2 chars long, and consist
                          of a "base" letter in LETTER_LIST optionally followed
                          by a modifier in MODIFIER_LIST.
                          We store values instead of letter grades to facilitate
                          calculations of GPA later.

                          (In "real" life, one would write a function that,
                          when displaying a Titem, would display the letter
                          grade even though the underlying representation is
                          numerical, but we're keeping things simple for this
                          lab.)
    """

    def __init__(self, n, lg):
        """Initializer: A new transcript line with course (name) n, gradeval
           the numerical equivalent of letter grade lg.

           Preconditions: n is a non-empty string.
           lg is a string consisting of a "base" letter in LETTER_LIST
           optionally followed by modifier in MODIFIER_LIST.
           """
        # assert statements that cause an error when preconditions are violated
        assert type(n) == str and type(lg) == str, 'argument type error'
        assert (len(n) >= 1 and  0 < len(lg) <= 2 and lg[0] in LETTER_LIST and
                (len(lg) == 1 or lg[1] in MODIFIER_LIST)), 'argument value error'

        self.course = n
        self.gradeval = lettergrade_to_val(lg)


def raise_grade(ti):
    """"Raise gradeval of transcript line ti by a non-noticeable amount.

    We imagine that this function is written by some mischievous entity with
    access to the university registrar's records.  The idea is that raising a
    grade of B- to a B, or B to a B+, could escape notice. But, someone might
    notice a change of B+ to A, since that's very "visible".

    So, ti's gradeval is raised by .3 unless the gradeval already corresponds to
    a "plus" grade like B+, in which case the gradeval is not changed.

    Preconditions: ti is a Titem.
    """
    # value of the base letter grade, e.g., 4 (or 4.0) for a 4.3
    bval = int(ti.gradeval)

    # part after decimal point in raised grade, e.g., 3 (or 3.0) for a 4.3
    newdec = min(int((ti.gradeval + .3)*10) % 10, 3)

    # get result by add the two values together, after shifting  newdec  one
    # decimal place
    newval = bval + round(newdec/10.0, 1)
    ti.gradeval = newval