# -*- coding: utf-8 -*-
import copy
import os
import re

import simplejson
from jinja2 import Environment, FileSystemLoader
from odoo.models import MetaModel
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
template_loader = FileSystemLoader(searchpath=BASE_DIR + "/templates")
jinja = Environment(loader=template_loader)

from odoo import http
import logging

_logger = logging.getLogger(__name__)


class JDReportController(http.Controller):
    
    @http.route('/v1/jd_report/header_editor', type='http')
    def jd_report_header_editor(self, **kwargs):
        report_id = kwargs.get("id")
        data = {}
        if report_id:
            report_id = int(report_id)
            report = http.request.env['jd.table.report'].browse(report_id)
            data.update({
                'report_id': report.id,
                'name': report.name
            })
        template = jinja.get_template('header_editor.html')
        return template.render(data=data)
    
    @http.route('/store-template', csrf=False, type='json')
    def store_template(self, **kwargs):
        params = http.request.jsonrequest
        report_id = params['report_id']
        report_model = http.request.env['jd.table.report']
        if report_id:
            rec = report_model.browse(int(report_id))
            rec.write({
                'gjshtml': params['gjs-html'],
                'gjscss': params['gjs-css'],
                'gjscomponents': params['gjs-components'],
                'gjsstyles': params['gjs-styles'],
                'gjsassets': params['gjs-assets'],

            })
            return simplejson.dumps({'code': 1, 'msg': 'success'})
        else:
            return simplejson.dumps({'code': 1, 'msg': 'source not found'})

    @http.route('/load-template', csrf=False, type='json')
    def load_template(self, **kwargs):
        params = http.request.jsonrequest
        report_id = params['report_id']
        report_model = http.request.env['jd.table.report']
        data = {}
        if report_id:
            rec = report_model.browse(int(report_id))
            data.update({
                'gjs-html': rec.gjshtml,
                'gjs-css': rec.gjscss,
                'gjs-components': '',
                'gjs-styles': rec.gjsstyles,
                'gjs-assets': rec.gjsassets,
            })
        return simplejson.dumps(data)

    @http.route('/v1/jd_report/sql/save', csrf=False)
    def jd_report_sql_save(self, **kwargs):
        '''
        保存SQL
        :param kwargs:
        :return:
        '''
        source_id = kwargs.get('id')
        sql = kwargs.get('sql')
        if source_id and sql:
            source_mode = http.request.env['jd.table.datasource']
            source = source_mode.browse(int(source_id))
            if source and source.id:
                source.write({'sql': sql})
                return simplejson.dumps({'code': 0, 'msg': 'ok'})

        return simplejson.dumps({'code': 1, 'msg': 'source not found'})

    @http.route('/v1/jd_report/sql_editor')
    def jd_report_open_sql_editor(self, **kwargs):
        '''
        打开sql编辑
        :param kwargs:
        :return:
        '''
        source_id = kwargs.get('id')
        data = {}
        if source_id:
            datasource = http.request.env['jd.table.datasource'].browse(int(source_id))
            data.update({'id': datasource.id, 'sql': datasource.sql, 'name': datasource.name})
        template = jinja.get_template('sql_editor.html')
        return template.render(data=data)

    @http.route('/v1/jd_report/table_def')
    def jd_report_get_table_def(self, **kwargs):
        '''
        获取表格定义数据
        :param kwargs:
        :return:
        '''
        data = {}
        report_id = kwargs.get("id")
        if report_id:
            report = http.request.env['jd.table.report'].browse(int(report_id))
            data.update({
                'name': report.name,
                'number': report.number,
                'state': report.state
            })
            cell_list = []
            for cell in report.cell_list:
                tmp_cell = {
                    'report_id': report.id,
                    'row_index': cell.row_index,
                    'col_index': cell.col_index,
                    'style': cell.style,
                    'value': cell.value,
                    'merge_x1': cell.merge_x1,
                    'merge_y1': cell.merge_y1,
                    'merge_x2': cell.merge_x2,
                    'merge_y2': cell.merge_y2
                }
                cell_list.append(tmp_cell)
            data.update({
                'cell_list': cell_list
            })
        else:
            data = {'code': 1, 'msg': 'report id not found.'}
        return simplejson.dumps({'code': 0, 'msg': 'ok', 'data': data})

    @http.route('/v1/jd_report/editor')
    def jd_report_editor(self, **kwargs):
        report_id = kwargs.get("id")
        data = {}
        if report_id:
            report_id = int(report_id)
            report = http.request.env['jd.table.report'].browse(report_id)
            data.update({
                'report_id': report.id,
                'name': report.name
            })
        template = jinja.get_template('report_editor.html')
        return template.render(data=data)
    
    @http.route('/v1/jd_report/preview')
    def jd_report_preview(self, **kwargs):
        report_id = kwargs.get('id')
        wizard_id = kwargs.get('wizard_id')
        wizard_model = kwargs.get('wizard_model')
        if report_id:
            report = http.request.env['jd.table.report'].sudo().browse(int(report_id))
            data_list, search_content = report.get_dict_data(wizard_id, wizard_model)
            cell_list = []
            for c in report.cell_list:
                merge = {}
                if c.merge_x1 != c.merge_x2 or c.merge_y1 != c.merge_y2:
                    merge.update({
                        'x1': c.merge_x1,
                        'y1': c.merge_y1,
                        'x2': c.merge_x2,
                        'y2': c.merge_y2
                    })
                cell_list.append({
                    'report_id': report.id,
                    'row_index': c.row_index,
                    'col_index': c.col_index,
                    'style': c.style,
                    'value': c.value,
                    'merge': merge
                })
            table = TableReportCell(cell_list, data_list, search_content)
            table_list, group_column_index = table.render()

            last_header = -1
            for x_index in xrange(0, len(table_list)):
                row = table_list[x_index]
                if row and len(row) > 0:
                    for r in row:
                        if 'header' in r.keys()and r['header'] == 1:
                            last_header = x_index
            header_list = []
            if last_header > 0:
                header_list = table_list[0:last_header + 1]
                del table_list[0:last_header + 1]
            else:
                header = table_list[0]
                del table_list[0]
                header_list.append(header)

            template = jinja.get_template('report_view.html')
            groups_index_str = ",".join(str(x) for x in group_column_index)
            html_header = report.gjshtml
            css_header =report.gjscss
            params = {}
            from odoo import models
            for key in search_content.keys():
                # # 说明是关系字段
                # if isinstance(search_content[key], models.Model):
                #     if getattr(search_content[key], 'name'):
                #         search_content[key] = search_content[key].name
                #     elif getattr(search_content[key], 'number'):
                #         search_content[key] = search_content[key].name
                #     else:
                #         search_content[key] = search_content[key]
                # 如果是枚举字段
                params.update({
                    key[1:]: search_content[key]
                })
            if html_header:
                for key in params.keys():
                    html_header = html_header.replace("{{%s}}" % key, str(params[key]))
            _logger.debug('table_list is %s' % table_list)
            max_rowspan = self.get_max_rowspan(header_list)
            fixed_column = report.fixed_column or 0
            sum_js = report.sum_js
            export_filename = report.export_filename
            return template.render(data={'data': table_list, 'headers': header_list, 'groups': groups_index_str,
                                         'html_header': html_header, "css_header": css_header,
                                         'fixed_column': fixed_column, 'max_rowspan': max_rowspan,
                                         'sum_js': sum_js,
                                         'export_filename': export_filename})

    def get_max_rowspan(self, header_list):
        """
        用于显示前端显示序号
        :return:
        """
        rowspan = []
        for header in header_list:
            for row in header:
                if 'row_span' in row.keys():
                    rowspan.append(row['row_span'])
        if rowspan:
            return max(rowspan)
        else:
            return 1

    @http.route('/v1/jd_report/save', csrf=False)
    def jd_save_report(self, **kwargs):
        '''
        保存报表定义
        :param auth:
        :return:
        '''
        data = kwargs.get('data')
        report_id = kwargs.get('id', None)
        data = simplejson.loads(data)
        report = None
        if report_id:
            report_id = int(report_id)
            report = http.request.env['jd.table.report'].browse(report_id)

        if not report.id:
            return simplejson.dumps({'code': 1, 'msg': 'report not found.'})
        else:
            sql = "delete from jd_table_report_cell where report_id=%s"
            http.request.cr.execute(sql, (report_id,))
            cell_model = http.request.env['jd.table.report.cell']
            for row in data:
                for cell in row:
                    cell_val = {
                        'report_id': report_id,
                        'row_index': cell['row_index'],
                        'col_index': cell['col_index'],
                        'style': cell['style'],
                        'value': cell['value']
                    }
                    if 'merge_x1' in cell.keys():
                        cell_val.update({
                            'merge_x1': cell['merge_x1'],
                            'merge_x2': cell['merge_x2'],
                            'merge_y1': cell['merge_y1'],
                            'merge_y2': cell['merge_y2'],
                        })
                    cell_model.create(cell_val)

        return simplejson.dumps({'code': 0, 'msg': 'ok'})


