define([
    'require'
    , 'jquery'
    , 'nbextensions/visualpython/src/common/vpCommon'
    , 'nbextensions/visualpython/src/common/constant'
    , 'nbextensions/visualpython/src/common/StringBuilder'
    , 'nbextensions/visualpython/src/common/vpFuncJS'
    , 'nbextensions/visualpython/src/container/vpContainer'
    , 'nbextensions/visualpython/src/pandas/common/pandasGenerator'
], function (requirejs, $, vpCommon, vpConst, sb, vpFuncJS, vpContainer, pdGen) {
    // 옵션 속성
    const funcOptProp = {
        stepCount : 1
        , funcName : "Figure 구성"
        , funcID : "mp_figure"  // TODO: ID 규칙 생성 필요
    }

    /**
     * html load 콜백. 고유 id 생성하여 부과하며 js 객체 클래스 생성하여 컨테이너로 전달
     * @param {function} callback 호출자(컨테이너) 의 콜백함수
     */
    var optionLoadCallback = function(callback, meta) {
        // document.getElementsByTagName("head")[0].appendChild(link);
        // 컨테이너에서 전달된 callback 함수가 존재하면 실행.
        if (typeof(callback) === 'function') {
            var uuid = vpCommon.getUUID();
            // 최대 10회 중복되지 않도록 체크
            for (var idx = 0; idx < 10; idx++) {
                // 이미 사용중인 uuid 인 경우 다시 생성
                if ($(vpConst.VP_CONTAINER_ID).find("." + uuid).length > 0) {
                    uuid = vpCommon.getUUID();
                }
            }
            $(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.OPTION_GREEN_ROOM))).find(vpCommon.formatString(".{0}", vpConst.API_OPTION_PAGE)).addClass(uuid);

            // 옵션 객체 생성
            var mpPackage = new MatplotPackage(uuid);
            mpPackage.metadata = meta;

            // 옵션 속성 할당.
            mpPackage.setOptionProp(funcOptProp);
            // html 설정.
            mpPackage.initHtml();
            callback(mpPackage);  // 공통 객체를 callback 인자로 전달
        }
    }
    
    /**
     * html 로드. 
     * @param {function} callback 호출자(컨테이너) 의 콜백함수
     */
    var initOption = function(callback, meta) {
        vpCommon.loadHtml(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.OPTION_GREEN_ROOM)), "matplotlib/figure.html", optionLoadCallback, callback, meta);
    }

    /**
     * 본 옵션 처리 위한 클래스
     * @param {String} uuid 고유 id
     */
    var MatplotPackage = function(uuid) {
        this.uuid = uuid;           // Load html 영역의 uuid.
        this.package = {
            name: 'plt.subplots()',
            code: '${o0}, ax = plt.subplots(${subplotsRows}, ${subplotsCols}${v})',
            input: [
                {
                    name: 'subplotsRows',
                    type: 'int',
                    label: 'Number of Rows',
                    component: 'input_single'
                },
                {
                    name: 'subplotsCols',
                    type: 'int',
                    label: 'Number of Columns',
                    component: 'input_single'
                }
            ],
            output: [
                {
                    name: 'o0',
                    type: 'var',
                    label: 'Figure Variable',
                    component: 'input_single',
                    required: true
                }
            ],
            variable: [
                {
                    name: 'figsize',
                    type: 'var'
                }
            ]
        };
        // cmap 종류
        this.cmap = [
            'viridis', 'plasma', 'inferno', 'magma', 'cividis'
            , 'Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2', 'Set1', 'Set2', 'Set3', 'tab10', 'tab20', 'tab20b', 'tab20c'
        ];
    }



    /**
     * vpFuncJS 에서 상속
     */
    MatplotPackage.prototype = Object.create(vpFuncJS.VpFuncJS.prototype);

    /**
     * 유효성 검사
     * @returns 유효성 검사 결과. 적합시 true
     */
    MatplotPackage.prototype.optionValidation = function() {
        return true;

        // 부모 클래스 유효성 검사 호출.
        // vpFuncJS.VpFuncJS.prototype.optionValidation.apply(this);
    }


    /**
     * html 내부 binding 처리
     */
    MatplotPackage.prototype.initHtml = function() {
        this.showFunctionTitle();

        // 차트 옵션 페이지 구성
        this.bindOption();
        this.bindSubplotRange();

        this.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "pandas/commonPandas.css");
        this.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "matplotlib/figure.css");
    }

    /**
     * 선택한 패키지명 입력
     */
    MatplotPackage.prototype.showFunctionTitle = function() {
        $(this.wrapSelector('.vp_functionName')).text(this.package.name);
    }

    /**
     * 옵션 구성 이벤트 바인딩
     */
    MatplotPackage.prototype.bindOption = function() {
        var that = this;

        //subplots 행/열 입력 시 subplot 박스 추가
        $(this.wrapSelector('#subplotsRows')).change(function() {
            var row = $(that.wrapSelector('#subplotsRows')).val() * 1;
            var col = $(that.wrapSelector('#subplotsCols')).val() * 1;
            // 행/열에 아무것도 입력되어있지 않으면 1
            if (row == 0) row = 1;
            if (col == 0) col = 1;

            $(that.wrapSelector('#subplotsRowsRange')).val(row);

            $(that.wrapSelector('#vp_subplotsGrid')).attr('data-row', row);
            $(that.wrapSelector('#vp_subplotsGrid')).css('height', 80 * row + 'px');
            $(that.wrapSelector('#vp_subplotsGrid')).css('grid-template-rows', 'repeat(' + row + ', 1fr)');

            $(that.wrapSelector('#vp_subplotsGrid')).html('');

            for (var i = 0; i < row * col; i++) {
                var div = document.createElement('div');
                var r = parseInt(i / col);
                var c = i % col;
                $(div).attr({
                    'class': 'grid-item',
                    'data-idx': i,
                    'data-row': r,
                    'data-col': c
                });
                
                var position = i;
                if (row > 1 && col > 1) {
                    position = r + ', ' + c;
                }
                $(div).text('[' + position + ']');
                $(div).click(function(evt) { that.subplotBoxClickHandler(that, evt); });
                $(that.wrapSelector('#vp_subplotsGrid')).append(div);
            }

            // 서브플롯 설정값 초기화
            that.selectedIdx = '0';
            if (row > 1 && col > 1) {
                that.selectedIdx = '0, 0';
            }
            that.subplotOption = [];
            // 서브플롯에 공간 만들기
            for (var i = 0; i < row * col; i++) {
                that.subplotOption.push({idx: i});
            }
        });

        $(this.wrapSelector('#subplotsCols')).change(function() {
            var row = $(that.wrapSelector('#subplotsRows')).val() * 1;
            var col = $(that.wrapSelector('#subplotsCols')).val() * 1;
            // 행/열에 아무것도 입력되어있지 않으면 1
            if (row == 0) row = 1;
            if (col == 0) col = 1;

            $(that.wrapSelector('#subplotsColsRange')).val(col);

            $(that.wrapSelector('#vp_subplotsGrid')).attr('data-col', col);
            $(that.wrapSelector('#vp_subplotsGrid')).css('width', 80 * col + 'px');
            $(that.wrapSelector('#vp_subplotsGrid')).css('grid-template-columns', 'repeat(' + col + ', 1fr)');

            $(that.wrapSelector('#vp_subplotsGrid')).html('');

            for (var i = 0; i < row * col; i++) {
                var div = document.createElement('div');
                var r = parseInt(i / col);
                var c = i % col;
                $(div).attr({
                    'class': 'grid-item',
                    'data-idx': i,
                    'data-row': r,
                    'data-col': c
                });
                
                var position = i;
                if (row > 1 && col > 1) {
                    position = r + ', ' + c;
                }
                $(div).text('[' + position + ']');
                $(div).click(function(evt) { that.subplotBoxClickHandler(that, evt); });
                $(that.wrapSelector('#vp_subplotsGrid')).append(div);
            }

            // 서브플롯 설정값 초기화
            that.selectedIdx = '0';
            if (row > 1 && col > 1) {
                that.selectedIdx = '0, 0';
            }
            that.subplotOption = [];
            // 서브플롯에 공간 만들기
            for (var i = 0; i < row * col; i++) {
                that.subplotOption.push({idx: i});
            }
        });

        
        // subplot 위치 버튼 클릭 시 해당 subplot의 옵션 설정을 위해 다음 페이지로 이동
        // 참고 : vpContainer.js > tabPageShow($(this).index());
        // - #vp_subplot span[data-caption-id="vp_functionDetail"]
        // - #vp_subplotOptional span[data-caption-id="vp_functionDetail"]
        $(this.wrapSelector('#vp_subplotsGrid div')).click(function (evt) {
            that.subplotBoxClickHandler(that, evt);
        });
    }

    /**
     * Subplot 행/열 범위 조정 이벤트
     */
    MatplotPackage.prototype.bindSubplotRange = function() {
        var that = this;
        // range 변경 시 값 표시
        $(this.wrapSelector('#subplotsRowsRange')).change(function() {
            var value = $(this).val();
            $(that.wrapSelector('#subplotsRows')).val(value);
            $(that.wrapSelector('#subplotsRows')).change();
        });
        $(this.wrapSelector('#subplotsColsRange')).change(function() {
            var value = $(this).val();
            $(that.wrapSelector('#subplotsCols')).val(value);
            $(that.wrapSelector('#subplotsCols')).change();
        });
    }

    /**
     * 서브플롯 버튼 클릭 이벤트핸들러
     */
    MatplotPackage.prototype.subplotBoxClickHandler = function(that, event) {
        var target = event.target;
        var parent = $(target).parent();
        // TODO: 설정하고 있던 서브플롯이 있었다면 설정값 저장

        // 다음 옵션 페이지 이동
        var thisPageIdx = $(target).closest(vpConst.OPTION_PAGE).index();
        vpContainer.tabPageShow(thisPageIdx + 1);

        // 다음 옵션 페이지의 위치 설명란에 [0,0] 표기
        var row = $(target).data('row');
        var col = $(target).data('col');
        
        // 표기 : row나 col이 하나라도 1이면 1차원, 그 이상이면 2차원 배열로 접근
        var position = $(target).data('idx');
        var rowLen = $(parent).data('row') * 1;
        var colLen = $(parent).data('col') * 1;
        
        if (rowLen > 1 && colLen > 1) { // TODO: parent().data-row / data-col 받아와야댐
            position = row + ', ' + col;
        }
        // 선택한 서브플롯 인덱스 설정
        that.selectedIdx = position + '';

        $(that.wrapSelector('span[data-caption-id="pageTitle"]'))[1].innerText = 'Subplot [' + position + '] Setting';
        $(that.wrapSelector('span[data-caption-id="pageTitle"]'))[2].innerText = 'Subplot [' + position + '] Add Chart';
    }

    

    /**
     * 색상 스타일 선택지 구현
     */
    MatplotPackage.prototype.bindCmapSelector = function() {
        // 기존 cmap 선택하는 select 태그 안보이게
        var cmapSelector = this.wrapSelector('#cmap');
        $(cmapSelector).hide();

        // cmap 데이터로 팔레트 div 동적 구성
        this.cmap.forEach(ctype => {
            var divColor = document.createElement('div');
            $(divColor).attr({
                'class': 'vp-plot-cmap-item',
                'data-cmap': ctype,
                'data-url': 'pandas/cmap/' + ctype + '.JPG',
                'title': ctype
            });
            $(divColor).text(ctype);
            // 이미지 url 바인딩
            var url = Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.RESOURCE_PATH + 'pandas/cmap/' + ctype + '.JPG';
            $(divColor).css({
                'background-image' : 'url(' + url + ')'
            })

            var selectedCmap = this.wrapSelector('#vp_selectedCmap');

            // 선택 이벤트 등록
            $(divColor).click(function() {
                if (!$(this).hasClass('selected')) {
                    $(this).parent().find('.vp-plot-cmap-item.selected').removeClass('selected');
                    $(this).addClass('selected');
                    // 선택된 cmap 이름 표시
                    $(selectedCmap).text(ctype);
                    // 선택된 cmap data-caption-id 변경
                    $(selectedCmap).attr('data-caption-id', ctype);
                    // select 태그 강제 선택
                    $(cmapSelector).val(ctype).prop('selected', true);
                }
            });
            $(this.wrapSelector('#vp_plotCmapSelector')).append(divColor);
        });

        // 선택 이벤트
        $(this.wrapSelector('.vp-plot-cmap-wrapper')).click(function() {
            $(this).toggleClass('open');
        });
    }

    /**
     * 코드 생성
     * @param {boolean} exec 실행여부
     */
    MatplotPackage.prototype.generateCode = function(addCell, exec) {
        
        var sbCode = new sb.StringBuilder();
        

        // 사용자 옵션 설정값 가져오기
        // var userOption = new sb.StringBuilder();
        // $(this.wrapSelector('#vp_userOption table tr:gt(0):not(:last)')).each(function() {
        //     var key = $(this).find('td:nth-child(1) input').val();
        //     var val = $(this).find('td:nth-child(2) input').val();
        //     userOption.appendFormat(', {0}={1}', key, val);
        // });

        // 코드 생성
        var figureCode = pdGen.vp_codeGenerator(this.uuid, this.package);
        if (figureCode == null) return "BREAK_RUN"; // 코드 생성 중 오류 발생

        sbCode.append(figureCode);
        // cell metadata 작성하기
        // pdGen.vp_setCellMetadata(_VP_CODEMD);
        

        if (addCell) this.cellExecute(sbCode.toString(), exec);

        return sbCode.toString();
    }

    return {
        initOption: initOption
    };
});