define(
    [
        'table',
        'buttons',
        'utils'
    ],
    function (table, buttons, utils) {
        "use strict";

        table.extend('extend', (function() {
            function TableExtend() {
                this.table = null;
                this.events = ['extend', 'reduce'];
                this.rows = {
                    enable: false,
                    max: 20,
                    controls: {
                        height: 40,
                        add: {
                            html: '+',
                            label: 'Add row'
                        },
                        del: {
                            html: '&#8722;',
                            label: 'Delete row'
                        }
                    }
                };
                this.cols = {
                    enable: false,
                    max: 20,
                    controls: {
                        width: 40,
                        add: {
                            html: '+',
                            label: 'Add col'
                        },
                        del: {
                            html: '&#8722;',
                            label: 'Delete col'
                        }
                    }
                };
            }

            TableExtend.prototype.init = function() {
                if (this.cols.enable) {
                    this.initColControls();
                }
                if (this.rows.enable) {
                    this.initRowControls();
                }
            };

            TableExtend.prototype.initRowControls = function() {
                var control, container;

                control = document.createElement('div');
                control.className = 'table-extend-controls table-extend-controls-row';
                control.style.height = this.rows.controls.height + 'px';

                container = document.createElement('div');
                container.className = 'table-container-lower';

                Object.assign(this.rows.controls.add, {
                    type: 'add-row',
                    classes: ['btn-no-style', 'btn-table-control'],
                    click: utils.triggerCustomEvent.bind(null, container, 'extend', {type: 'row'})
                });
                this.rows.controls.add = buttons.construct(this.rows.controls.add);
                control.appendChild(this.rows.controls.add.el);

                Object.assign(this.rows.controls.del, {
                    type: 'delete-row',
                    classes: ['btn-no-style', 'btn-table-control'],
                    click: utils.triggerCustomEvent.bind(null, container, 'reduce', {type: 'row'})
                });
                this.rows.controls.del = buttons.construct(this.rows.controls.del);
                control.appendChild(this.rows.controls.del.el);

                container.appendChild(control);
                container.insertAdjacentHTML('beforeend', '<div></div>');

                this.table.container.appendChild(container);
            };

            TableExtend.prototype.initColControls = function() {
                var control, container;

                control = document.createElement('div');
                control.className = 'table-extend-controls table-extend-controls-col';
                control.style.width = this.cols.controls.width + 'px';

                container = document.createElement('div');
                container.className = 'table-container-upper';

                Object.assign(this.cols.controls.add, {
                    type: 'add-col',
                    classes: ['btn-no-style', 'btn-table-control'],
                    click: utils.triggerCustomEvent.bind(null, container, 'extend', {type: 'col'})
                });
                this.cols.controls.add = buttons.construct(this.cols.controls.add);
                control.appendChild(this.cols.controls.add.el);

                Object.assign(this.cols.controls.del, {
                    type: 'delete-col',
                    classes: ['btn-no-style', 'btn-table-control'],
                    click: utils.triggerCustomEvent.bind(null, container, 'reduce', {type: 'col'})
                });
                this.cols.controls.del = buttons.construct(this.cols.controls.del);
                control.appendChild(this.cols.controls.del.el);

                container.appendChild(this.table.el);
                container.appendChild(control);

                this.table.container.appendChild(container);
            };

            TableExtend.prototype.addRow = function(data, row) {
                if (this.table.rows.num == this.table.rows.max) { return false; }

                row = row || this.table.rows.num++;

                //update content with data or array of empty objects if non passed
                this.table.content.push(data || utils.getPopulatedArray(this.table.cols.num, {}));

                //create and append new row
                this.table.rows.dom.push(table.create(this.table, this.table.content[row]));
                this.table.body.appendChild(this.table.rows.dom[row]);

                //add col dom refs
                this.table.cols.dom.forEach(function(col, i) {
                    col.push(this.table.rows.dom[row].children[i]);
                }.bind(this));
            };

            TableExtend.prototype.addCol = function(data, col) {
                if (this.table.cols.num == this.table.cols.max) { return false; }

                col = col || this.table.cols.num++;

                this.table.cols.dom.push([]);
                this.table.content.forEach(function(row, i) {
                    //update content with data or empty object if non passed
                    row.push(Array.isArray(data) ? data[i] : {});

                    //create and append new cell
                    this.table.rows.dom[i].appendChild(table.create(this.table, this.table.content[i][col], i));

                    //add col dom ref
                    this.table.cols.dom[col].push(this.table.rows.dom[i].lastChild);
                }.bind(this));
            };

            TableExtend.prototype.deleteRow = function() {
                if (this.table.rows.num == this.table.rows.initial) { return false; }

                this.table.rows.num--;
                this.table.content.pop();

                this.table.body.removeChild(this.table.rows.dom[this.table.rows.num]);

                this.table.rows.dom.pop();
                this.table.cols.dom.forEach(function(col) {
                    col.pop();
                });
            };

            TableExtend.prototype.deleteCol = function() {
                if (this.table.cols.num == this.table.cols.initial) { return false; }

                this.table.cols.num--;
                this.table.content.forEach(function(row) {
                    row.pop();
                });

                this.table.cols.dom.pop();
                this.table.rows.dom.forEach(function(row) {
                    row.removeChild(row.lastChild);
                }.bind(this));

                utils.resize_iframe();
            };

            TableExtend.prototype.update = function() {
                var row = this.table.content.splice(this.table.rows.num);
                var col = [];

                this.table.content.forEach(function(data) {
                    data = data.splice(this.table.cols.num);

                    data.forEach(function(data, i) {
                        col[i] = col[i] || [];
                        col[i].push(data);
                    });
                }.bind(this));

                col.forEach(function(data) {
                    this.addCol(data);
                }.bind(this));

                row.forEach(function(data) {
                    this.addRow(data);
                }.bind(this));
            };

            TableExtend.prototype.reset = function() {
                while (this.table.rows.num > this.table.rows.initial) {
                    this.deleteRow();
                }

                while (this.table.cols.num > this.table.cols.initial) {
                    this.deleteCol();
                }
            };

            TableExtend.prototype.handleEvent = function(e) {
                switch (e.type) {
                    case 'data-loaded':
                        this.update();
                        break;
                    case 'extend':
                        if (e.detail.type == 'col') {
                            this.addCol();
                        }
                        else {
                            this.addRow();
                        }
                        break;
                    case 'reduce':
                        if (e.detail.type == 'col') {
                            this.deleteCol();
                        }
                        else {
                            this.deleteRow();
                        }
                        break;
                    case 'reset':
                        this.reset();
                }
            };

            return {
                construct: function() {
                    return new TableExtend();
                }
            };
        })());
    }
);