# Path: simfile/_private/generic.py
# E = TypeVar('E')
# 
# class ListWithRepr(UserList, MutableSequence[E]):
#     """
#     Subclass of UserList with type hints and some overrides for convenience.
#     """
#     def __repr__(self) -> str:
#         return '%s(%s)' % (self.__class__.__name__, super().__repr__())
# 
# Path: simfile/_private/property.py
# def item_property(name, alias=None):
#     
#     # Decide whether to use the property's alias instead of its primary name
#     def _name_or_alias(self):
#         if name not in self and alias and alias in self:
#             return alias
#         else:
#             return name
# 
#     @property
#     def item_property(self: MutableMapping[str, str]) -> Optional[str]:
#         return self.get(_name_or_alias(self))
# 
#     @item_property.setter
#     def item_property(self: MutableMapping[str, str], value: str) -> None:
#         self[_name_or_alias(self)] = value
#     
#     @item_property.deleter
#     def item_property(self: MutableMapping[str, str]) -> None:
#         del self[_name_or_alias(self)]
# 
#     return item_property
# 
# Path: simfile/_private/serializable.py
# class Serializable(metaclass=ABCMeta):
# 
#     @abstractmethod
#     def serialize(self, file: TextIO) -> None:
#         """
#         Write the object to provided text file object as MSD.
#         """
#         pass
#     
#     def __str__(self) -> str:
#         """
#         Convert the object to an MSD string.
#         """
#         serialized = StringIO()
#         self.serialize(serialized)
#         return serialized.getvalue()


from abc import ABCMeta, abstractclassmethod, abstractmethod
from collections import OrderedDict
from typing import Iterator, Optional, TextIO, Tuple, Union
from msdparser import parse_msd
from ._private.generic import E, ListWithRepr
from ._private.property import item_property
from ._private.serializable import Serializable
    Additionally, properties recognized by the current stable version
    of StepMania are exposed through lower-case properties on the
    object for easy (and implicitly spell-checked) access. The
    following known properties are defined:

    * Metadata: `title`, `subtitle`, `artist`, `titletranslit`,
      `subtitletranslit`, `artisttranslit`, `genre`, `credit`,
      `samplestart`, `samplelength`, `selectable`, `instrumenttrack`,
      `timesignatures`
    * File paths: `banner`, `background`, `lyricspath`, `cdtitle`,
      `music`
    * Gameplay events: `bgchanges`, `fgchanges`, `keysounds`, `attacks`,
      `tickcounts`
    * Timing data: `offset`, `bpms`, `stops`, `delays`

    If a desired simfile property isn't in this list, it can still be
    accessed as a dict item.

    By default, the underlying parser will throw an exception if it
    finds any stray text between parameters. This behavior can be
    overridden by setting `strict` to False in the constructor.
    """
    title = item_property('TITLE')
    subtitle = item_property('SUBTITLE')
    artist = item_property('ARTIST')
    titletranslit = item_property('TITLETRANSLIT')
    subtitletranslit = item_property('SUBTITLETRANSLIT')
    artisttranslit = item_property('ARTISTTRANSLIT')
    genre = item_property('GENRE')
    credit = item_property('CREDIT')

# Path: simfile/_private/generic.py
# E = TypeVar('E')
# 
# class ListWithRepr(UserList, MutableSequence[E]):
#     """
#     Subclass of UserList with type hints and some overrides for convenience.
#     """
#     def __repr__(self) -> str:
#         return '%s(%s)' % (self.__class__.__name__, super().__repr__())
# 
# Path: simfile/_private/property.py
# def item_property(name, alias=None):
#     
#     # Decide whether to use the property's alias instead of its primary name
#     def _name_or_alias(self):
#         if name not in self and alias and alias in self:
#             return alias
#         else:
#             return name
# 
#     @property
#     def item_property(self: MutableMapping[str, str]) -> Optional[str]:
#         return self.get(_name_or_alias(self))
# 
#     @item_property.setter
#     def item_property(self: MutableMapping[str, str], value: str) -> None:
#         self[_name_or_alias(self)] = value
#     
#     @item_property.deleter
#     def item_property(self: MutableMapping[str, str]) -> None:
#         del self[_name_or_alias(self)]
# 
#     return item_property
# 
# Path: simfile/_private/serializable.py
# class Serializable(metaclass=ABCMeta):
# 
#     @abstractmethod
#     def serialize(self, file: TextIO) -> None:
#         """
#         Write the object to provided text file object as MSD.
#         """
#         pass
#     
#     def __str__(self) -> str:
#         """
#         Convert the object to an MSD string.
#         """
#         serialized = StringIO()
#         self.serialize(serialized)
#         return serialized.getvalue()


# Path: simfile/base.py
from abc import ABCMeta, abstractclassmethod, abstractmethod
from collections import OrderedDict
from typing import Iterator, Optional, TextIO, Tuple, Union
from msdparser import parse_msd
from ._private.generic import E, ListWithRepr
from ._private.property import item_property
from ._private.serializable import Serializable

    Additionally, properties recognized by the current stable version
    of StepMania are exposed through lower-case properties on the
    object for easy (and implicitly spell-checked) access. The
    following known properties are defined:

    * Metadata: `title`, `subtitle`, `artist`, `titletranslit`,
      `subtitletranslit`, `artisttranslit`, `genre`, `credit`,
      `samplestart`, `samplelength`, `selectable`, `instrumenttrack`,
      `timesignatures`
    * File paths: `banner`, `background`, `lyricspath`, `cdtitle`,
      `music`
    * Gameplay events: `bgchanges`, `fgchanges`, `keysounds`, `attacks`,
      `tickcounts`
    * Timing data: `offset`, `bpms`, `stops`, `delays`

    If a desired simfile property isn't in this list, it can still be
    accessed as a dict item.

    By default, the underlying parser will throw an exception if it
    finds any stray text between parameters. This behavior can be
    overridden by setting `strict` to False in the constructor.
    """
    title = item_property('TITLE')
    subtitle = item_property('SUBTITLE')
    artist = item_property('ARTIST')
    titletranslit = item_property('TITLETRANSLIT')
    subtitletranslit = item_property('SUBTITLETRANSLIT')
    artisttranslit = item_property('ARTISTTRANSLIT')
    genre = item_property('GENRE')
    credit = item_property('CREDIT')

    banner = item_property('BANNER')