# *****************************************************************************
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Module authors:
#   Markus Zolliker <markus.zolliker@psi.ch>
#
# *****************************************************************************
"""handling of prefixes of physical units"""

import re
import prefixed

prefixed.SI_MAGNITUDE['u'] = 1e-6  # accept 'u' as replacement for 'µ'


class NumberWithUnit:
    def __init__(self, *units):
        pfx = "|".join(prefixed.SI_MAGNITUDE)
        unt = "|".join(units)
        self.units = units
        self.pattern = re.compile(rf'\s*([+-]?\d*\.?\d*(?:[eE][+-]?\d+)?\s*(?:{pfx})?)({unt})\s*$')

    def parse(self, value):
        """parse and return number and value"""
        match = self.pattern.match(value)
        if not match:
            raise ValueError(f'{value!r} can not be interpreted as a number with unit {",".join(self.units)}')
        number, unit = match.groups()
        return prefixed.Float(number), unit

    def getnum(self, value):
        """parse and return value only"""
        return self.parse(value)[0]


def format_with_unit(value, unit='', digits=3):
    return f'{prefixed.Float(value):.{digits}H}{unit}'
