#
# Copyright (C) 2008-2009 by Arnold Krille
#
# This file is part of FFADO
# FFADO = Free Firewire (pro-)audio drivers for linux
#
# FFADO is based upon FreeBoB.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import os
import dbus

import shlex

import logging
log = logging.getLogger('configparser')

class DeviceList:
    def __init__( self, filename="" ):
        self.devices = list()
        if not filename == "":
            self.updateFromFile( filename )

    def updateFromFile( self, filename, must_exist=False):
        filename = os.path.expanduser(filename)
        log.debug("DeviceList::updateFromFile(%s)" % filename)
        if not os.path.exists( filename ):
            if must_exist:
                log.error("cannot open file")
            return
        f = open( filename, "r" )

        lex = Parser( f )
        config = {}
        while lex.peaktoken() != lex.eof:
            tmp = lex.parsenamedvalue()
            if tmp != None:
                config[ tmp[0] ] = tmp[1]
        if "device_definitions" in config:
            for dev in config["device_definitions"]:
                self.addDevice( dev )

    def getDeviceById( self, vendor, model ):
        if isinstance(vendor, dbus.Int32):
            vendor = str(int(vendor))
        if isinstance(model, dbus.Int32):
            model = str(int(model))

        log.debug("DeviceList::getDeviceById( %s, %s )" % (vendor, model ))
        for dev in self.devices:
            if int("%s" % dev['vendorid'], 0) == int("%s" % vendor, 0) and \
               int("%s" % dev['modelid'], 0) == int("%s" % model, 0):
                return dev
        tmp = dict()
        self.devices.append( tmp )
        return tmp

    def addDevice( self, device_dict ):
        log.debug("DeviceList::addDevice()")
        dev = self.getDeviceById( device_dict['vendorid'], device_dict['modelid'] )
        dev.update( device_dict )

class Parser:
    def __init__( self, file ):
        self.lex = shlex.shlex( file )
        self.eof = self.lex.eof

    def peaktoken( self ):
        token = self.lex.get_token()
        self.lex.push_token( token )
        return token

    def parselist( self, level="" ):
        token = self.peaktoken()
        if token != "(":
            return
        self.lex.get_token()
        log.debug("%sWill parse list" % level)
        ret = []
        token = self.peaktoken()
        while token != ")":
            ret.append( self.parsenamedvalue( level+"  " ) )
            token = self.peaktoken()
        log.debug("%slist is %s" % (level, str(ret)))
        self.lex.get_token()
        if self.peaktoken() == ",":
            log.debug("%sFound a delimiter" % level)
            self.lex.get_token()
        return ret

    def parsemap( self, level="" ):
        token = self.lex.get_token()
        if token != "{":
            return
        log.debug("%sWill parse map" % level)
        ret = {}
        token = self.peaktoken()
        while token != "}":
            #self.push_token( token )
            tmp = self.parsenamedvalue( level+"  " )
            if tmp != None:
                ret[ tmp[0] ] = tmp[1]
            token = self.peaktoken()
        token = self.lex.get_token()
        log.debug("%sMap ended with '%s' and '%s'"% (level,token,self.peaktoken()))
        if self.peaktoken() in (",",";"):
            log.debug("%sFound a delimiter!" % level)
            self.lex.get_token()
        return ret

    def parsevalue( self, level="" ):
        token = self.lex.get_token()
        log.debug("%sparsevalue() called on token '%s'" % (level, token))
        self.lex.push_token( token )
        if token == "(":
            value = self.parselist( level+"  " )
        elif token == "{":
            value = self.parsemap( level+"  " )
        else:
            value = self.lex.get_token().replace( "\"", "" )
        token = self.peaktoken()
        if token == ";":
            log.debug("%sFound a delimiter!" % level)
            self.lex.get_token()
        return value

    def parsenamedvalue( self, level="" ):
        token = self.lex.get_token()
        log.debug("%sparsenamedvalue() called on token '%s'" % (level, token))
        if token == "{":
            self.lex.push_token( token )
            return self.parsemap( level+"  " )
        if len(token) > 0 and token not in ("{","}","(",")",",",";"):
            log.debug("%sGot name '%s'" %(level,token))
            name = token
            token = self.lex.get_token()
            if token in ("=",":"):
                #print( "%sWill parse value" % level )
                value = self.parsevalue( level )
                return (name,value)
        log.debug("%sparsenamedvalue() will return None!" % level)
        return

#
# Have kind of a test directly included...
#
if __name__ == "__main__":

    import sys

    file = sys.argv[1]

    log.setLevel(logging.DEBUG)
    devs = DeviceList( file )

    print( devs.devices )

# vim: et