class TableReportCell:

    def __init__(self, cell_def, data_list, searcher):
        self.cell_list = cell_def
        self.data = data_list
        self.search_content = searcher

    def render(self):
        u'''
        数据结构如下：
        根据element_def，封装data成页面可以展示的数据
        :return:
        '''
        data = []
        element_def = []
        final_data = []
        cell_list = self.cell_list
        data_list = self.data
        cell_list = self.translate_cell_def_to_row(cell_list)
        self.compute_merge_cell(cell_list)
        group_fields, group_column_index = self.get_group_fields(cell_list)
        #self.group_data(group_fields, data_list)

        index = 0
        pre_row_data = None
        while index < len(cell_list):
            row = cell_list[index]
            if self.is_list_row(row):
                del cell_list[index]
                for data in data_list:
                    row_def = copy.deepcopy(row)  # 会修改成数据行
                    self.render_list_row(row_def, pre_row_data, data, group_fields)
                    pre_row_data = row_def
                    cell_list.insert(index, row_def)
                    index += 1
                if not data_list:
                    index += 1
            elif self.is_header_row(row):
                # 表格头部
                for cell in row:
                    tag, header_value = None, None
                    if 'value' in cell:
                        tag, header_value = self.get_field_name_from_def(cell['value'])
                    if not tag or not header_value:
                        continue
                    cell.update({'value': header_value, 'header': 1})
                index += 1
            else:
                index += 1

            for cell in row:
                if 'value' not in cell.keys():
                    continue
                tag, cell_value = self.get_field_name_from_def(cell['value'])
                if not tag or not cell_value:
                    continue
                # 填充参数值。
                if self.search_content and tag == 'param':
                    key_list = cell_value.split(".")#获取下级的值，比如user.partner_id.name
                    if key_list[0] in self.search_content.keys():
                        tmp_val = self.search_content[key_list[0]]
                        for x in xrange(1, len(key_list)):
                            key = key_list[x]
                            if hasattr(tmp_val, key):
                                tmp_val = getattr(tmp_val, key)
                        cell.update({'value': tmp_val})



        cell_len = len(cell_list)
        for idx in xrange(0, cell_len):
            row = cell_list[idx]
            for cell in row:
                if cell and 'row_index' in cell.keys():
                    # 第几行,row_index 会改变
                    cell['original_row_index'] = cell['row_index']
                    cell['row_index'] = idx

        self.merge_group_data(cell_list)
        return cell_list, group_column_index

    def compute_merge_cell(self, cell_list):
        '''
        计算合并表格,合并存放格式：merge:[startX,startY,endX,endY]
        :param cell_list:
        :return:
        '''
        for row in cell_list:
            for col in row:
                if 'merge' in col.keys():
                    merge = col['merge']
                    xy_keys = merge.keys()
                    is_next = True
                    if 'x1' in xy_keys and 'x2' in xy_keys and 'y1' in xy_keys and 'y2' in xy_keys:
                        is_next = False

                    if is_next:
                        continue
                    x1 = merge['x1']
                    y1 = merge['y1']
                    x2 = merge['x2']
                    y2 = merge['y2']
                    col_span = x2 - x1
                    row_span = y2 - y1
                    if row_span > 0:
                        col['row_span'] = row_span + 1
                    if col_span > 0:
                        col['col_span'] = col_span + 1

                    for row2 in cell_list:
                        for col2 in row2:
                            if not col2 or 'row_index' not in col2.keys() or 'col_index' not in col2.keys():
                                continue
                            x = col2['col_index']
                            y = col2['row_index']
                            if x1 <= x <= x2 and y1 <= y <= y2:
                                if col != col2:
                                    col2['remove'] = 1
                                    if ('value' not in col.keys() or not col['value']) and 'value' in col2.keys() and \
                                            col2['value']:
                                        col['value'] = col2['value']  # 被删除的元素有数据，没有删除的元素无数据，则把数据放回将要合并，而且不删除的元素中。
                                    if ('original_value' not in col.keys() or not col[
                                        'original_value']) and 'original_value' in col2.keys() and col2[
                                        'original_value']:
                                        col['original_value'] = col2['original_value']

    def render_list_row(self, row_def, pre_row, current_row_data, group_fields):
        '''
        根据行定义，填充行数据。该方法会修改row_def的值。
        :param row_def: 行定义
        :param pre_row: 行列二维数组
        :param current_row_data: 行数据
        :return:
        '''
        group_column_index = []
        col_length = len(row_def)
        for i in xrange(0, col_length):
            col = row_def[i]
            def_val = col['value']
            tag, field_name = self.get_field_name_from_def(def_val)
            if tag == 'group':
                group_column_index.append(i)
            col['field_name'] = field_name
            pre_val = None
            field_val = None
            if pre_row and 'field_name' in pre_row[i].keys() and pre_row[i]['field_name'] == field_name and 'value' in \
                    pre_row[i].keys():
                pre_val = pre_row[i]['value']
            if field_name in current_row_data.keys():
                field_val = current_row_data[field_name]
                col['original_value'] = col['value']
                col['value'] = field_val
            if field_name in group_fields:
                if pre_val == field_val:
                    col['group_pre'] = 1  # 和前一行在同一分组。
                else:
                    col['group_pre'] = 0  # 和前一行在不同分组
        return group_column_index

    def merge_group_data(self, cell_list):
        '''
        合并需要分组的数据
        :param cell_list: 需要分组数据，带有group_pre属性，和前一行数据在相同分组的，group_pre为1，在不同分组的group_pre为0。
        :return:
        '''
        col_len = 0
        if cell_list and len(cell_list) > 0:
            col_len = len(cell_list[0])

        for index in xrange(0, col_len):  # 行合并，按行进行处理
            row_span = 1
            first_group_cel_value = None  # 同一分组的第一行数据
            for row in cell_list:
                group_col_value = row[index]
                if 'group_pre' in group_col_value.keys():
                    if group_col_value['group_pre'] == 0:  # 新的分组
                        if first_group_cel_value:  # 给同一分组的第一行数据 定义跨行数量
                            first_group_cel_value['row_span'] = row_span

                        row_span = 1
                        first_group_cel_value = group_col_value
                    elif group_col_value['group_pre'] == 1:  # 和前面一行在相同分组
                        row_span += 1
                        group_col_value['remove'] = 1  # 删除相同分组后面的数据。

            if first_group_cel_value:  # 最后一个分组的第一行数据，也需要定义跨行数量
                first_group_cel_value['row_span'] = row_span

    def get_field_name_from_def(self, def_val):
        '''
        从元素定义值中获取字段名
        :param def_val:
        :return:
        '''
        group_reg = r'=(group)\((\w+)\)'
        select_reg = r'=(select)\((\w+)\)'
        field_reg = r'=(field)\((\w+)\)'
        header_reg = r'(header)\(([\w\W\u4e00-\u9fff]+)\)'  # 表头包含中文
        param_reg = r'=(param)\(([@?\w+.?]+)\)'
        group_pattern = re.compile(group_reg)
        select_pattern = re.compile(select_reg)
        field_pattern = re.compile(field_reg)
        header_pattern = re.compile(header_reg)
        param_pattern = re.compile(param_reg)
        group_matcher = re.search(group_pattern, def_val)
        select_matcher = re.search(select_pattern, def_val)
        field_matcher = re.search(field_pattern, def_val)
        header_matcher = re.search(header_pattern, def_val)
        param_matcher = re.search(param_pattern, def_val)
        if group_matcher:
            return group_matcher.group(1), group_matcher.group(2)
        elif select_matcher:
            return select_matcher.group(1), select_matcher.group(2)
        elif field_matcher:
            return field_matcher.group(1), field_matcher.group(2)
        elif header_matcher:
            return header_matcher.group(1), header_matcher.group(2)
        elif param_matcher:
            return param_matcher.group(1), param_matcher.group(2)
        return None, None

    def is_list_row(self, def_row):
        '''
        是否包含列表行, 元素定义为:=group(xxx),=select(xxx),=field(field_name)表示是列表行
        :param def_row:
        :param data_row:
        :return:
        '''
        list_func = ['=group', '=select', '=field']
        for col in def_row:
            if col and 'value' in col.keys():
                val = col['value']
                for func in list_func:
                    if val.startswith(func):
                        return True
        return False

    def is_header_row(self, def_row):
        '''
        是否是标题行
        :param def_row:
        :return:
        '''
        list_func = ['header', '=header']
        for col in def_row:
            if col and 'value' in col.keys():
                val = col['value']
                for func in list_func:
                    if val.startswith(func):
                        return True
        return False

    def group_data(self, group_fields, data_list):
        '''
        数据分组排序，分组后的数据。为了方便表格合并，相同分组中的第一行对应的列有值，后面的值都是''。
        :param group_fields:  分组列名
        :param data_list:
        :return:
        '''

        length = len(data_list)
        for field in group_fields:
            i = 0
            while i < length:
                data = data_list[i]
                current_group_val = data[field]
                for j in xrange(i + 1, length):
                    data_relocation = data_list[j]
                    data_val2 = data_relocation[field]
                    if current_group_val == data_val2:
                        del data_list[j]
                        # 把相同值得数据，排在一起
                        data_list.insert(i + 1, data_relocation)
                        i += 1
                i += 1

    def get_group_fields(self, cell_list):
        '''
        获取分组的字段，分组优先级从高到低排序
        :return:
        '''
        group_func_reg = r'=group\((\w+)\)'
        # 把分组的列先找出路，再把数据分组
        group_fields = []
        group_column_index = []
        for row in cell_list:
            col_index = 0
            for col in row:
                col_index += 1
                if not col or 'value' not in col.keys():
                    continue
                cell_val = col['value']
                group_pattern = re.compile(group_func_reg)
                matcher = re.search(group_pattern, cell_val)
                if matcher:
                    field_name = matcher.group(1)
                    group_fields.append(field_name)
                    group_column_index.append(col_index-1)#上面已经执行了col_index += 1
        group_column_index = list(set(group_column_index))
        return group_fields, group_column_index

    def translate_cell_def_to_row(self, cell_list):
        '''
        把行列定义转成行列二维数组，行是第-维，列为第二维。比例[row1,row2,row3,row4]这样。
        row的数据格式:[{value:'',report_id:xx,row_index:23,col_index:32,style:'xxx',origin_value:'xx'}，{value:'',report_id:xx,row_index:23,col_index:32,style:'xxx',origin_value:'xx'}]
        :param cell_list: 报表元素定义列表[{report_id:xx,row_index:xx,col_index:32,style:'2323',value:'=group(aaa,bb)'}]
        :return:[row1,row2,row3,row4], row:[column1, column2,column3], column格式：{value:'',report_id:xx,row_index:23,col_index:32,style:'xxx',origin_value:'xx'}
        '''
        final_data = []
        max_row, max_col = self.get_max_row_column_index(cell_list)
        for row_index in xrange(0, max_row + 1):
            row_list = []
            for col_index in xrange(0, max_col + 1):
                row_list.append({
                    'col_index': col_index,
                    'row_index': row_index
                })
            final_data.append(row_list)

        for cell in cell_list:
            row_index = cell['row_index']
            col_index = cell['col_index']
            final_data[row_index][col_index].update(cell)

        return final_data

    def get_max_row_column_index(self, cell_list):
        '''
        获取最大行和列下标
        :param cell_list: [{report_id:xx,row_index:xx,col_index:32,style:'2323',value:'=group(aaa,bb)'}]
        :return: max row, max column
        '''
        max_row = 0
        max_col = 0
        for cell in cell_list:
            if max_row < cell['row_index']:
                max_row = cell['row_index']
            if max_col < cell['col_index']:
                max_col = cell['col_index']
        return max_row, max_col