#
# $Source: /home/blais/repos/cvsroot/arubomu/lib/python/arubomu/user.py,v $
# $Id: user.py,v 1.6 2005/05/08 18:14:24 blais Exp $
#

"""Data structures and parser for arubomu 'user' format.

This modules provides some format independent data structures and conversion
from/to XML, and implements some assumptions in the data structures conversion.

"""

__version__ = "$Revision: 1.6 $"
__author__ = "Martin Blais <blais@furius.ca>"

__version__ = "$Revision: 1.6 $"
__author__ = "Martin Blais <blais@furius.ca>"


import sys, os
import re
from datetime import date

from elementtree import ElementTree

from arubomu.common import SimpleAttr


nodre = re.compile('[0-9]+')


def load(f):
    """Reads an XML file and parses as an album file."""

    tree = ElementTree.parse(f)
    root = tree.getroot()
    if root.tag == 'user':
        album = User().fromxml(root)
    else:
        albumel = root.find('user')
        album = User().fromxml(albumel)
    return album



class User(SimpleAttr):

    """Class that represents an album."""

    elems = ['category', 'type', 'source', 'encoder', 'date',
             'encoding', 'comments']

    def __init__(self):
        SimpleAttr.__init__(self, self.elems)

        # list of Track objects.
        self.missing_tracks, self.missing_discs = [], []
        self.extra_tracks, self.extra_discs = [], []

        # list of TrackDJ objects
        self.dj = []

    def init_basic_empty(self):
        """Initialize typical common fields with common or empty values.
        This is used to prepare the user to be filled/modified by hand."""

        self.category = 'unknown'
        self.type = 'encoded'
        self.source = 'download'
        self.encoder = 'unknown'
        self.date = date.today()

    def __repr__(self):
        r = SimpleAttr.__repr__(self, self.elems)
        for m in self.missing_tracks:
            r += repr(m)
        for m in self.missing_discs:
            r += repr(m)
        for m in self.extra_tracks:
            r += repr(m)
        for m in self.extra_discs:
            r += repr(m)
        for m in self.dj:
            r += repr(m)
        return r

    def fromxml(self, xel):
        assert xel.tag == 'user'
        SimpleAttr.fromxml(self, xel, [], self.elems)

        assert self.type in [None, 'copy', 'orig', 'encoded']

        mel = xel.find('missing')
        if mel != None:
            for el in mel.findall('track'):
                self.missing_tracks.append(Track().fromxml(el))
            for el in mel.findall('disc'):
                self.missing_discs.append(DiscRef().fromxml(el))

        mel = xel.find('extra')
        if mel != None:
            for el in mel.findall('track'):
                self.extra_tracks.append(Track().fromxml(el))
            for el in mel.findall('disc'):
                self.extra_discs.append(DiscRef().fromxml(el))

        mel = xel.find('dj')
        if mel != None:
            for el in mel.findall('track'):
                self.dj.append(TrackDJ().fromxml(el))

        return self

    def toxml(self):
        xel = ElementTree.Element('user')
        SimpleAttr.toxml(self, xel, [], self.elems)

        if self.missing_tracks or self.missing_discs:
            pel = ElementTree.SubElement(xel, 'missing')
            for disc in self.missing_discs:
                pel.append(disc.toxml())
            for track in self.missing_tracks:
                pel.append(track.toxml())

        if self.extra_tracks or self.extra_discs:
            pel = ElementTree.SubElement(xel, 'extra')
            for disc in self.extra_discs:
                pel.append(disc.toxml())
            for track in self.extra_tracks:
                pel.append(track.toxml())

        if self.dj:
            pel = ElementTree.SubElement(xel, 'dj')
            for track in self.dj:
                pel.append(track.toxml())

        return xel


class DiscRef(SimpleAttr):

    """Class that represents a simple disc reference."""

    attribs = ['no']

    def __init__(self):
        SimpleAttr.__init__(self, self.attribs)

    def __repr__(self):
        r = SimpleAttr.__repr__(self, self.attribs)
        return r

    def fromxml(self, xel):
        assert xel.tag == 'disc'
        SimpleAttr.fromxml(self, xel, self.attribs, [])
        if self.no: self.no = int(self.no)
        return self

    def toxml(self):
        xel = ElementTree.Element('disc')
        SimpleAttr.toxml(self, xel, self.attribs, [])
        return xel


class Track(SimpleAttr):

    """Class that represents a simple track reference."""

    attribs = ['no', 'discno']

    def __init__(self):
        SimpleAttr.__init__(self, self.attribs)

    def __repr__(self):
        r = SimpleAttr.__repr__(self, self.attribs)
        return r

    def fromxml(self, xel):
        assert xel.tag == 'track'
        SimpleAttr.fromxml(self, xel, self.attribs, [])
        if self.no: self.no = int(self.no)
        if self.discno: self.discno = int(self.discno)
        return self

    def toxml(self):
        xel = ElementTree.Element('track')
        SimpleAttr.toxml(self, xel, self.attribs, [])
        return xel


class TrackDJ(SimpleAttr):

    """Class that represents a DJ track reference."""

    attribs = ['no', 'discno', 'bpm']

    def __init__(self):
        SimpleAttr.__init__(self, self.attribs)

        self.comment = None

    def __repr__(self):
        r = SimpleAttr.__repr__(self, self.attribs)
        return r

    def fromxml(self, xel):
        assert xel.tag == 'track'
        SimpleAttr.fromxml(self, xel, self.attribs, [])
        if self.no: self.no = int(self.no)
        if self.discno: self.discno = int(self.discno)

        if xel.text != None:
            self.comment = xel.text

        return self

    def toxml(self):
        xel = ElementTree.Element('track')
        SimpleAttr.toxml(self, xel, self.attribs, [])

        if self.comment != None:
            xel.text = self.comment

        return xel
