import os
from os.path import join
import yaml
from toybag import enumerate
from sys import exit

class IInfoAdder:
    """I define an interface to add metadata to VorbisInfoLists."""
    def __init__(self):
        """Take in all metadata location information that you need here."""
        pass

    def add(self, vil=None):
        """Decorate the VorbisInfoList vil here."""

class YamlInfoAdder(IInfoAdder):
    def __init__(self, infoDir):
        IInfoAdder.__init__(self)
        self.infoDir = infoDir
        self._validateInfoDir()

    def _validateInfoDir(self):
        assert os.path.isdir(self.infoDir)

    def _addGlobalComments(self, vil):
        "vil is a VorbisInfoList that already has objects in it"
        try:
            comments = yaml.loadFile(join(self.infoDir, 'globalcomments.txt'))
            # okay, we've got to treat {k: v} and {k: [v, w]} the same.
            # pile the comments into a dict that we control and then add
            # from there.
            fakemd = list(comments)[0]
            for k, vorvs in fakemd.items():
                if isinstance(vorvs, list):
                    for v in vorvs:
                        for vi in vil:
                            vi.comments.insert((k, v))
                else:
                    for vi in vil:
                        vi.comments.insert((k, vorvs))
           
        except IOError:
            print "No globalcomments.txt file found."

    def _addComments(self, vil):
        try:
            comments = list(yaml.loadFile(join(self.infoDir,
                                               'comments.txt')))[0]
            for (inComment, vi), i in enumerate(zip(comments, vil), 1):
                vi.comments.merge(inComment)
                vi.comments.insert(('tracknumber', str(i)))
        except IOError:
            print "No comments.txt file found."

    def _addGlobalPragmas(self, vil):
        try:
            pragmas = yaml.loadFile(join(self.infoDir, 'globalpragmas.txt'))
            for pragma in pragmas:
                vil.pragmas.update(pragma)
        except IOError:
            print "No globalpragmas.txt file found."
        

    def _addPragmas(self, vil):
        try:
            pragmasIterator = yaml.loadFile(join(self.infoDir, 'pragmas.txt'))
            pragmas = list(pragmasIterator)[0] # XXX: THIS IS BLACK MAGIC
            print "the raw pragmas", pragmas
            for tracknum, pragma in pragmas.items():
                print "TRACK: %s, PRAGMA: %s", (tracknum, pragma)
                index = int(tracknum) - 1 # lists are 0-indexed, CDs, 1-
                vil[index].pragmas.update(pragma)
        except IOError:
            print "No pragmas.txt file found."

    def _applyOffset(self, vil):
        """Changes the value of TRACKNUMBER so it starts from another value.

        This function scans through vil's pragmas and renumbers
        TRACKNUMBERs starting from the value of the 'offset' pragma.
        
        Why:
        Some CDs (like game CDs) have a data track for track 1, and when
        they're ripped, will have track numbers starting from 2. Since sonice
        assumes that the files in its 'wav' dir are numbered 1-N, these CDs
        break that assumption. Since the benefits of not having to rename
        wav files are really frigging nice, this hack is in place to scan the
        VorbisInfoList's pragmas attribute and renumber accordingly.
        """
        newindex = 1
        if 'beginning-tracknumber' in vil.pragmas:
            try: # funky try/except block, clean up later
                newindex = int(vil.pragmas['beginning-tracknumber'])
            except:
                print "caught something"
                raise
            assert isinstance(newindex, int)
            for vi in vil:
                vi.comments.get('tracknumber')[0] = str(newindex)
                newindex += 1
            
            
            
    def add(self, vil):
        assert len(vil) > 0
        self._addGlobalComments(vil)
        self._addComments(vil)
        self._addGlobalPragmas(vil)
        self._addPragmas(vil)
        self._applyOffset(vil)
