#!/usr/bin/env python

import re
import unittest
import collections

def flatten(l):
    "http://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists-in-python"
    if l:
        for el in l:
            if isinstance(el, collections.Iterable) and not isinstance(el, (str,bytes)):
# The following is incompatible with python 3.
#            if isinstance(el, collections.Iterable) and not isinstance(el, basestring):
                for sub in flatten(el):
                    yield sub
            else:
                yield el

def parseDirectiveArguments(data):
    
    """Makes a list whose elements are delimited by commas in an input

    string. Commas inside a scope started with brackets, parens, single-
    or double-quotes, are skipped.  Scopes delimited by brackets or
    parentheses are assumed to be well formed.  I.e. we simply count
    opening and closing brackets and parens without regards to any other
    syntax or ordering rules. It would be nice to throw an exception or
    emit warnings when we detect suspicious syntax.
    """
    
    pos = 0; npos = len(data); str=''; maskCommas=False
    scopeCounts = {'[':0,'(':0,'"':0,"'":0} # Assume well formed scopes.
    scopeTerminators = {'[':']','(':')','"':'"',"'":"'"}
    scopeNames = {'(':'parens','[':'brackets','"':'double quotes',"'":'single quotes'}
    while (pos < npos):
        if data[pos] == ',' and not maskCommas:
            return [i for i in flatten([str,parseDirectiveArguments(data[pos+1:])])]
        else:
            for key in scopeCounts.keys():
                if data[pos] == key:
                    scopeCounts[key] = scopeCounts[key] + 1
                    maskCommas = True
                elif data[pos] == scopeTerminators[key]:
                    scopeCounts[key] = scopeCounts[key] - 1
                    if scopeCounts[key] < 0:
                        # Maybe try exceptions...
                        print('parseDirectiveArguments::error: mismatched '+scopeNames[key]+' parenCount < 0 "',str,'" from "',data,'"')
                        return None
                    else:
                        maskCommas = sum(map(abs,scopeCounts.values())) > 0
        str = str + data[pos]
        pos = pos + 1
    return [str]
        
    
class TestParseDirectiveArgs(unittest.TestCase):

    def test_args1(self):
        self.assertEqual(['a','b','c'],parseDirectiveArguments('a,b,c'))

    def test_args2(self):
        self.assertEqual(['a','b(1,2)','c((1,3,z(x,y(4))))'],parseDirectiveArguments('a,b(1,2),c((1,3,z(x,y(4))))'))

    def test_args3(self):
        self.assertEqual(['a','b','c[d,e,f(x,y)]'],parseDirectiveArguments('a,b,c[d,e,f(x,y)]'))

    def test_args4(self):
        self.assertEqual(['a','b','c[d,e,f(x,y]'],parseDirectiveArguments('a,b,c[d,e,f(x,y]'))

    def test_args5(self):
        self.assertEqual(['a','b="This, is, a, test."'],parseDirectiveArguments('a,b="This, is, a, test."'))
        self.assertEqual(["a","b='This, is, a, test.'"],parseDirectiveArguments("a,b='This, is, a, test.'"))

if __name__ == '__main__':
    print('starting')
    unittest.main()
    print('done')