#!/usr/bin/env python

import scanners
# FIXME null in fieldList
class Application(object):
    def __init__(self, operator, operands):
        self.operator = operator
        self.operands = operands
    def __str__(self):
        import StringIO
        IO = StringIO.StringIO()
        IO.write("(")
        if len(self.operands) == 1:
            IO.write(self.operator)
        for i in range(len(self.operands)):
            IO.write(repr(self.operands[i]))
            if i < len(self.operands) - 1:
                IO.write(self.operator)
        IO.write(")")
        return(IO.getvalue())
class Query(object):
    def __init__(self, fieldList, destination, source, filter, order, group, groupFilter):
        self.fieldList = fieldList
        self.destination = destination
        self.source = source
        self.filter = filter
        self.order = order
        self.group = group
        self.groupFilter = groupFilter
    def __str__(self):
        import StringIO
        IO = StringIO.StringIO()
        IO.write("SELECT ")
        IO.write(", ".join([str(x) for x in self.fieldList]))
        if self.destination:
            IO.write(" INTO %s" % self.destination)
        if self.source:
            IO.write(" FROM %s" % self.source)
        if self.filter:
            IO.write(" WHERE %s" % self.filter)
        if self.order:
            IO.write(" ORDER BY %s" % self.order)
        if self.group:
            IO.write(" GROUP BY %s" % self.group)
        if self.groupFilter:
            IO.write(" HAVING %s" % self.groupFilter)
        return(IO.getvalue())
class SourceFieldAccessor(object):
    def __init__(self, table, field):
        self.table = table
        self.field = field
    def __repr__(self): # TODO quote
        if self.table:
            return("%s.%s" % (self.table, self.field))
        else:
            return("%s" % self.field)
class SelectField(object):
    def __init__(self, expression, alias):
        self.expression = expression
        self.alias = alias
    def __str__(self):
        return("%s%s" % (str(self.expression), (" AS %s" % self.alias) if self.alias else ""))
def accessField(table, field):
    return(SourceFieldAccessor(table, field))
def createSelectField(expression, alias):
    return(SelectField(expression, alias))
class Parser(scanners.Scanner):
    def parseStatement(self):
        self.consume("SELECT")
        return(Query(self.parseSELECTFieldList(), 
                     self.parseINTO(), 
                     self.parseFROM(), 
                     self.parseWHERE(), 
                     self.parseORDERBY(), 
                     self.parseGROUPBY(), 
                     self.parseHAVING()))
    def parseSELECTField(self):
        a = self.parseExpression()
        if self.input == "AS":
            self.consume()
            b = self.consume("ID")
        else:
            b = None
        return(createSelectField(a, b))
    def parseSELECTFieldList(self):
        l = [self.parseSELECTField()]
        while self.input and self.input == ",":
            self.consume()
            l.append(self.parseSELECTField())
        return(l)
    def parseINTO(self):
        if self.input == "INTO":
            self.consume("INTO")
            self.err("<implemented-INTO>", "<unimplemented-fun>")
        else:
            return(None)
    def parseFROM(self):
        if self.input == "FROM":
            self.consume("FROM")
            self.err("<implemented-FROM>", "<unimplemented-fun>")
        else:
            return(None)
    def parseWHERE(self):
        if self.input == "WHERE":
            self.consume("WHERE")
            self.err("<implemented-WHERE>", "<unimplemented-fun>")
        else:
            return(None)
    def parseORDERBY(self):
        if self.input == "ORDER":
            self.consume("ORDER")
            self.consume("BY")
            self.err("<implemented-ORDERBY>", "<unimplemented-fun>")
        else:
            return(None)
    def parseGROUPBY(self):
        if self.input == "GROUP":
            self.consume("GROUP")
            self.consume("BY")
            self.err("<implemented-GROUPBY>", "<unimplemented-fun>")
        else:
            return(None)
    def parseHAVING(self):
        if self.input == "HAVING":
            self.consume("HAVING")
            self.err("<implemented-HAVING>", "<unimplemented-fun>")
        else:
            return(None)
    def parseExpression(self):
        return(self.parseSum())
    def parseSum(self):
        l = []
        l.append(self.parseProduct())
        if self.input == "+" or self.input == "-":
            operator = self.consume()
            l.append(self.parseProduct())
            return(Application(operator, l))
        else:
            return(l[0])
    def parseProduct(self):
        l = []
        l.append(self.parseValue())
        if self.input == "*" or self.input == "/":
            operator = self.consume()
            l.append(self.parseValue())
            return(Application(operator, l))
        else:
            return(l[0])
    def parseFunctionCall(self, a):
        self.consume()
        l = []
        while self.input and self.input != ")":
            l.append(self.parseExpression())
            if self.input == ",":
                self.consume(",")
            else:
                break
        self.consume(")")
        return(Application(a, l))
    def parseValue(self):
        if self.input == "STRING":
            return(self.consume("STRING"))
        else: # field, function call.
            if self.input == "*":
                self.consume()
                return(accessField(None, "*"))
            else:
                a = self.consume("ID")
                if self.input == ".":
                    if self.input == "ID":
                        b = self.consume("ID")
                    else:
                        b = self.consume("*")
                    return(accessField(a,b))
                elif self.input == "(": # function call.
                    return(self.parseFunctionCall(a))
                else:
                    return(accessField(None, a))
if __name__ == "__main__":
    import StringIO
    parser = Parser()
    parser.push(StringIO.StringIO("SELECT * FROM dual"))
    parser.consumeDetail()
    parser.consume()
    print(parser.parseStatement())
