# This file is part of the Coral project.
# Please read the copyright notice in the LICENSE file.

import copy
from coral import log

import string
import sys
import os


theCG=None
lastCG=None

def getCG():
    global theCG
    global lastCG
    if not theCG:
        theCG=CodeGenerator()
    if not lastCG:
        lastCG=theCG
    return lastCG

def setDefaultCodeGenerator(cg):
    global lastCG
    lastCG=cg

class CodeGenerator:
    def __init__(self):
        self.outputString=""
        self.keepOutput=0
        self.outputFD=sys.stdout
        self.margin=0
        self.lineCounter=0
        self.indentLine=0
        self.tabSize=4
        setDefaultCodeGenerator(self)
        self.nl=0
        
    def setKeepOutput(self,b):
        self.keepOutput=b
        if not self.keepOutput:
            self.outputString=""
            
    def setTab(self,tab):
        assert(tab>0)
        self.tabSize=tab

    def getTab(self):
        return self.tabSize

    def setLeftMargin(self,m):
        assert(m>=0)
        self.margin=m
        
    def inLine(self,i):
        if i==1:
            self.lineCounter+=1
        else:
            self.lineCounter-=1
        if self.lineCounter==0 and i!=0:
            self.emit("\n")
        
    def indent(self,i):
        self.margin+=i*self.tabSize
        if self.margin<0:
            self.margin=0

    def emitLine(self,*args):
        self.inLine(+1)
        self.emit(args)
        self.inLine(-1)
        
    def emit(self,*args):
        s=""
        for x in args:
            if x!="" and x is not None:
                s=s+str(x)
        if s=="->>":
            self.indent(+1)
            return
        if s=="<<-":
            self.indent(-1)
            return
        if s=="\\->>":
            s="->>"
        if s=="\\<<-":
            s="<<-"
        if s:
            if self.nl:
                s=self.margin*" "+s
                self.nl=0

            if s[-1]=='\n':
                self.nl=1
                
            s=string.replace(s[:-1],"\n","\n"+self.margin*" ")+s[-1]
            if self.outputFD:
                self.outputFD.write(s)
            else:
                raise "Output descriptor is closed "
            if self.keepOutput:
                self.outputString=self.outputString+s
            
                       
    def setOutputTo(self,fn,append=0):
        if self.outputFD and self.outputFD!=sys.stdout:
            self.outputFD.close()            
        if not fn:
            self.outputFD=None
        else:
            if type(fn)==type(""):
                if os.path.dirname(fn):
                    try:
                        os.makedirs(os.path.dirname(fn))
                    except:
                        pass
                if not append:
                    self.outputFD=open(fn,"w")
                else:
                    self.outputFD=open(fn,"w+")
            else:
                self.outputFD=fn
        return self.outputFD

    def close(self,fn):
        self.setOutputTo(None)
        
def pipeParse( s ,addImport=1 ):
    if addImport:
        script="from coral.core.transform import pipeScript\n"
    else:
        script=""
    s=string.replace(s,"\r","")
    for l in string.split(s,"\n"):
        if '|' not in l:
            script=script+ l+"\n"
        else:
            line=""
            inEmit=0
            inComment=0
            blank=1
            margin=0
            inPython=1
            inEscape=0
            for c in l:
                if inEscape:
                    if c!='|':
                        line=line+'\\'
                    line=line+c
                    inEscape=0
                else:
                    if c=='#':
                        inComment=1
                        line=line+c
                    elif c=='\\':                    
                        inEscape=1
                        blank=0
                    else:
                        if c=='|' and not inComment:
                            if inEmit==0:
                                if blank:
                                    line=line+"pipeScript.getCG().inLine(+1);pipeScript.getCG().emit('"
                                else:
                                    line=line[:margin]+ \
                                          "pipeScript.getCG().inLine(+1);pipeScript.getCG().emit("+ \
                                          line[margin:] + \
                                          ",'"
                                blank=0
                                inEmit=1
                            elif inEmit==1:
                                inEmit=2
                                line=line+"');pipeScript.getCG().emit("
                            else:
                                line=line+");pipeScript.getCG().emit('"
                                inEmit=1
                        else:
                             if blank and c in string.whitespace:
                                 margin+=1
                             else:
                                 blank=0
                             line=line+c
            if l[-2:]=="|+" and inEmit==2:
                line=line[:-25]+" pipeScript.getCG().inLine(0)"
            else:
                if inEmit==1:
                    line=line+"'); pipeScript.getCG().inLine(-1)"
                if inEmit==2:
                    line=line+") ; pipeScript.getCG().inLine(-1)"

            script=script+line+"\n"
            
    return script
    
class PipeScriptRunner:

    def __init__(self,argv=None):
        if argv:
            self.argv=argv
        else:
            self.argv=[]
        self.error=0
        self.log=log.getLogger("PipeScript")

    def loadScript(self,fileName):
        fd=open(fileName,'r')
        try:
            script=pipeParse(fd.read())
        finally:
            fd.close()
        return script
        
    def main(self,loop,args):
        self.argv=args
        self.doit()            

    def doit(self):
        self.output=""
        if len(self.argv)==0:
            print "Usage: spyrun script args"
            sys.exit(0)
            
        self.script=self.loadScript(self.argv[0])
        #print self.script
        dict={}
        sys.argv=self.argv
        exec(self.script,dict)


        
