# Misc functions

from string import lower,printable,Template,capitalize as fcap
import re,shlex
import asyncore as ac
from random import *

NL = "\r\n"
is_a = isinstance
cap = lambda x: x[:1].upper() + x[1:]   # capitalize first letter
sxarg = shlex.split

# split with quote handling
def sxarg(x):
    try: return shlex.split(x) # shlex.split has trouble with improper quotes
    except: return x.split()

# Sort of like MERC's one_arg, except much much stupider
def xarg(t):
    ts = sxarg(t)
    return ts and [ts[0]," ".join(ts[1:])] or ts

# does t match any of the names in ns?
def nmatch(t,ns):
    for x in ns:
        if x.startswith(t): return 1

# split up a string into keywords
tok = lambda t: map(lower,t.strip().split())

# connected players
def cplayers():
    return [c.p for c in ac.socket_map.itervalues() if c.p]

# n = name to find, xs = list to search, gn = extract obj
def find(n,xs,gn=lambda x:x):
    skip = 0
    ns = tok(n)
    if not ns: return 0
    if ns[-1].isdigit(): # "green tea 2" gets the second green tea
        skip = max(int(ns[-1])-1,0)
        del ns[-1]
    for z in xs:
        x = gn(z)
        if not x.names: x.names = tok(x.name)
        for n in ns:
            if not nmatch(n,x.names): break
        else:
            if skip: skip -= 1
            else: return z

# fix dangling color '{'
def cfix(r):
    if r and r[-1] == '{' and (len(r) == 1 or r[-2] != '{'): r += '{'
    return r

# fits a list to a certain size, filling empty spaces with g
def fit(x,z=2,g=''): return x[:z] + [g] * (z-len(x))

# respect descriptions
rscale = ("hellishly vile",20,"utterly pathetic",30,"mildly idiotic",
50,"rather frumpish",70,"slightly unkempt",85,"decent",99,"respectable",
275,"very respectable",350,"trendy",650,"stunning",750,"debonair",999,"awesome")

# health descs (by percent)
hscale = ("near death",10,"horribly disfigured",20,"ghastly pale",
30,"terribly wounded",50,"badly bruised",70,"bruised",80,"slightly scratched",
95,"pretty good shape",100,"in perfect health")

def scale(s,m):
    r = 0
    for x in s:
        if is_a(x,int) and m < x: break
        r = x
    return r

# broadcast messages
# uses format strings like $SN (subj name)
#   targets: S for subj, V for vict, O for obj
#   formats: N for name, T for text, E for he/she/it,
#            M for him/her/it, S for his/her/its
#
# broadcats functions:
#   room  - third-party bystanders excluding subj and vict in subj's room
#   subj  - subj only
#   vict  - vict only
#   all   - everyone in subj's room
#   world - global except subj

# It's a "class act"! Get it? Ahahaha - okay, sorry, no more puns
class Act(object):
    def __init__(S,subj=0,vict=0,obj=0):
        S._s = subj; S._v = vict; S._o = obj

    def repl(S, m):
        x, y = m.group(1, 2)
        r = {'S':S._s,'V':S._v,'O':S._o}[x]

        if y == 'N': t = r.name
        if y == 'T': t = cfix(r)
        if y == 'E': t = r.SE
        if y == 'M': t = r.SM
        if y == 'S': t = r.SS
        return t

    room = lambda S,t: S.act(t, S._s.room.people, [S._s,S._v,S._o])
    subj = lambda S,t: S.act(t, [S._s])
    vict = lambda S,t: S.act(t, [S._v], [S._s])
    obj = lambda S,t: S.act(t, [S._o], [S._s,S._v])
    all = lambda S,t: S.act(t, S._s.room.people)
    world = lambda S,t: S.act(t, cplayers(), [S._s])

    # text, seq of viewers, seq to exclude
    def act(S,t,vs,ex=[]):
        if not t: return S
        x = cap(re.sub("\$([SVO])([NTEMS])",S.repl,t))
        for v in (y for y in vs if y not in ex): v.sendl(x)
        return S # allow chaining