from arm.material.shader import Shader
import arm.utils

class ShaderData:

    def __init__(self, material):
        self.material = material
        self.contexts = []
        self.global_elems = [] # bone, weight, off
        self.sd = {}
        self.data = {}
        self.data['shader_datas'] = [self.sd]
        self.matname = arm.utils.safesrc(material.name)
        self.sd['name'] = self.matname + '_data'
        self.sd['contexts'] = []

    def add_context(self, props):
        con = ShaderContext(self.material, self.sd, props)
        if con not in self.sd['contexts']:
            for elem in self.global_elems:
                con.add_elem(elem['name'], elem['size'])
            self.sd['contexts'].append(con.get())
        return con

    def get(self):
        return self.data

class ShaderContext:

    def __init__(self, material, shader_data, props):
        self.vert = None
        self.frag = None
        self.geom = None
        self.tesc = None
        self.tese = None
        self.material = material
        self.matname = arm.utils.safesrc(material.name)
        self.shader_data = shader_data
        self.data = {}
        self.data['name'] = props['name']
        self.data['depth_write'] = props['depth_write']
        self.data['compare_mode'] = props['compare_mode']
        self.data['cull_mode'] = props['cull_mode']
        if 'vertex_structure' in props:
            self.data['vertex_structure'] = props['vertex_structure']
        else:
            self.data['vertex_structure'] = [{'name': 'pos', 'size': 3}, {'name': 'nor', 'size': 3}]
        if 'blend_source' in props:
            self.data['blend_source'] = props['blend_source']
        if 'blend_destination' in props:
            self.data['blend_destination'] = props['blend_destination']
        if 'blend_operation' in props:
            self.data['blend_operation'] = props['blend_operation']
        if 'alpha_blend_source' in props:
            self.data['alpha_blend_source'] = props['alpha_blend_source']
        if 'alpha_blend_destination' in props:
            self.data['alpha_blend_destination'] = props['alpha_blend_destination']
        if 'alpha_blend_operation' in props:
            self.data['alpha_blend_operation'] = props['alpha_blend_operation']
        if 'color_write_red' in props:
            self.data['color_write_red'] = props['color_write_red']
        if 'color_write_green' in props:
            self.data['color_write_green'] = props['color_write_green']
        if 'color_write_blue' in props:
            self.data['color_write_blue'] = props['color_write_blue']
        if 'color_write_alpha' in props:
            self.data['color_write_alpha'] = props['color_write_alpha']

        self.data['texture_units'] = []
        self.tunits = self.data['texture_units']
        self.data['constants'] = []
        self.constants = self.data['constants']

    def add_elem(self, name, size):
        elem = { 'name': name, 'size': size }
        if elem not in self.data['vertex_structure']:
            self.data['vertex_structure'].append(elem)
            self.sort_vs()

    def sort_vs(self):
        # TODO: sort vertex data
        vs = []
        ar = ['pos', 'nor', 'tex', 'tex1', 'col', 'tang', 'bone', 'weight', 'off']
        for ename in ar:  
            elem = self.get_elem(ename)
            if elem != None:
                vs.append(elem)
        self.data['vertex_structure'] = vs

    def is_elem(self, name):
        for elem in self.data['vertex_structure']:
            if elem['name'] == name:
                return True
        return False

    def get_elem(self, name):
        for elem in self.data['vertex_structure']:
            if elem['name'] == name:
                return elem
        return None

    def get(self):
        return self.data

    def add_constant(self, ctype, name, link=None):
        for c in self.constants:
            if c['name'] == name:
                return

        c = { 'name': name, 'type': ctype }
        if link != None:
            c['link'] = link
        self.constants.append(c)

    def add_texture_unit(self, ctype, name, link=None, is_image=None):
        for c in self.tunits:
            if c['name'] == name:
                return

        c = { 'name': name }
        if link != None:
            c['link'] = link
        if is_image != None:
            c['is_image'] = is_image
        self.tunits.append(c)

    def make_vert(self):
        self.data['vertex_shader'] = self.matname + '_' + self.data['name'] + '.vert'
        self.vert = Shader(self, 'vert')        
        return self.vert

    def make_frag(self):
        self.data['fragment_shader'] = self.matname + '_' + self.data['name'] + '.frag'
        self.frag = Shader(self, 'frag')
        return self.frag

    def make_geom(self):
        self.data['geometry_shader'] = self.matname + '_' + self.data['name'] + '.geom'
        self.geom = Shader(self, 'geom')
        return self.geom

    def make_tesc(self):
        self.data['tesscontrol_shader'] = self.matname + '_' + self.data['name'] + '.tesc'
        self.tesc = Shader(self, 'tesc')
        return self.tesc

    def make_tese(self):
        self.data['tesseval_shader'] = self.matname + '_' + self.data['name'] + '.tese'
        self.tese = Shader(self, 'tese')
        return self.tese
