/*
    替换 odoo 原生 data_export.js
    增加 sql 导出传参
*/
odoo.define('web.DataExport', function (require) {
    "use strict";
    
    var core = require('web.core');
    var crash_manager = require('web.crash_manager');
    var data = require('web.data');
    var Dialog = require('web.Dialog');
    var framework = require('web.framework');
    var pyeval = require('web.pyeval');
    
    var QWeb = core.qweb;
    var _t = core._t;
    
    var DataExport = Dialog.extend({
        template: 'ExportDialog',
        events: {
            'click .o_expand_parent': function(e) {
                this.on_expand_action(this.records[$(e.target).closest('.o_export_tree_item').data('id')]);
            },
            'click .o_export_tree_item': function(e) {
                e.stopPropagation();
                var $elem = $(e.currentTarget);
    
                var row_index = $elem.prevAll('.o_export_tree_item').length;
                var row_index_level = $elem.parents('.o_export_tree_item').length;
    
                if(e.shiftKey && row_index_level === this.row_index_level) {
                    var minIndex = Math.min(row_index, this.row_index);
                    var maxIndex = Math.max(row_index, this.row_index);
    
                    this.$records.filter(function() { return ($elem.parent()[0] === $(this).parent()[0]); })
                                 .slice(minIndex, maxIndex+1)
                                 .addClass('o_selected')
                                 .filter(':not(:last)')
                                 .each(process_children);
                }
    
                this.row_index = row_index;
                this.row_index_level = row_index_level;
    
                if(e.ctrlKey) {
                    $elem.toggleClass('o_selected').focus();
                } else if(e.shiftKey) {
                    $elem.addClass('o_selected').focus();
                } else {
                    this.$(".o_selected").removeClass("o_selected")
                    $elem.addClass("o_selected").focus();
                }
    
                function process_children() {
                    var $this = $(this);
                    if($this.hasClass('open')) {
                        $this.children('.o_export_tree_item')
                             .addClass('o_selected')
                             .each(process_children);
                    }
                }
            },
            'dblclick .o_export_tree_item': function(e) {
                var $elem = $(e.currentTarget);
                $elem.removeClass('o_selected');
                this.add_field($elem.data('id'), $elem.find('.o_tree_column').first().text());
            },
            'keydown .o_export_tree_item': function(e) {
                e.stopPropagation();
                var $elem = $(e.currentTarget);
                var record = this.records[$elem.data('id')];
    
                switch(e.keyCode || e.which) {
                    case $.ui.keyCode.LEFT:
                        if ($elem.hasClass('open')) {
                            this.on_expand_action(record);
                        }
                        break;
                    case $.ui.keyCode.RIGHT:
                        if (!$elem.hasClass('open')) {
                            this.on_expand_action(record);
                        }
                        break;
                    case $.ui.keyCode.UP:
                        var $prev = $elem.prev('.o_export_tree_item');
                        if($prev.length === 1) {
                            while($prev.hasClass('open')) {
                                $prev = $prev.children('.o_export_tree_item').last();
                            }
                        } else {
                            $prev = $elem.parent('.o_export_tree_item');
                            if($prev.length === 0) {
                                break;
                            }
                        }
    
                        $elem.removeClass("o_selected").blur();
                        $prev.addClass("o_selected").focus();
                        break;
                    case $.ui.keyCode.DOWN:
                        var $next;
                        if($elem.hasClass('open')) {
                            $next = $elem.children('.o_export_tree_item').first();
                        } else {
                            $next = $elem.next('.o_export_tree_item');
                            if($next.length === 0) {
                                $next = $elem.parent('.o_export_tree_item').next('.o_export_tree_item');
                                if($next.length === 0) {
                                    break;
                                }
                            }
                        }
    
                        $elem.removeClass("o_selected").blur();
                        $next.addClass("o_selected").focus();
                        break;
                }
            },
    
            'click .o_add_field': function() {
                var self = this;
                this.$('.o_field_tree_structure .o_selected')
                    .removeClass('o_selected')
                    .each(function() {
                        var $this = $(this);
                        self.add_field($this.data('id'), $this.children('.o_tree_column').text());
                    });
            },
            'click .o_remove_field': function() {
                this.$fields_list.find('option:selected').remove();
            },
            'click .o_remove_all_field': function() {
                this.$fields_list.empty();
            },
            'click .o_move_up': function() {
                var $selected_rows = this.$fields_list.find('option:selected');
    
                var $prev_row = $selected_rows.first().prev();
                if($prev_row.length){
                    $prev_row.before($selected_rows.detach());
                }
            },
            'click .o_move_down': function () {
                var $selected_rows = this.$fields_list.find('option:selected');
    
                var $next_row = $selected_rows.last().next();
                if($next_row.length){
                    $next_row.after($selected_rows.detach());
                }
            },
    
            'click .o_toggle_save_list': function(e) {
                e.preventDefault();
    
                var $saveList = this.$(".o_save_list");
                if($saveList.is(':empty')) {
                    $saveList.append(QWeb.render('Export.SaveList'));
                } else {
                    if($saveList.is(':hidden')) {
                        $saveList.show();
                        $saveList.find(".o_export_list_input").val("");
                    } else {
                        $saveList.hide();
                    }
                }
            },
            'click .o_save_list > button': function(e) {
                var $saveList = this.$(".o_save_list");
    
                var value = $saveList.find("input").val();
                if(!value) {
                    Dialog.alert(this, _t("Please enter save field list name"));
                    return;
                }
    
                var fields = this.get_fields();
                if (fields.length === 0) {
                    return;
                }
    
                $saveList.hide();
    
                var self = this;
                this.exports.create({
                    name: value,
                    resource: this.dataset.model,
                    export_fields: _.map(fields, function (field) {
                        return [0, 0, {name: field}];
                    }),
                }).then(function(export_list_id) {
                    if(!export_list_id) {
                        return;
                    }
                    var $select = self.$(".o_exported_lists_select");
                    if($select.length === 0 || $select.is(":hidden")) {
                        self.show_exports_list();
                    }
                    $select.append(new Option(value, export_list_id));
                });
            },
        },
        init: function(parent, dataset) {
            var options = {
                title: _t("Export Data"),
                buttons: [
                    {text: _t("Export To File"), click: this.export_data, classes: "btn-primary"},
                    {text: _t("Close"), close: true},
                ],
            };
            this._super(parent, options);
            this.records = {};
            this.dataset = dataset;
            this.exports = new data.DataSetSearch(this, 'ir.exports', this.dataset.get_context());
    
            this.row_index = 0;
            this.row_index_level = 0;
            this.fstore = new Map();            // fstore 保存模板字段 store 信息，获取模板时进行保存
            this.export_loc_limit = 5000;       // export_loc_limit 保存 config 信息，导出 widget 加载时获取并保存
            this.export_orm_limit = 50000;      // export_orm_limit 保存 config 信息，导出 widget 加载时获取并保存
            this.export_maintainer = false;     // export_maintainer 保存 config 信息，导出 widget 加载时获取并保存
            this.maintainer = false;            // maintainer 保存 config 信息，导出 widget 加载时获取并保存
    
            // The default for the ".modal_content" element is "max-height: 100%;"
            // but we want it to always expand to "height: 100%;" for this modal.
            // This can be achieved thanks to LESS modification without touching
            // the ".modal-content" rules... but not with Internet explorer (11).
            this.$modal.find(".modal-content").css("height", "100%");
        },
        start: function() {
            var self = this;
            var waitFor = [this._super.apply(this, arguments)];
    
            this.$fields_list = this.$('.o_fields_list');
            this.$import_compat_radios = this.$('.o_import_compat input');
    
            waitFor.push(this.rpc('/web/export/formats', {}).then(do_setup_export_formats));
    
            var got_fields = new $.Deferred();
            this.$import_compat_radios.change(function(e) {
                self.$('.o_field_tree_structure').remove();
                self.rpc("/web/export/get_fields", {
                    model: self.dataset.model,
                    import_compat: $(e.target).val() === 'yes',     // radios 'yes' or '' or 'sql, 'yes': import_compat
                    sql_export: $(e.target).val() === 'sql',        // 'sql': sql_export
                }).done(function (records) {
                    var compatible_fields = _.map(records, function (record) {return record.id});
                    self.$fields_list
                        .find('option')
                        .filter(function () {
                            var option_field = $(this).attr('value');
                            if (compatible_fields.indexOf(option_field) === -1) {
                                return true;
                            }
                        })
                        .remove();
                    got_fields.resolve();
                    self.on_show_data(records);
                });
                self.on_change_mode(); // 提示信息渲染
            }).eq(0).change();
            waitFor.push(got_fields);
    
            waitFor.push(this.getParent().get_active_domain().then(function (domain) {
                if (domain === undefined) {
                    self.ids_to_export = self.getParent().get_selected_ids();
                    self.domain = self.dataset.domain;
                } else {
                    self.ids_to_export = false;
                    self.domain = domain;
                }
                self.on_show_domain();
            }));
    
            waitFor.push(this.show_exports_list());
            
            waitFor.push(this.rpc('/web/export/mtconfig', {}).then(function(cf) { // get mtconfig 获取 config 中导出相关的配置
                self.export_loc_limit = cf.export_loc_limit;
                self.export_orm_limit = cf.export_orm_limit;
                self.export_maintainer = cf.export_maintainer;
                self.maintainer = cf.maintainer;
            }));
            return $.when.apply($, waitFor);
    
            function do_setup_export_formats(formats) {
                var $fmts = self.$('.o_export_format');
    
                _.each(formats, function(format, i) {
                    var $radio = $('<input/>', {type: 'radio', value: format.tag, name: 'o_export_format_name'});
                    var $label = $('<label/>', {html: format.label});
    
                    if (format.error) {
                        $radio.prop('disabled', true);
                        $label.html(_.str.sprintf("%s — %s", format.label, format.error));
                    }
    
                    $fmts.append($("<div/>").append($radio, $label));
                });
    
                self.$export_format_inputs = $fmts.find('input');
                self.$export_format_inputs.first().prop('checked', true);
            }
        },
        show_exports_list: function() {
            if (this.$('.o_exported_lists_select').is(':hidden')) {
                this.$('.o_exported_lists').show();
                return $.when();
            }
    
            var self = this;
            return this.exports.read_slice(['name'], {
                domain: [['resource', '=', this.dataset.model]]
            }).then(function (export_list) {
                if (!export_list.length) {
                    return;
                }
                self.$('.o_exported_lists').append(QWeb.render('Export.SavedList', {'existing_exports': export_list}));
                self.$('.o_exported_lists_select').on('change', function() {
                    self.$fields_list.empty();
                    var export_id = self.$('.o_exported_lists_select option:selected').val();
                    if(export_id) {
                        self.rpc('/web/export/namelist', {
                            model: self.dataset.model,
                            export_id: parseInt(export_id, 10),
                        }).then(do_load_export_field);
                    }
                });
                self.$('.o_delete_exported_list').click(function() {
                    var select_exp = self.$('.o_exported_lists_select option:selected');
                    if(select_exp.val()) {
                        self.exports.unlink([parseInt(select_exp.val(), 10)]);
                        select_exp.remove();
                        self.$fields_list.empty();
                        if (self.$('.o_exported_lists_select option').length <= 1) {
                            self.$('.o_exported_lists').hide();
                        }
                    }
                });
            });
    
            function do_load_export_field(field_list) {
                _.each(field_list, function (field) {
                    self.$fields_list.append(new Option(field.label, field.name));
                    self.fstore.set(field.name, field.store);   // 保存模板字段中各字段的 store 信息
                });
                console.log('======== Update fstore after namelist get ========');
                console.log(self.fstore);
            }
        },
        on_expand_action: function(record) {
            if(!record['children']) {
                return;
            }
    
            var model = record['params']['model'];
            var prefix = record['params']['prefix'];
            var name = record['params']['name'];
            var exclude_fields = [];
            var store = record['store'];
            if(record['relation_field']) {
                exclude_fields.push(record['relation_field']);
            }
    
            if(!record.loaded) {
                var self = this;
                this.rpc("/web/export/get_fields", {
                    model: model,
                    prefix: prefix,
                    parent_name: name,
                    import_compat: this.$import_compat_radios.filter(':checked').val() === 'yes',   // radios: 'yes' or '' or 'sql', 'yes': import_compat
                    parent_field_type : record['field_type'],
                    exclude: exclude_fields,
                    sql_export: this.$import_compat_radios.filter(':checked').val() === 'sql',      // 'sql': sql_export
                    parent_store: store,    // 获取下穿字段时，携带上级关联字段的 store 信息，如果上级关联字段 non_store, 所有下穿字段也应该为 non_store
                }).done(function(results) {
                    record.loaded = true;
                    self.on_show_data(results, record.id);
                });
            } else {
                this.show_content(record.id);
            }
        },
        on_show_domain: function() {
            // this.$('p').first().after(QWeb.render('Export.DomainMessage', {record: this}));
            this.$('p').first().after(QWeb.render('Export.DomainMessagePlus', {record: this}));
        },
        on_change_mode: function() {
            this.$('.o_mode_message').remove();
            this.$('p').first().after(QWeb.render('Export.ModeMessage', {sql_export: this.$import_compat_radios.filter(':checked').val() === 'sql'}));
        },
        on_show_data: function(records, expansion) {
            var self = this;
    
            if(expansion) {
                this.$('.o_export_tree_item[data-id="' + expansion + '"]')
                    .addClass('open')
                    .find('.o_expand_parent')
                    .toggleClass('fa-plus fa-minus')
                    .next()
                    .after(QWeb.render('Export.TreeItems', {'fields': records}));
            } else {
                this.$('.o_left_field_panel').empty().append(
                    $("<div/>").addClass('o_field_tree_structure')
                               .append(QWeb.render('Export.TreeItems', {'fields': records}))
                );
            }
    
            _.extend(this.records, _.object(_.pluck(records, 'id'), records));
            this.$records = this.$(".o_export_tree_item");
            this.$records.each(function(i, el) {
                var $elem = $(el);
                $elem.find('.o_tree_column').first().toggleClass('o_required', !!self.records[$elem.data('id')].required);
            });
        },
        show_content: function(id) {
            var $this = this.$('.o_export_tree_item[data-id="' + id + '"]');
            $this.toggleClass('open');
            var is_open = $this.hasClass('open');
    
            $this.children('.o_expand_parent').toggleClass('fa-minus', !!is_open).toggleClass('fa-plus', !is_open);
    
            var $child_field = $this.find('.o_export_tree_item');
            var child_len = (id.split("/")).length + 1;
            for (var i = 0 ; i < $child_field.length ; i++) {
                var $child = $child_field.eq(i);
                if(!is_open) {
                    $child.hide();
                } else if(child_len === $child_field.eq(i).data('id').split("/").length) {
                    if ($child.hasClass('open')) {
                        $child.removeClass('open');
                        $child.children('.o_expand_parent').removeClass('fa-minus').addClass('fa-plus');
                    }
                    $child.show();
                }
            }
        },
        add_field: function(field_id, string) {
            var $field_list = this.$('.o_fields_list');
            field_id = this.records[field_id].value || field_id;
            if($field_list.find("option[value='" + field_id + "']").length === 0) {
                $field_list.append(new Option(string, field_id));
            }
        },
        get_fields: function() {
            var $export_fields = this.$(".o_fields_list option").map(function() {
                return $(this).val();
            }).get();
            if($export_fields.length === 0) {
                Dialog.alert(this, _t("Please select fields to save export list..."));
            }
            return $export_fields;
        },
        export_data: function() {
            var self = this;
            var export_id = this.$('.o_exported_lists_select option:selected').val()

            var exported_fields = this.$('.o_fields_list option').map(function () {
                return {
                    name: (self.records[this.value] || this).value,
                    label: this.textContent || this.innerText // DOM property is textContent, but IE8 only knows innerText
                };
            }).get();
    
            if (_.isEmpty(exported_fields)) {
                Dialog.alert(this, _t("Please select fields to export..."));
                return;
            }
            var sql_export = this.$import_compat_radios.filter(':checked').val() === 'sql';
            if (sql_export) {
                // 快速导出
                var invalid_fields = [];
                console.log('======== Current exported fields list(records) ========')
                console.log(self.records);
                exported_fields.forEach(function(item, index, array) {
                    var item_name = item['name'];
                    if (item_name.length > 3 && item_name.substring(item_name.length - 3) === '/id') {
                        // company_id/id ==> company_id, self.records: 可导出字段，键为 company_id 而不是 company_id/id
                        item_name = item_name.substring(0, item_name.length - 3);
                    }
                    // 1. 可导出字段中没有（可能是因为下穿字段直接通过模板获取） 或 可导出字段中有，但 non_store（可能是在非快速导出模式中获取的）；
                    // 2. 获取模板时获取到该字段 non_store （直接选择不通过模板获取时没有）。选择到的字段只存在于这两种情况之一。
                    if ((!self.records[item_name] || (self.records[item_name] && !self.records[item_name].store)) && !self.fstore.get(item['name'])) {
                        invalid_fields.push(item['label']);
                    }
                })

                var alert_msg = '';

                invalid_fields.forEach(function(item, index, array) {
                    if (alert_msg === '') {
                        alert_msg += _t('In Sql Quick Export mode, the following fields cannot be exported: ');
                    }
                    if (index < invalid_fields.length - 1) {
                        alert_msg += item + _t(', ');
                    } else {
                        alert_msg += item;
                    }
                })
                // 存在 non_store 字段，提示并提前结束方法，不进入 request
                if (alert_msg) {    
                    alert_msg += _t(' Pelease review chosen fields, remove or replace invalid fields...');
                    Dialog.alert(this, _t(alert_msg));
                    return;
                }
            } else {    // 导入兼容或导出全部数据
                var export_length = 0;
                if (this.ids_to_export && this.ids_to_export.length > 0) {  // 只有非全选时，导出记录 id: ids_to_export[] 有值，直接获取数组长度即为记录数量
                    console.log('Get length from ids_to_export');
                    export_length = this.ids_to_export.length;
                } else {                                                    // 全选时，导出记录为当前符合筛选条件的所有记录，通过 this.dataset._length 可获取
                    console.log('Get length from dataset');
                    export_length = this.dataset._length;
                }
                if (export_length > this.export_loc_limit && !this.maintainer) {    // 导出数量大于本地限制且非维护机进入校验
                    if (export_length > this.export_orm_limit) {    // 导出数量大于 export_orm_limit 只允许使用快速导出
                        alert_msg = _t("Exporting ") + export_length + _t(" records larger than ") + this.export_orm_limit + _t(", only 'Sql Quick Export' mode is usable.");
                        Dialog.alert(this, _t(alert_msg));
                        return;
                    }
                    if (!this.export_maintainer) {      // 导出数量符合导向维护机且未配置维护机 ip
                        alert_msg = _t("Exporting ") + export_length + _t(" records larger than ") + this.export_loc_limit + _t(", only 'Sql Quick Export' mode is usable since 'export maintainer' config is missing. Please contact technical staff to update system config.");
                        Dialog.alert(this, _t(alert_msg));
                        return;
                    }
                }
            }

            exported_fields.unshift({name: 'id', label: 'External ID'});
    
            var export_format = this.$export_format_inputs.filter(':checked').val();
    
            framework.blockUI();
            this.session.get_file({
                url: '/web/export/' + export_format,
                data: {data: JSON.stringify({
                    model: this.dataset.model,
                    fields: exported_fields,
                    export_id: export_id,
                    ids: this.ids_to_export,
                    domain: this.domain,
                    context: pyeval.eval('contexts', [this.dataset._model.context()]),
                    import_compat: this.$import_compat_radios.filter(':checked').val() === 'yes',
                    sql_export: sql_export,     // 增加 sql 导出传参
                })},
                complete: framework.unblockUI,
                error: crash_manager.rpc_error.bind(crash_manager),
            });
        },
    });
    
    return DataExport;
    
    });
    