#!/usr/bin/python
# -*- coding: utf-8 -*-

#
# Copyright 2011, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import sys

def RemoveAnnotation(line):
    if line.find(":") >= 0:
        annotation = line[line.find(":"): line.find(" ", line.find(":"))]
        return line.replace(annotation, "*")
    else:
        return line

if __name__ == "__main__":
    externs = []
    lines = open("../../../frameworks/base/opengl/libs/GLES2_dbg/gl2_api_annotated.in").readlines()
    output = open("src/com/android/glesv2debugger/MessageParser.java", "w")

    i = 0
    output.write("""\
/*
 ** Copyright 2011, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
 ** You may obtain a copy of the License at
 **
 **     http://www.apache.org/licenses/LICENSE-2.0
 **
 ** Unless required by applicable law or agreed to in writing, software
 ** distributed under the License is distributed on an "AS IS" BASIS,
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */

// auto generated by generate_MessageParser_java.py,
//  which also prints skeleton code for MessageParserEx.java

package com.android.glesv2debugger;

import com.android.glesv2debugger.DebuggerMessage.Message;
import com.android.glesv2debugger.DebuggerMessage.Message.Function;
import com.google.protobuf.ByteString;

import java.nio.ByteBuffer;

public abstract class MessageParser {

    String args;

    String[] getList()
    {
        String arg = args;
        args = args.substring(args.lastIndexOf('}') + 1);
        final int comma = args.indexOf(',');
        if (comma >= 0)
            args = args.substring(comma + 1).trim();
        else
            args = null;

        final int comment = arg.indexOf('=');
        if (comment >= 0)
            arg = arg.substring(comment + 1);
        arg = arg.trim();
        assert arg.charAt(0) == '{';
        arg = arg.substring(1, arg.lastIndexOf('}')).trim();
        return arg.split("\\s*,\\s*");
    }

    ByteString parseFloats(int count) {
        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
        buffer.order(SampleView.targetByteOrder);
        String [] arg = getList();
        for (int i = 0; i < count; i++)
            buffer.putFloat(Float.parseFloat(arg[i].trim()));
        buffer.rewind();
        return ByteString.copyFrom(buffer);
    }

    ByteString parseInts(int count) {
        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
        buffer.order(SampleView.targetByteOrder);
        String [] arg = getList();
        for (int i = 0; i < count; i++)
            buffer.putInt(Integer.parseInt(arg[i].trim()));
        buffer.rewind();
        return ByteString.copyFrom(buffer);
    }

    ByteString parseUInts(int count) {
        ByteBuffer buffer = ByteBuffer.allocate(count * 4);
        buffer.order(SampleView.targetByteOrder);
        String [] arg = getList();
        for (int i = 0; i < count; i++)
            buffer.putInt((int)(Long.parseLong(arg[i].trim()) & 0xffffffff));
        buffer.rewind();
        return ByteString.copyFrom(buffer);
    }

    ByteString parseMatrix(int columns, int count) {
        return parseFloats(columns * columns * count);
    }

    ByteString parseString() {
        // TODO: escape sequence and proper string literal
        String arg = args.substring(args.indexOf('"') + 1, args.lastIndexOf('"'));
        args = args.substring(args.lastIndexOf('"'));
        int comma = args.indexOf(',');
        if (comma >= 0)
            args = args.substring(comma + 1).trim();
        else
            args = null;
        return ByteString.copyFromUtf8(arg);
    }

    String getArgument()
    {
        final int comma = args.indexOf(',');
        String arg = null;
        if (comma >= 0)
        {
            arg = args.substring(0, comma);
            args = args.substring(comma + 1);
        }
        else
        {
            arg = args;
            args = null;
        }
        final int comment = arg.indexOf('=');
        if (comment >= 0)
            arg = arg.substring(comment + 1);
        return arg.trim();
    }

    int parseArgument()
    {
        String arg = getArgument();
        if (arg.startsWith("GL_"))
            return GLEnum.valueOf(arg).value;
        else if (arg.toLowerCase().startsWith("0x"))
            return Integer.parseInt(arg.substring(2), 16);
        else
            return Integer.parseInt(arg);
    }

    int parseFloat()
    {
        String arg = getArgument();
        return Float.floatToRawIntBits(Float.parseFloat(arg));
    }

    public void parse(final Message.Builder builder, String string) {
        int lparen = string.indexOf("("), rparen = string.lastIndexOf(")");
        String s = string.substring(0, lparen).trim();
        args = string.substring(lparen + 1, rparen);
        String[] t = s.split(" ");
        Function function = Function.valueOf(t[t.length - 1]);
        builder.setFunction(function);
        switch (function) {
""")

    abstractParsers = ""

    for line in lines:
        if line.find("API_ENTRY(") >= 0: # a function prototype
            returnType = line[0: line.find(" API_ENTRY(")].replace("const ", "")
            functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
            parameterList = line[line.find(")(") + 2: line.find(") {")]

            parameters = parameterList.split(',')
            paramIndex = 0

            #if returnType != "void":
            #else:

            if parameterList == "void":
                parameters = []
            inout = ""

            paramNames = []
            abstract = False
            argumentSetters = ""
            output.write("\
            case %s:\n" % (functionName))

            for parameter in parameters:
                parameter = parameter.replace("const","")
                parameter = parameter.strip()
                paramType = parameter.split(' ')[0]
                paramName = parameter.split(' ')[1]
                annotation = ""

                argumentParser = ""

                if parameter.find(":") >= 0:
                    dataSetter = ""
                    assert inout == "" # only one parameter should be annotated
                    inout = paramType.split(":")[2]
                    annotation = paramType.split(":")[1]
                    paramType = paramType.split(":")[0]
                    count = 1
                    countArg = ""
                    if annotation.find("*") >= 0: # [1,n] * param
                        count = int(annotation.split("*")[0])
                        countArg = annotation.split("*")[1]
                        assert countArg in paramNames
                    elif annotation in paramNames:
                        count = 1
                        countArg = annotation
                    elif annotation == "GLstring":
                        annotation = annotation
                    else:
                        count = int(annotation)

                    if paramType == "GLfloat":
                        argumentParser = "parseFloats"
                    elif paramType == "GLint":
                        argumentParser = "parseInts"
                    elif paramType == "GLuint":
                        argumentParser = "parseUInts"
                    elif annotation == "GLstring":
                        assert paramType == 'GLchar'
                    elif paramType.find("void") >= 0:
                        assert 1
                    else:
                        assert 0

                    if functionName.find('Matrix') >= 0:
                        columns = int(functionName[functionName.find("fv") - 1: functionName.find("fv")])
                        assert columns * columns == count
                        assert countArg != ""
                        assert paramType == "GLfloat"
                        dataSetter = "builder.setData(parseMatrix(%d, builder.getArg%d()));" % (
                            columns, paramNames.index(countArg))
                    elif annotation == "GLstring":
                        dataSetter = "builder.setData(parseString());"
                    elif paramType.find("void") >= 0:
                        dataSetter = "// TODO"
                        abstract = True
                    elif countArg == "":
                        dataSetter = "builder.setData(%s(%d));" % (argumentParser, count)
                    else:
                        dataSetter = "builder.setData(%s(%d * builder.getArg%d()));" % (
                            argumentParser, count, paramNames.index(countArg))
                    argumentSetters += "\
                %s // %s %s\n" % (dataSetter, paramType, paramName)
                else:
                    if paramType == "GLfloat" or paramType == "GLclampf":
                        argumentSetters += "\
                builder.setArg%d(parseFloat()); // %s %s\n" % (
                    paramIndex, paramType, paramName)
                    elif paramType.find("*") >= 0:
                        argumentSetters += "\
                // TODO: %s %s\n" % (paramType, paramName)
                        abstract = True
                    else:
                        argumentSetters += "\
                builder.setArg%d(parseArgument()); // %s %s\n" % (
                    paramIndex, paramType, paramName)
                paramNames.append(paramName)
                paramIndex += 1

            if not abstract:
                output.write("%s" % argumentSetters)
            else:
                output.write("\
                parse_%s(builder);\n" % functionName)
                abstractParsers += "\
    abstract void parse_%s(Message.Builder builder);\n" % functionName
                print """\
    @Override
    void parse_%s(Message.Builder builder) {
%s    }
""" % (functionName, argumentSetters) # print skeleton code for MessageParserEx

            output.write("\
                break;\n")
    output.write("""\
            default:
                assert false;
        }
    }
""")
    output.write(abstractParsers)
    output.write("\
}""")