# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/05_utils.ipynb.

# %% auto 0
__all__ = ['psyn', 'nsyn', 'zsyn', 'any2signint', 'num2signint', 'str2signint', 'numstr2signint', 'tosignint', 'matchsign',
           'toint', 'tochr', 'tosym', 'tosyn', 'toset', 'topow', 'tosign', 'totuple', 'prep_strs', 'make_fstr',
           'make_bstr', 'make_estr', 'from_fstr', 'from_bstr', 'from_estr']

# %% ../nbs/05_utils.ipynb 3
from numbers import Number
from typing import Any, Tuple, Optional

# %% ../nbs/05_utils.ipynb 4
from atyp import BoolCall
from bflag import tern2x

# %% ../nbs/05_utils.ipynb 5
from .types import sint, NumStr, SignInt, SignChr, SignSym, ExpoChr, NumStrQ, SignIntQ, SignSymQ, SignChrQ, ExpoChrQ
from .guard import ispos, isneg, isstr, isnum, isnumstr, isexpochr
from .sign import sign, P, Z, N

from .cons import BASE
from .pttn import (ftmpl, btmpl, etmpl, fpttn, bpttn, epttn)

# %% ../nbs/05_utils.ipynb 7
def psyn(s: str) -> bool: return P.issyn(s)
def nsyn(s: str) -> bool: return N.issyn(s)
def zsyn(s: str) -> bool: return Z.issyn(s)

def any2signint(val: Any, posfn: Optional[BoolCall] = ispos, negfn: Optional[BoolCall] = isneg) -> SignInt: 
    return tern2x(val, posfn, negfn, P.int, N.int, Z.int)

def num2signint(s: Number) -> SignInt: return any2signint(s, ispos, isneg)
def str2signint(s: str) -> SignInt:
    try: return num2signint(int(s))
    except: return any2signint(s, psyn, nsyn)

def numstr2signint(s: NumStrQ) -> SignInt: return str2signint(s) if isstr(s) else num2signint(s) if isnum(s) else Z.int

def tosignint(s: Any) -> SignIntQ: return numstr2signint(s) if isnumstr(s) else None
def matchsign(val: Any, pos: Any = P.int, neg: Any = N.int, nil: Any = Z.int, default: Any = None) -> Any:
    match tosignint(val):
        case  1: return pos
        case -1: return neg
        case  0: return nil
        case  _: return default

def toint(s: NumStr) -> SignInt: return matchsign(s, P.int, N.int, Z.int)
def tochr(s: NumStr) -> SignChr: return matchsign(s, P.chr, N.chr, Z.chr)
def tosym(s: NumStr) -> SignSym: return matchsign(s, P.sym, N.sym, Z.sym)
def tosyn(s: NumStr) -> set: return matchsign(s, P.syn, N.syn, Z.syn)
def toset(s: NumStr) -> set: return matchsign(s, P.set, N.set, Z.set)
def topow(base: int, expo: int, sign: NumStrQ = None) -> Number: return base ** (expo * tosignint(sign or expo))

def tosign(s: NumStr, force: bool = False) -> Optional[sign]: return matchsign(s, P, N, Z, None if force else Z)
def totuple(s: NumStr) -> tuple: return tuple(tosign(s))

# %% ../nbs/05_utils.ipynb 9
def prep_strs(
    expo: Number = 0, sign: sint = None, base: Number = BASE, 
    echr: ExpoChr = '^', showsign: bool = True, showbase: bool = True
) -> Tuple[int, str, SignSymQ, SignChrQ, ExpoChrQ]:
    sign = tosign(sign or expo, force = True)
    bstr = str(base) if showbase else ''
    sstr = sign.sym if showsign else ''
    schr = sign.chr
    echr = echr if isexpochr(echr) else '^'
    estr = abs(expo)
    return bstr, sstr, schr, estr, echr

# %% ../nbs/05_utils.ipynb 11
def make_fstr(
    expo: Number = 0, sign: sint = None, base: Number = BASE, 
    echr: ExpoChr = '^', showsign: bool = True, showbase: bool = True
) -> str:
    bstr, sstr, schr, estr, echr = prep_strs(expo, sign, base, echr, showsign, showbase)
    return ftmpl.substitute(expo=estr, sign=schr)

def make_bstr(
    expo: Number = 0, sign: sint = None, base: Number = BASE, 
    echr: ExpoChr = '^', showsign: bool = True, showbase: bool = True
) -> str:
    bstr, sstr, schr, estr, echr = prep_strs(expo, sign, base, echr, showsign, showbase)
    return btmpl.substitute(base=bstr, sign=sstr, echr=echr, expo=estr)

def make_estr(
    expo: Number = 0, sign: sint = None, base: Number = BASE, 
    echr: ExpoChr = '^', showsign: bool = True, showbase: bool = True
) -> str:
    bstr, sstr, schr, estr, echr = prep_strs(expo, sign, base, echr, showsign, showbase)
    return etmpl.substitute(sign=sstr, expo=estr)


# %% ../nbs/05_utils.ipynb 14
def from_fstr(s: str, base: int = BASE) -> (Number, SignIntQ, Number):
    match = fpttn.match(s)
    if match:
        expo = int(match.group('expo'))
        sign = toint(match.group('sign'))
        return expo, sign, base
    raise ValueError(f"String '{s}' doesn't match factor format")

def from_bstr(s: str, base: int = BASE) -> (Number, SignIntQ, Number):
    match = bpttn.match(s)
    if match:
        base = int(match.group('base')) if match.group('base') else base
        expo = int(match.group('expo'))
        sign = toint(match.group('sign') + '1')
        return expo, sign, base
    raise ValueError(f"String '{s}' doesn't match base format")

def from_estr(s: str, base: int = BASE) -> (Number, Number, SignIntQ):
    match = epttn.match(s)
    if match:
        expo = int(match.group('expo'))
        sign = toint(match.group('sign') + '1')
        return expo, sign, base
    raise ValueError(f"String '{s}' doesn't match exponent format")
