# spigot algorithms for calculating
# (c) Goetz Schwandtner <schwandtner@googlemail.com> 08-2006
#
# SpigotPi: implementation of the pascal program from [1]
# [1] Stanley Rabinowitz, Stan Wagon: A Spigot Algorithm for the Digits 
#       of pi. American Mathematical Monthly, Vol 102 No 3 (Mar 1995) pp 195-203

class SpigotPi(object):
    "Spigot algorithm for Pi implementation. Initialize with number of digits and then run with run() method"
    def __init__(self, numdigits, out=True):
        self.n=numdigits
        self.out=out
    def _output(self, x):
        self.res.append(x)
        if self.out:
            print x,
    def run(self):
        "Run the algorithm. If out, print digits as they appear."
        self.res=[]
        len=10*self.n/3
        a=[2 for i in range(len)]
        nines=0
        predigit=0
        for j in range(1,self.n+1):
            q=0
            for i in range(len,0,-1):
                x=10*a[i-1]+q*i
                a[i-1]=x % (2*i-1)
                q=x/(2*i-1)
            a[0],q=q%10,q/10
            if q==9:
                nines=nines+1
            elif q==10:
                self._output(predigit+1)
                for k in range(nines):
                    self._output(0)
                predigit,nines=0,0
            else:
                self._output(predigit)
                predigit=q
                if nines != 0:
                    for k in range(nines):
                        self._output(9)
                    nines=0
        self._output(predigit)
        return self.res

class SpigotE(object):
    "Spigot algorithm for e implementation. Initialize with number of digits and then run with run() method"
    def __init__(self, numdigits, out=True):
        self.n=numdigits
        self.out=out
    def _output(self, x):
        self.res.append(x)
        if self.out:
            print x,
    def run(self):
        "Run the algorithm. If out, print digits as they appear."
        self.res=[]
        len=self.n+1
        a=[1 for i in range(len)]
        for j in range(1,self.n+1):
            q=0
            for i in range(len,0,-1):
                x=10*a[i-1]+q
                a[i-1]=x % i
                q=x/i
            a[0],q=q%10,q/10
            self._output(a[0])
        return self.res

# app stuff for Symbian S60 form handling
import appuifw, e32

class FormHandler(object):
    def __init__(self):
        self.n=0
    def display(self):
        self.f = appuifw.Form([(u'Type','combo',([u'pi',u'e'],0)),(u'#dig','number',self.n),(u'result','text')],appuifw.FFormEditModeOnly)
        self.f.save_hook=self.recalc
        self.f.menu=[(u'about',self.about)]
        self.f.execute()
    def about(self):
        appuifw.note(u'(c) 2006 Goetz Schwandtner\n <schwandtner@googlemail.com>')
    def recalc(self,ls):
        n=ls[1][2]
        if ls[0][2][1]==0:
            s=SpigotPi(n)
            print "\npi: ",
        else:
            s=SpigotE(n)
            print "\ne: ",        
        print n," Digits:"
        p=s.run()
        print "\n\n"
        r=self.seq2String(p)
        if ls[0][2][1]==0:
            r=r[1]+"."+r[2:]
        else:
            r="2."+r           
        ls[2]=(u'result','text',u''+r)
        return True
    def seq2String(self,s):
        return reduce((lambda x,y:str(x)+str(y)),s)

if __name__ == '__main__':
    appuifw.app.title = u'Spigot algorithms (c) G.Schwandtner'
    fh=FormHandler()
    fh.display()
    
