1# -*- coding: utf-8 -*-
2# Copyright (C) 2005  Michael Urman
3#
4# This program is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 2 of the License, or
7# (at your option) any later version.
8
9from ._util import loadfile
10
11
12class PaddingInfo(object):
13    """PaddingInfo()
14
15    Abstract padding information object.
16
17    This will be passed to the callback function that can be used
18    for saving tags.
19
20    ::
21
22        def my_callback(info: PaddingInfo):
23            return info.get_default_padding()
24
25    The callback should return the amount of padding to use (>= 0) based on
26    the content size and the padding of the file after saving. The actual used
27    amount of padding might vary depending on the file format (due to
28    alignment etc.)
29
30    The default implementation can be accessed using the
31    :meth:`get_default_padding` method in the callback.
32
33    Attributes:
34        padding (`int`): The amount of padding left after saving in bytes
35            (can be negative if more data needs to be added as padding is
36            available)
37        size (`int`): The amount of data following the padding
38    """
39
40    def __init__(self, padding, size):
41        self.padding = padding
42        self.size = size
43
44    def get_default_padding(self):
45        """The default implementation which tries to select a reasonable
46        amount of padding and which might change in future versions.
47
48        Returns:
49            int: Amount of padding after saving
50        """
51
52        high = 1024 * 10 + self.size // 100  # 10 KiB + 1% of trailing data
53        low = 1024 + self.size // 1000  # 1 KiB + 0.1% of trailing data
54
55        if self.padding >= 0:
56            # enough padding left
57            if self.padding > high:
58                # padding too large, reduce
59                return low
60            # just use existing padding as is
61            return self.padding
62        else:
63            # not enough padding, add some
64            return low
65
66    def _get_padding(self, user_func):
67        if user_func is None:
68            return self.get_default_padding()
69        else:
70            return user_func(self)
71
72    def __repr__(self):
73        return "<%s size=%d padding=%d>" % (
74            type(self).__name__, self.size, self.padding)
75
76
77class Tags(object):
78    """`Tags` is the base class for many of the tag objects in Mutagen.
79
80    In many cases it has a dict like interface.
81    """
82
83    __module__ = "mutagen"
84
85    def pprint(self):
86        """
87        Returns:
88            text: tag information
89        """
90
91        raise NotImplementedError
92
93
94class Metadata(Tags):
95    """Metadata(filething=None, **kwargs)
96
97    Args:
98        filething (filething): a filename or a file-like object or `None`
99            to create an empty instance (like ``ID3()``)
100
101    Like :class:`Tags` but for standalone tagging formats that are not
102    solely managed by a container format.
103
104    Provides methods to load, save and delete tags.
105    """
106
107    __module__ = "mutagen"
108
109    def __init__(self, *args, **kwargs):
110        if args or kwargs:
111            self.load(*args, **kwargs)
112
113    @loadfile()
114    def load(self, filething, **kwargs):
115        raise NotImplementedError
116
117    @loadfile(writable=False)
118    def save(self, filething=None, **kwargs):
119        """save(filething=None, **kwargs)
120
121        Save changes to a file.
122
123        Args:
124            filething (filething): or `None`
125        Raises:
126            MutagenError: if saving wasn't possible
127        """
128
129        raise NotImplementedError
130
131    @loadfile(writable=False)
132    def delete(self, filething=None):
133        """delete(filething=None)
134
135        Remove tags from a file.
136
137        In most cases this means any traces of the tag will be removed
138        from the file.
139
140        Args:
141            filething (filething): or `None`
142        Raises:
143            MutagenError: if deleting wasn't possible
144        """
145
146        raise NotImplementedError
147