(function($){
    "use strict";

    $.pixeTypoSettings = {

        tabHead: false,
        tabContent: false,
        isChanged: false,

        // initiate content
        init: function(settings){
            if( !pixeData.typoPreset ){ return; }

            settings = $.extend({
            }, settings);

            var t = this;
            t.isChanged = false;
            
            var container = $('<div class="pixe-typo-settings pixe-box-sizing" ></div>');
            var tab = $('<div class="pixe-settings-tab" ></div>');
            var activeTab = '';
            tab.appendTo(container);

            // init header area
            t.tabHead = $('<div class="pixe-settings-tab-head" ></div>');
            if( settings.type == 'preset' ){
                t.tabHead.append(pixei18n.preset.typos);
                activeTab = 'preset';
            }else{
                t.tabHead.append('<span data-tab="google-font" >Google Fonts</span>');
                t.tabHead.append('<span data-tab="custom-font" >Custom Fonts</span>');
                activeTab = 'google-font';
            }
            tab.append(t.tabHead);
            
            // init content area
            t.tabContent = $('<div class="pixe-settings-tab-content" ></div>');
            t.changeTab(activeTab);
            tab.append(t.tabContent);

            // get content
            t.tabHead.on('click', '[data-tab]', function(){
                t.changeTab($(this).attr('data-tab'));
            });
            
            // popup
            if( settings.container ){
                settings.container.append(container);
            }else{
                var lb = new $.pixeLightboxPopup({
                    class: 'pixe-lb-typo-settings',
                    content: container,
                    onClose: function(){
                        if( !t.isChanged ) return; 
                        
                        // sync variable with iframe
                        $.pixeTypoStyle.setPresetStyle();

                        if( $.pixeBuilder ){

                            // update to children frame
                            $.pixeBuilder.setIframeData(['typoPreset']);

                            // update typography settings (if exists)
                            $.pixeBuilder.settingsPanel.panel.find('.pixe-sselector-typo-content .pixe-device-selector').trigger('viewport-update');
                        }
                    }
                });

                t.tabHead.append($.pixeGetAdminIcon('cancel', { class: 'pixe-close' }));
                t.tabHead.on('click', '.pixe-close', function(){
                    lb.close();
                });
            }

        },

        // change font settings tab
        changeTab: function(activeTab){
            var t = this;
            var tab = t.tabHead.find('[data-tab="' + activeTab + '"]');

            if( tab.hasClass('pixe-active') ) return;
            tab.addClass('pixe-active').siblings().removeClass('pixe-active');

            switch(activeTab){
                case 'preset':
                    t.getPresetTab();
                    break;
                case 'google-font':
                    t.getGoogleFontTab();
                    break;
                case 'custom-font':
                    t.getCustomFontTab();
                    break;
            }
        },

        // custom font tab
        getCustomFontTab: function(activeFont = ''){

            function getCustomTitle(title = '', active = false){
                var html  = '<div class="' + (active? 'pixe-active': '') + '" data-font-id="' + $.pixeEscAttr(title) + '" >';
                    html += '<span class="pixe-text" >' + $.pixeEscHtml(title) + '</span>';
                    html += '</div>';
                return html;
            }
            function updateEmptyState(){
                if( customFont.find('[data-font-id]').length ){
                    container.removeClass('pixe-empty');
                    container.children('.pixe-message-content-empty').remove();
                }else{
                    container.addClass('pixe-empty');
                    if( !container.children('.pixe-message-content-empty').length ){
                        container.prepend($.pixeEmptyNotice('custom-font'));
                    }
                }
            }

            var t = this;
            t.activeFont = activeFont;
            
            // init area
            var container = $('<div class="pixe-custom-font-settings" ></div>');
            t.tabContent.empty();
            t.tabContent.append(container);

            // option area
            var customFontWrap = $('<div class="pixe-custom-font-option" ></div>');
            var customFont = $('<div class="pixe-content pixe-scrollbar"></div>');
            container.append(customFontWrap.append(customFont));
            
            // custom font
            for( var slug in pixeData.typoPreset.customFont ){
                if( t.activeFont == '' ){ t.activeFont = slug; }
                
                var isActive = (t.activeFont == slug);
                customFont.append(getCustomTitle(slug, isActive));
            }

            // content area
            var content = $('<div class="pixe-custom-font-content pixe-scrollbar" ></div>');
            container.append(content);
            t.getCustomFontContent(content, t.activeFont);

            updateEmptyState();

            // change font
            customFont.on('click', '[data-font-id]', function(){
                if( $(this).hasClass('pixe-active') ) return;
                $(this).addClass('pixe-active').siblings().removeClass('pixe-active');

                t.activeFont = $(this).attr('data-font-id');
                t.getCustomFontContent(content, t.activeFont);
            });
            t.bindCustomFontHeaderEvents(content, customFont, getCustomTitle, updateEmptyState);

            // add new font
            var addNew = $('<div class="pixe-preset-new" ></div>');
            var html  = '<label>Add New Font</label>';
                html += '<div class="pixe-input" ><input type="text" data-field="name" placeholder="Font Name..." /></div>';
                html += '<div class="pixe-ss-button" >Create Font</div>';
            container.append(addNew.append(html));

            // add new event
            addNew.on('click', '.pixe-ss-button', function(){
                var input = addNew.find('input[type="text"]');
                var name = input.val().trim();
                
                // invalid name
                if( name.length == 0 || !$.pixeIsNameValid(name) ){
                    $.pixeConfirmationBox({
                        title: 'Invalid Name',
                        message: 'Please use only English characters, number or space in your font name.',
                        cancelText: ''
                    });
                    return;
                }

                if( !pixeData.typoPreset.customFont[name] ){

                    // add data
                    pixeData.typoPreset.customFont[name] = [];
                    
                    // add item
                    var item = $(getCustomTitle(name));
                    customFont.append(item);
                    updateEmptyState();
                    item.trigger('click');

                    // clear input 
                    input.val('');

                    t.updateData();
                }else{
                    $.pixeConfirmationBox({
                        title: 'Font Already Existed',
                        message: 'Please fill another name to create new custom font.',
                        cancelText: ''
                    });
                    return;
                }
            });
            addNew.on('keydown', 'input[type="text"]', function(e){
                if( e.keyCode == 13 ){
                    e.preventDefault();
                    addNew.find('.pixe-ss-button').trigger('click');
                }
            });

        },
        getCustomFontContent: function(customFontContent, activeFont){

            // clear old data
            customFontContent.empty();
            if( !activeFont ) return;

            var t = this;
            customFontContent.append(t.getCustomFontHeader(activeFont));

            var form = $('<div class="pixe-form pixe-clearfix" ></div>');
            customFontContent.append(form);

            function updateFontData(){
                pixeData.typoPreset.customFont[activeFont] = [];
                form.find('.pixe-custom-font-item').each(function(){
                    var value = $.pixeGetVal($(this));
                    pixeData.typoPreset.customFont[activeFont].push({
                        value: value,
                        style: $.pixeTypoStyle.getCustomFontFace(activeFont, value)
                    });
                });
                t.updateData();
            }

            // add item
            for( var i in pixeData.typoPreset.customFont[activeFont] ){
                var fontItem = t.getCustomFontItem(pixeData.typoPreset.customFont[activeFont][i]);
                fontItem.removeClass('pixe-active');
                form.append(fontItem);
            }
            form.pixeCombobox();

            // on save
            form.on('change', '.pixe-combobox, input[type="text"]', function(){
                updateFontData();
            });

            // add new style
            var addNew = $('<div class="pixe-preset-subitem-new" >' + $.pixeGetAdminIcon('plus') + 'Add Variant</div>');
            form.append(addNew);

            addNew.on('click', function(){
                var fontItem = t.getCustomFontItem({value: {weight: 400, style: 'normal'}});
                fontItem.css('display', 'none');
                fontItem.insertBefore($(this));
                fontItem.slideDown(150);
                form.pixeCombobox();
                updateFontData();
            });

            // remove style
            form.on('click', '.pixe-remove', function(){
                var fontItem = $(this).closest('.pixe-custom-font-item');

                $.pixeConfirmationBox({
                    title: 'Remove Custom Font Style',
                    message: 'You are about to remove the Custom Font Style. Please note that this process cannot be undone.',
                    onSuccess: function(){
                        fontItem.slideUp(150, function(){ 
                            $(this).remove(); 
                            updateFontData();
                        });
                    }
                });
            });

        },
        getNextCustomFontName: function(name){
            var baseName = name || 'Custom Font';
            var newName = baseName + ' Copy';
            var index = 2;

            while( pixeData.typoPreset.customFont[newName] ){
                newName = baseName + ' Copy ' + index;
                index++;
            }

            return newName;
        },
        getCustomFontHeader: function(activeFont){
            var html  = '<div class="pixe-preset-item-header" >';
                html += '<label>Custom Font</label>';
                html += '<div class="pixe-actions" >';
                html += $.pixeGetAdminIcon('copy', {class: 'pixe-copy'});
                html += $.pixeGetAdminIcon('edit', {class: 'pixe-edit'});
                html += $.pixeGetAdminIcon('check', {class: 'pixe-submit pixe-with-bg pixe-hidden'});
                html += $.pixeGetAdminIcon('cancel', {class: 'pixe-cancel pixe-with-bg pixe-hidden'});
                html += $.pixeGetAdminIcon('remove', {class: 'pixe-remove'});
                html += '</div>';
                html += '<div class="pixe-name" >';
                html += '<span>' + $.pixeEscHtml(activeFont) + '</span>';
                html += '<div class="pixe-input" style="display: none;" ><input type="text" data-field="name" value="' + $.pixeEscAttr(activeFont) + '" /></div>';
                html += '</div>';
                html += '</div>';

            return html;
        },
        bindCustomFontHeaderEvents: function(content, customFont, getCustomTitle, updateEmptyState){
            var t = this;

            // copy active font
            content.on('click', '.pixe-preset-item-header .pixe-copy', function(){
                var oldName = t.activeFont;
                var newName = t.getNextCustomFontName(oldName);

                pixeData.typoPreset.customFont[newName] = $.pixeClone(pixeData.typoPreset.customFont[oldName]);

                var item = $(getCustomTitle(newName));
                customFont.append(item);
                item.trigger('click');

                t.updateData();
            });

            // edit font name
            content.on('click', '.pixe-preset-item-header .pixe-edit', function(){
                var header = content.find('.pixe-preset-item-header');

                header.find('.pixe-copy, .pixe-edit, .pixe-remove').addClass('pixe-hidden');
                header.find('.pixe-submit, .pixe-cancel').removeClass('pixe-hidden');
                header.find('.pixe-name span').hide();
                header.find('.pixe-input').show();
                header.find('[data-field="name"]').focus().select();
            });

            // cancel font name edit
            content.on('click', '.pixe-preset-item-header .pixe-cancel', function(){
                t.getCustomFontContent(content, t.activeFont);
            });

            // change font name
            content.on('click', '.pixe-preset-item-header .pixe-submit', function(){
                var input = content.find('[data-field="name"]');
                var name = input.val().trim();
                var oldName = t.activeFont;

                if( name.length == 0 || !$.pixeIsNameValid(name) ){
                    $.pixeConfirmationBox({
                        title: 'Invalid Name',
                        message: 'Please use only English characters, number or space in your font name.',
                        cancelText: ''
                    });
                    return;
                }

                if( name != oldName && pixeData.typoPreset.customFont[name] ){
                    $.pixeConfirmationBox({
                        title: 'Font Already Existed',
                        message: 'Please fill another name to create new custom font.',
                        cancelText: ''
                    });
                    return;
                }

                if( name != oldName ){
                    pixeData.typoPreset.customFont[name] = pixeData.typoPreset.customFont[oldName];
                    delete pixeData.typoPreset.customFont[oldName];
                    t.activeFont = name;

                    customFont.find('[data-font-id="' + oldName + '"]')
                        .attr('data-font-id', name)
                        .find('.pixe-text')
                        .html(name);
                }

                t.getCustomFontContent(content, t.activeFont);
                t.updateData();
            });

            // submit/cancel font name edits with keyboard
            content.on('keydown', '[data-field="name"]', function(e){
                if( e.key == 'Enter' ){
                    content.find('.pixe-preset-item-header .pixe-submit').trigger('click');
                }

                if( e.key == 'Escape' ){
                    t.getCustomFontContent(content, t.activeFont);
                }
            });

            // remove active font
            content.on('click', '.pixe-preset-item-header .pixe-remove', function(){
                var fontId = t.activeFont;
                var fontItem = customFont.find('[data-font-id="' + fontId + '"]');

                $.pixeConfirmationBox({
                    title: 'Remove Custom Font',
                    message: 'You are about to remove the Custom Font. Please note that this process cannot be undone.',
                    onSuccess: function(){
                        fontItem.remove();
                        updateEmptyState();
                        
                        delete pixeData.typoPreset.customFont[fontId];
                        t.activeFont = Object.keys(pixeData.typoPreset.customFont)[0] || '';
                        t.getCustomFontContent(content, t.activeFont);
                        customFont.find('[data-font-id="' + t.activeFont + '"]').addClass('pixe-active').siblings().removeClass('pixe-active');
                        t.updateData();
                    }
                });
            });
        },
        getCustomFontItem: function(settings = {}){
            if( !settings ) return;
            var value = settings.value? settings.value: {};

            function getFontWeightText(weight){
                var fontWeights = {
                    '100': 'Thin',
                    '200': 'Extra Light',
                    '300': 'Light',
                    '400': 'Normal',
                    '500': 'Medium',
                    '600': 'Semi Bold',
                    '700': 'Bold',
                    '800': 'Extra Bold',
                    '900': 'Black',
                    '950': 'Extra Black'
                };

                return weight + (fontWeights[weight]? ' ' + fontWeights[weight]: '');
            }
            function getFontFileText(value, types){
                var count = 0;
                var total = Object.keys(types).length;

                for( var type in types ){
                    if( value[type] ){
                        count++;
                    }
                }

                return count + ' / ' + total + ' files';
            }

            // html content
            var html;
            var types = {
                'woff2': 'WOFF2 · Recommended', 
                'woff': 'WOFF', // 'ttf': 'TTF', 'otf': 'OTF'
            };
            var fontItem = $('<div class="pixe-custom-font-item pixe-active" ></div>');
            var fontHead = $('<div class="pixe-custom-font-item-head pixe-no-user-select" ></div>');
            var fontStyle = value.style? value.style: 'normal';
            var fontWeight = value.weight? value.weight: '400';

            html  = '<span class="pixe-text" >';
            html += $.pixeGetAdminIcon('toggle-close', {class: 'pixe-toggle-icon'});
            html += '<span class="pixe-title" style="font-style: ' + fontStyle + '; font-weight: ' + fontWeight + ';" >Aa</span>';
            html += '<span class="pixe-value" data-type="style" >' + fontStyle + '</span>';
            html += '<span class="pixe-dot" >·</span>';
            html += '<span class="pixe-value" data-type="weight" >' + getFontWeightText(fontWeight) + '</span>';
            html += '</span>';
            html += '<span class="pixe-text-right" >';
            html += '<span class="pixe-file-count" >' + getFontFileText(value, types) + '</span>';
            html += '<span class="pixe-remove" >' + $.pixeGetAdminIcon('remove') + '</span>';
            html += '</span>';
            fontHead.append(html);
            fontHead.appendTo(fontItem);

            var fontContent = $('<div class="pixe-custom-font-item-content pixe-clearfix" ></div>');
            html  = '<div class="pixe-box-float" data-width="1-2" >';
            html += '<label>Font Style</label>';
            html += $.pixeCombobox({
                slug: 'style',
                value: value.style,
                options: $.pixeComboboxOption.fontStyle(false)
            });
            html += '</div>';
            html += '<div class="pixe-box-float" data-width="1-2" >';
            html += '<label>Font Weight</label>';
            html += $.pixeCombobox({
                slug: 'weight',
                value: value.weight,
                options: $.pixeComboboxOption.fontWeight(false)
            });
            html += '</div>';
            html += '<div class="pixe-box-title" >Font Files</div>';
            for( var slug in types ){
                html += '<div class="pixe-box-float pixe-font-upload" data-type="' + slug + '" data-width="1-2" >';
                html += '<label>' + types[slug] + '</label>';
                html += $.pixeInput({
                    slug: slug,
                    value: value[slug]
                });
                html += '<div class="pixe-submit">' + $.pixeGetAdminIcon('plus') + '</div>';
                html += '</div>'; // pixe-font-upload
            }
            fontContent.append(html);
            fontContent.appendTo(fontItem);

            // open, close content
            fontItem.on('click', '.pixe-custom-font-item-head', function(e){
                if( $(e.target).closest('.pixe-remove').length ) return;

                if( fontItem.hasClass('pixe-active') ){
                    fontContent.css('display', 'block').slideUp(150);
                    fontItem.removeClass('pixe-active');
                    fontHead.find('.pixe-toggle-icon').replaceWith($.pixeGetAdminIcon('toggle-close', {class: 'pixe-toggle-icon'}));
                }else{
                    fontContent.slideDown(150);
                    fontItem.addClass('pixe-active');
                    fontHead.find('.pixe-toggle-icon').replaceWith($.pixeGetAdminIcon('toggle-open', {class: 'pixe-toggle-icon'}));
                }
            });

            // change tab title
            fontItem.on('change', '.pixe-combobox, input[type="text"]', function(){
                if( $(this).attr('data-slug') == 'style' ){
                    var fontStyle = $(this).data('value');
                    fontHead.find('.pixe-title').css('font-style', fontStyle);
                    fontHead.find('.pixe-value[data-type="style"]').html(fontStyle);
                }else if( $(this).attr('data-slug') == 'weight' ){
                    var fontWeight = $(this).data('value');
                    fontHead.find('.pixe-title').css('font-weight', fontWeight);
                    fontHead.find('.pixe-value[data-type="weight"]').html(getFontWeightText(fontWeight));
                }else if( types[$(this).attr('data-slug')] ){
                    var fontValue = $.pixeGetVal(fontItem);
                    fontHead.find('.pixe-file-count').html(getFontFileText(fontValue, types));
                }
            });

            // upload
            fontItem.on('click', '.pixe-submit', function(){
                var list = $(this).closest('.pixe-font-upload');
                var input = list.find('[data-slug]');

                var frame = wp.media({ 
                    title: 'Upload Fonts',
                    multiple: false,
                    library: {
                        type: ['font/woff2', 'font/woff', 'font/ttf', 'font/otf']
                    }
                }).open().on('select', function(){
                    var selections = frame.state().get('selection').toJSON();
                    var selection = selections[0];
                    if( selection && selection.id && selection.url ){
                        input.val(selection.url);
                        input.trigger('change');
                    }
                }).on('close', function(){
                    $(document.body).trigger('uploadframeclose');
                });
            });

            return fontItem;
        },

        // google font tab
        getGoogleFontTab: function(){

            function getFontItem(fontName){
                return '<div data-font-name="' + fontName + '" >' + fontName + $.pixeGetAdminIcon('remove', {'class': 'pixe-remove'}) + '</div>';
            }
            function updateEmptyState(){
                if( contentList.find('[data-font-name]').length ){
                    content.removeClass('pixe-empty');
                    content.children('.pixe-message-content-empty').remove();
                }else{
                    content.addClass('pixe-empty');
                    if( !content.children('.pixe-message-content-empty').length ){
                        content.append($.pixeEmptyNotice('google-font'));
                    }
                }
            }

            var t = this;
            var html = '';

            // init area
            var container = $('<div class="pixe-google-font-settings" ></div>');
            t.tabContent.empty();
            t.tabContent.append(container);

            var content = $('<div class="pixe-google-font-content" ></div>');
            html  = '<div class="pixe-google-font-head" >';
            html += '<label>';
            html += 'Installed Fonts';
            html += '<div class="pixe-google-font-display" >' + $.pixeGetAdminIcon('gear') + '</div>';
            html += '</label>';
            html += '<input type="text" placeholder="Search installed fonts..." />';
            html += '</div>';
            content.append(html);
            container.append(content);

            var contentList = $('<div class="pixe-google-font-content-list pixe-scrollbar" ></div>');
            for( var fontName in pixeData.typoPreset.googleFont ){
                contentList.append(getFontItem(fontName));
            }
            content.append(contentList);

            // check if empty
            updateEmptyState();
            
            // search existed font
            content.on('input', 'input[type="text"]', function(){
                var search = $(this).val();
                var options = contentList.find('[data-font-name]');

                if( search.length ){
                    options.hide();
                    options.filter(':pixecontainsi("' + search + '")').show();
                }else{
                    options.show();
                }
            });

            // add new fonts
            var addNew = $('<div class="pixe-preset-new" ></div>');
            var html  = '<label>Add Google Font</label>';
                html += '<div class="pixe-input" ><input type="text" data-field="name" placeholder="Search Google Fonts to add" /></div>';
                html += '<div class="pixe-ss-button" >Add Font</div>';
                html += '<div class="pixe-google-font-list" >';
                html += '<div class="pixe-options pixe-scrollbar" >';
                for( var fontFamily in pixeGoogleFont ){
                    html += '<div class="pixe-option" >' + fontFamily + '</div>';
                }
                html += '</div>'; // pixe-google-font-list
                html += '</div>'; // pixe-options
            container.append(addNew.append(html));

            // search new font action
            var fontList = addNew.find('.pixe-google-font-list');
            var fontInput = addNew.find('input[type="text"]');
            addNew.on('click', '.pixe-ss-button', function(){
                var fontName = fontInput.val();
                
                // not valid font
                if( !pixeGoogleFont[fontName] ){ 
                    $.pixeConfirmationBox({
                        title: 'Invalid Font Name',
                        message: 'Please select google font from the list.',
                        cancelText: ''
                    });

                // font already exits
                }else if( pixeData.typoPreset.googleFont[fontName] ){ 
                    $.pixeConfirmationBox({
                        title: 'Font Already Existed',
                        message: 'Please select another google font from the list.',
                        cancelText: ''
                    });

                // add new font
                }else{ 
                    // visualize
                    contentList.append(getFontItem(fontName));
                    updateEmptyState();

                    // update data
                    pixeData.typoPreset.googleFont[fontName] = pixeGoogleFont[fontName];
                    t.updateData();
                    
                    // reset input
                    fontInput.val('');
                    
                    // include google font for preview
                    $.pixeTypoStyle.includeGoogleFont();
                }
            });
            addNew.on('input', 'input[type="text"]', function(){
                var search = fontInput.val();
                var options = fontList.find('.pixe-option');

                if( search.length ){
                    options.hide();
                    options.filter(':pixecontainsi("' + search + '")').show();
                }else{
                    options.show();
                }
            });
            addNew.on('focusin', 'input[type="text"]', function(){
                fontList.fadeIn(150);
                fontList.addClass('pixe-top');

                if( $(this).closest('.pixe-lb').length ){
                    fontList.css({
                        left: fontInput.offset().left,
                        top: 'auto',
                        bottom: window.innerHeight - fontInput.offset().top + 10,
                        width: fontInput.outerWidth()
                    });
                }else{
                    fontList.css({
                        left: fontInput.position().left,
                        top: fontInput.position().top - 198,
                        bottom: 'auto',
                        width: fontInput.outerWidth()
                    });
                }
            });
            addNew.on('focusout', 'input[type="text"]', function(){
                setTimeout(function(){
                    fontList.fadeOut(150);
                }, 50);
            });
            addNew.on('click', '.pixe-option', function(){
                fontInput.val($(this).html());
            });

            // remove font
            contentList.on('click', '.pixe-remove', function(){
                var fontItem = $(this).closest('[data-font-name]');
                var fontName = fontItem.attr('data-font-name');

                $.pixeConfirmationBox({
                    title: 'Remove Google Font',
                    message: 'You are about to remove the Google Font. Please note that this process cannot be undone.',
                    onSuccess: function(){
                        fontItem.remove();
                        updateEmptyState();
                        
                        delete pixeData.typoPreset.googleFont[fontName];
                        t.updateData();
                    }
                });
            });

            // typo settings
            content.on('click', '.pixe-google-font-display', function(){
                var popup = new $.pixeInlinePopup({
                    target: $(this),
                    style: 'pixe-popup-google-font-display',
                    options: {
                        'google-font-display': {
                            'title': 'Google Fonts Display',
                            'type': 'combobox',
                            'options': {
                                'auto': 'Auto',
                                'block': 'Block',
                                'swap': 'Swap',
                                'fallback': 'Fallback',
                                'optional': 'Optional'
                            },
                            'width': '1-1'
                        }
                    },
                    values: {
                        'google-font-display': pixeData.typoPreset['google-font-display']
                    }
                });

                if( popup.content ){
                    popup.content.on('change', '.pixe-combobox', function(){
                        $.pixeSetData(pixeData.typoPreset, 'google-font-display', $.pixeGetInputVal($(this)));
                        t.updateData();
                    });
                }
            });

            var description = '<div class="pixe-description" >Browse all fonts at: <a class="pixe-link" target="_blank" href="https://fonts.google.com" >https://fonts.google.com</a></div>';
            container.append(description);
        },

        // preset tab
        getPresetTab: function(activePreset = ''){
            function getCustomTitle(slug, title = ''){
                var html  = '<div data-preset-id="' + slug + '" >';
                    html += '<span class="pixe-text" >' + title + '</span>';
                    html += '</div>';
                return html;
            }
            var t = this;
            var state = {
                activePreset: activePreset
            };

            // init area
            var container = $('<div class="pixe-preset-settings" ></div>');
            t.tabContent.empty();
            t.tabContent.append(container);

            var presetWrap = $('<div class="pixe-preset-option" ></div>');
            var preset = $('<div class="pixe-content pixe-scrollbar"></div>');
            container.append(presetWrap.append(preset));
            
            // 2 loop for core & custom preset
            for( var slug in $.pixeTypoStyle.systemTypo ){
                var title = $.pixeTypoStyle.systemTypo[slug];
                if( state.activePreset == '' ){
                    state.activePreset = slug;
                }

                if( state.activePreset == slug ){
                    preset.append('<div class="pixe-active" data-preset-id="' + slug + '" >' + title + '</div>');
                }else{
                    preset.append('<div data-preset-id="' + slug + '" >' + title + '</div>');
                }
            }
            preset.append('<div class="pixe-divider" ></div>');
            if( pixeData.typoPreset.presetOrder ){
                for( var i = 0; i < pixeData.typoPreset.presetOrder.length; i++ ){
                    var slug = pixeData.typoPreset.presetOrder[i];
                    if( pixeData.typoPreset.preset[slug] && pixeData.typoPreset.preset[slug].label ){
                        preset.append(getCustomTitle(slug, pixeData.typoPreset.preset[slug].label));
                    }
                }
            }
            

            // preset content
            var presetContent = $('<div class="pixe-font-preset-content pixe-scrollbar" ></div>');
            container.append(presetContent);
            t.getPresetContent(presetContent, state.activePreset);

            // change preset
            preset.on('click', '[data-preset-id]', function(){
                if( $(this).hasClass('pixe-active') ) return;
                $(this).addClass('pixe-active').siblings().removeClass('pixe-active');

                state.activePreset = $(this).attr('data-preset-id');
                t.getPresetContent(presetContent, state.activePreset);
            });
            t.bindPresetHeaderEvents(presetContent, preset, state, getCustomTitle);

            // add new preset
            var addNew = $('<div class="pixe-preset-new" ></div>');
            var html  = '<label>' + pixei18n.preset.newPreset + '</label>';
                html += '<div class="pixe-input" ><input type="text" data-field="name" placeholder="Preset Name..." /></div>';
                html += '<div class="pixe-ss-button" >Create Preset</div>';
            container.append(addNew.append(html));

            // add new event
            addNew.on('click', '.pixe-ss-button', function(){
                var input = addNew.find('input[type="text"]');
                var name = input.val().trim();
                var slug = $.pixeToSlug(name);
                if( !$.pixeTypoStyle.testPresetName(name, slug) ) return;

                // add data
                if( !pixeData.typoPreset.presetOrder ){ pixeData.typoPreset.presetOrder = []; }
                pixeData.typoPreset.preset[slug] = { label: name };
                pixeData.typoPreset.presetOrder.push(slug);
                
                // add item
                var item = $(getCustomTitle(slug, name));
                preset.append(item);
                item.trigger('click');

                input.val('');
                t.updateData();
            });
            addNew.on('keydown', 'input[type="text"]', function(e){
                if( e.keyCode == 13 ){
                    e.preventDefault();
                    addNew.find('.pixe-ss-button').trigger('click');
                }
            });

        },
        getPresetTitle: function(slug){
            if( $.pixeTypoStyle.systemTypo[slug] ){
                return $.pixeTypoStyle.systemTypo[slug];
            }

            if( pixeData.typoPreset.preset[slug] && pixeData.typoPreset.preset[slug].label ){
                return pixeData.typoPreset.preset[slug].label;
            }

            return slug;
        },
        getNextPresetSlug: function(slug){
            var baseSlug = slug || 'preset';
            var newSlug = baseSlug;
            var index = 2;

            while( pixeData.typoPreset.preset[newSlug] || $.pixeTypoStyle.systemTypo[newSlug] ){
                newSlug = baseSlug + '-' + index;
                index++;
            }

            return newSlug;
        },
        getPresetHeader: function(activePreset){
            var presetData = pixeData.typoPreset.preset[activePreset] || {};
            var presetTitle = this.getPresetTitle(activePreset);
            var isCustomPreset = !!presetData.label;
            var html  = '<div class="pixe-preset-item-header" >';
                html += '<label>Preset</label>';
                html += '<div class="pixe-actions" >';
                html += $.pixeGetAdminIcon('copy', {class: 'pixe-copy'});
                if( isCustomPreset ){
                    html += $.pixeGetAdminIcon('edit', {class: 'pixe-edit'});
                    html += $.pixeGetAdminIcon('check', {class: 'pixe-submit pixe-with-bg pixe-hidden'});
                    html += $.pixeGetAdminIcon('cancel', {class: 'pixe-cancel pixe-with-bg pixe-hidden'});
                    html += $.pixeGetAdminIcon('remove', {class: 'pixe-remove'});
                }
                html += '</div>';
                html += '<div class="pixe-name" >';
                html += '<span>' + $.pixeEscHtml(presetTitle) + '</span>';
                if( isCustomPreset ){
                    html += '<div class="pixe-input" style="display: none;" ><input type="text" data-field="name" value="' + $.pixeEscAttr(presetTitle) + '" /></div>';
                }
                html += '</div>';
                html += '</div>';

            return html;
        },
        bindPresetHeaderEvents: function(presetContent, preset, state, getCustomTitle){
            var t = this;

            // copy active preset
            presetContent.on('click', '.pixe-preset-item-header .pixe-copy', function(){
                var oldSlug = state.activePreset;
                var newSlug = t.getNextPresetSlug(oldSlug);
                var newTitle = t.getPresetTitle(oldSlug) + ' Copy';
                var value = t.getPresetData(oldSlug);
                var newData = { label: newTitle };

                if( Object.keys(value).length ){
                    newData.value = value;
                }

                if( !pixeData.typoPreset.presetOrder ){ pixeData.typoPreset.presetOrder = []; }
                pixeData.typoPreset.preset[newSlug] = newData;
                pixeData.typoPreset.presetOrder.push(newSlug);

                var item = $(getCustomTitle(newSlug, newTitle));
                preset.append(item);
                item.trigger('click');

                t.updateData();
            });

            // edit preset name
            presetContent.on('click', '.pixe-preset-item-header .pixe-edit', function(){
                var header = presetContent.find('.pixe-preset-item-header');

                header.find('.pixe-copy, .pixe-edit, .pixe-remove').addClass('pixe-hidden');
                header.find('.pixe-submit, .pixe-cancel').removeClass('pixe-hidden');
                header.find('.pixe-name span').hide();
                header.find('.pixe-input').show();
                header.find('[data-field="name"]').focus().select();
            });

            // cancel preset name edit
            presetContent.on('click', '.pixe-preset-item-header .pixe-cancel', function(){
                t.getPresetContent(presetContent, state.activePreset);
            });

            // change preset name
            presetContent.on('click', '.pixe-preset-item-header .pixe-submit', function(){
                var input = presetContent.find('[data-field="name"]');
                var name = input.val().trim();

                if( name.length == 0 || !$.pixeIsNameValid(name) ){
                    $.pixeConfirmationBox({
                        title: 'Invalid Name',
                        message: 'Please use only English characters, number or space in your preset name.',
                        cancelText: ''
                    });
                    return;
                }

                pixeData.typoPreset.preset[state.activePreset].label = name;
                preset.find('[data-preset-id="' + state.activePreset + '"] .pixe-text').html(name);
                t.getPresetContent(presetContent, state.activePreset);
                t.updateData();
            });

            // submit/cancel preset name edits with keyboard
            presetContent.on('keydown', '[data-field="name"]', function(e){
                if( e.key == 'Enter' ){
                    presetContent.find('.pixe-preset-item-header .pixe-submit').trigger('click');
                }

                if( e.key == 'Escape' ){
                    t.getPresetContent(presetContent, state.activePreset);
                }
            });

            // remove active preset
            presetContent.on('click', '.pixe-preset-item-header .pixe-remove', function(){
                var currentPreset = state.activePreset;
                var currentPresetItem = preset.find('[data-preset-id="' + currentPreset + '"]');

                $.pixeConfirmationBox({
                    title: 'Remove Custom Preset',
                    message: 'You are about to remove a custom preset. Please note that this process cannot be undone.',
                    onSuccess: function(){

                        // delete preset data
                        var index = pixeData.typoPreset.presetOrder.indexOf(currentPreset);
                        if( index >= 0 ){ pixeData.typoPreset.presetOrder.splice(index, 1); }
                        delete pixeData.typoPreset.preset[currentPreset];

                        // remove object
                        currentPresetItem.slideUp(150, function(){
                            $(this).remove();
                        });

                        t.updateData();

                        // switch preset
                        preset.find('[data-preset-id]').first().trigger('click');
                    }
                });
            });
        },
        getPresetData: function(activePreset){
            if( pixeData.typoPreset.preset[activePreset] && pixeData.typoPreset.preset[activePreset].value ){
                return $.pixeClone(pixeData.typoPreset.preset[activePreset].value);
            }else{
                return {};
            }
        },
        getPresetContent: function(presetContent, activePreset){
            var t = this;
            var device = 'desktop';
            var value = t.getPresetData(activePreset);

            // clear old value
            presetContent.empty();

            // preset header
            presetContent.append(t.getPresetHeader(activePreset));

            // create form and bind input
            var form = $('<div class="pixe-form pixe-clearfix" ></div>');
            form.appendTo(presetContent);

            // get typo input
            var ss = new $.pixeStyleSelector({
                obj: value,
                slug: false,
                display: 'html',
                ignoreViewport: true
            });
            ss.getContent(form, 'typo');

            // preview area
            var previewHtml = '<div class="pixe-typo-preview" >';
            previewHtml += 'Sample Text';
            previewHtml += '<style></style>';
            previewHtml += '</div>';
            
            var preview = $(previewHtml);
            var previewStyle = preview.children('style');
            preview.appendTo(presetContent);
            
            // typo style
            function setPreviewStyle(){
                var css = $.pixeTypoStyle.getPresetCss(value, '');
                if( device == 'tablet' || device == 'mobile' ){
                    css += $.pixeTypoStyle.getPresetCss(value, 'tablet-');
                }
                if( device == 'mobile' ){
                    css += $.pixeTypoStyle.getPresetCss(value, 'mobile-');
                }
                previewStyle.html($.pixeSetCss('.pixe-font-preset-content .pixe-typo-preview', {
                    'custom': css
                }));
            }
            setPreviewStyle();

            // change device
            form.on('click', '.pixe-device-selector [data-device]', function(){
                device = $(this).attr('data-device');
                setPreviewStyle();
            });

            // save action
            var updateData = $.pixeDebounce(function(){ t.updateData(); }, 1000);

            // on change
            form.on('change', '[data-slug]', function(){
                var slug = $(this).attr('data-slug');
                var inputVal = $.pixeGetInputVal($(this));
                
                t.isChanged = true;
                $.pixeSetData(value, slug, inputVal);
                setPreviewStyle();

                // set value to typo object
                if( Object.keys(value).length ){
                    
                    // init data if not exists 
                    if( !pixeData.typoPreset.preset[activePreset] ){
                        pixeData.typoPreset.preset[activePreset] = {};
                    }
                    
                    // set typo data
                    pixeData.typoPreset.preset[activePreset].value = value;
                }else{
                    delete pixeData.typoPreset.preset[activePreset].value;
                    
                    // remove object out if not assigned & not custom preset
                    if( !pixeData.typoPreset.preset[activePreset].label ){
                        delete pixeData.typoPreset.preset[activePreset];
                    }
                }
                
                updateData();
            });
        },
        
        // create new preset
        addNewPreset: function(slug, value){
            var t = this;

            if( slug && value ){
                if( !pixeData.typoPreset.preset[slug] ){
                    pixeData.typoPreset.preset[slug] = value;
                    pixeData.typoPreset.presetOrder.push(slug);
                    t.updateData();
                }
            }
        },

        // update data to database
        updateData: function(){
            var t = this;
            t.isChanged = true;

            // set preset style
            $.pixeTypoStyle.setPresetStyle();
            if( $.pixeBuilder ){
                $.pixeUpdateCombobox($.pixeBuilder.settingsPanel.panel, {
                    selector: '.pixe-typo-preset-combobox',
                    options: 'typoPreset'
                });
            }

            // format data
            var ajaxData = $.pixeGetAjaxData({
                action: 'pixe_save_typo',
                typo: pixeData.typoPreset,
                site: pixeData.site
            });

            $.pixeAjax({
                ajaxData: ajaxData,
                onSuccess: function(data){
                    if( $.pixeDebug ){ console.log('typo settings updated: ', data); }
                }
            });

        },

    };

})(jQuery);	
