function [mgens,ok] = parseMgenList( s )
%mgens = parseMgenList( s )
%   s is a string containing a list of morphogen names and possibly
%   morphogen properties.  The general syntax is:
%       mgenname ( propertyname = propertyvalue, ... )
%   The property names that can be specified are:
%       d, diff: diffusion constant (default value 0)
%       dec, decay: decay constant (default value 0)
%   The result is a struct array with fields 'mgen', 'diff', and
%   'decay'.

    nexttokenpats = { '[A-Za-z][A-Za-z0-9_]*', '\(','\)','=',',','[0-9.]+', '.' };
    tokens = tokenise( s, nexttokenpats );

  % tokens = wordsplit( s, {'\(','\)','=',',','[0-9.]+'} );
    defaultstruct = struct( 'mgen', '', 'diff', 0, 'decay', 0 );
    mgens = [defaultstruct];
    nummgens = 0;
    ok = true;
    i = 1;
    while i <= length(tokens)
        tok = lower(tokens{i});
        if ~isValidMgenName( tok )
            complain( 'Unexpected token ''%s'' found where morphogen name expected\n', tok );
            ok = false;
            return;
        end
        nummgens = nummgens+1;
        mgens(nummgens) = defaultstruct;
        mgens(nummgens).mgen = tok;
        i = i+1;
        if (i <= length(tokens)) && strcmp(tokens{i},'(')
            while (i < length(tokens)) && ~strcmp( tokens{i}, ')' )
                i = i+1;
                if i > length(tokens)
                    complain( 'Unexpected end of morphogen spec ''%s''.\n', s );
                    ok = false;
                    return;
                end
                paramname = lower(tokens{i});
                if ~isfield( defaultstruct, paramname )
                    complain( 'Unexpected parameter name ''%s''.\n', paramname );
                    ok = false;
                    return;
                end
                i = i+1;
                if i > length(tokens)
                    complain( 'Unexpected end of morphogen spec ''%s''.\n', s );
                    ok = false;
                    return;
                end
                if ~strcmp(tokens{i},'=')
                    complain( 'Unexpected token ''%s'' found where ''='' expected\n', tokens{i} );
                    ok = false;
                    return;
                end
                i = i+1;
                if i > length(tokens)
                    complain( 'Unexpected end of morphogen spec ''%s''.\n', s );
                    ok = false;
                    return;
                end
                paramvalue = tokens{i};
                [paramvalue,count,errmsg] = sscanf( paramvalue, '%f', 1 );
                if count ~= 1
                    complain( 'Unexpected token ''%s'' found where number expected\n', tokens{i} );
                    return;
                end
                mgens(nummgens).(paramname) = paramvalue;
                i = i+1;
                if i > length(tokens)
                    complain( 'Unexpected end of morphogen spec ''%s''.\n', s );
                    ok = false;
                    return;
                end
                switch tokens{i}
                    case ','
                        % Nothing
                    case ')'
                        % Nothing
                    otherwise
                        complain( 'Unexpected token ''%s'' found where '','' or '')'' expected\n', tokens{i} );
                        ok = false;
                        return;
                end
            end
            i = i+1;
        end
    end
end

function toks = tokenise( s, pats )
    toks = {};
    while s
        for i=1:length(pats)
            sp = regexp( s, ['^\s*(', pats{i}, ')\s*(.*)$'], 'tokens' );
            if isempty(sp)
            else
                before = sp{1}{1};
                after = sp{1}{2};
                if before
                    toks{end+1} = before;
                    s = after;
                    break;
                else
                end
            end
        end
    end
end
