#!/usr/bin/python
# Copyright 2016 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# gen_format_map.py:
#  Code generation for GL format map. The format map matches between
#  {format,type} and internal format.

from datetime import date
import sys

sys.path.append('renderer')
import angle_format

template_cpp = """// GENERATED FILE - DO NOT EDIT.
// Generated by {script_name} using data from {data_source_name}.
// ES3 format info from {es3_data_source_name}.
//
// Copyright {copyright_year} The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// format_map:
//   Determining the sized internal format from a (format,type) pair.
//   Also check es3 format combinations for validity.

#include "angle_gl.h"
#include "common/debug.h"

namespace gl
{{

GLenum GetSizedFormatInternal(GLenum format, GLenum type)
{{
    switch (format)
    {{
{format_cases}        case GL_NONE:
            return GL_NONE;

        default:
            break;
    }}

    return GL_NONE;
}}

bool ValidES3Format(GLenum format)
{{
    switch (format)
    {{
{es3_format_cases}            return true;

        default:
            return false;
    }}
}}

bool ValidES3Type(GLenum type)
{{
    switch (type)
    {{
{es3_type_cases}            return true;

        default:
            return false;
    }}
}}

bool ValidES3FormatCombination(GLenum format, GLenum type, GLenum internalFormat)
{{
    ASSERT(ValidES3Format(format) && ValidES3Type(type));

    switch (format)
    {{
{es3_combo_cases}        default:
            UNREACHABLE();
            break;
    }}

    return false;
}}

}}  // namespace gl
"""

template_format_case = """        case {format}:
            switch (type)
            {{
{type_cases}                default:
                    break;
            }}
            break;

"""

template_simple_case = """                case {key}:
                    return {result};
"""

template_es3_combo_type_case = """                case {type}:
                {{
                    switch (internalFormat)
                    {{
{internal_format_cases}                            return true;
                        default:
                            break;
                    }}
                    break;
                }}
"""

def parse_type_case(type, result):
    return template_simple_case.format(
        key = type, result = result)

def parse_format_case(format, type_map):
    type_cases = ""
    for type, internal_format in sorted(type_map.iteritems()):
        type_cases += parse_type_case(type, internal_format)
    return template_format_case.format(
        format = format, type_cases = type_cases)

input_script = 'format_map_data.json'

format_map = angle_format.load_json(input_script)

format_cases = ""

for format, type_map in sorted(format_map.iteritems()):
    format_cases += parse_format_case(format, type_map)

combo_data_file = 'es3_format_type_combinations.json'
es3_combo_data = angle_format.load_json(combo_data_file)
combo_data = [combo for sublist in es3_combo_data.values() for combo in sublist]

types = set()
formats = set()
combos = {}

for internal_format, format, type in combo_data:
    types.update([type])
    formats.update([format])
    if format not in combos:
        combos[format] = {}
    if type not in combos[format]:
        combos[format][type] = [internal_format]
    else:
        combos[format][type] += [internal_format]

es3_format_cases = ""

for format in sorted(formats):
    es3_format_cases += "        case " + format + ":\n"

es3_type_cases = ""

for type in sorted(types):
    es3_type_cases += "        case " + type + ":\n"

es3_combo_cases = ""

for format, type_combos in combos.iteritems():
    this_type_cases = ""
    for type, combos in type_combos.iteritems():
        internal_format_cases = ""
        for internal_format in combos:
            internal_format_cases += "                        case " + internal_format + ":\n"

        this_type_cases += template_es3_combo_type_case.format(
            type = type, internal_format_cases = internal_format_cases)

    es3_combo_cases += template_format_case.format(
        format = format, type_cases = this_type_cases)

with open('format_map_autogen.cpp', 'wt') as out_file:
    output_cpp = template_cpp.format(
        script_name = sys.argv[0],
        data_source_name = input_script,
        es3_data_source_name = combo_data_file,
        copyright_year = date.today().year,
        format_cases = format_cases,
        es3_format_cases = es3_format_cases,
        es3_type_cases = es3_type_cases,
        es3_combo_cases = es3_combo_cases)
    out_file.write(output_cpp)
