<?php

if (!defined('ABSPATH')) {
    exit;
}
if (!class_exists('acf_form_customizer')) {
    class acf_form_customizer
    {
        function __construct()
        {
            $this->preview_values = array();
            $this->preview_fields = array();
            $this->preview_errors = array();
            add_action('customize_controls_init', array($this, 'customize_controls_init'));
            add_action('customize_preview_init', array($this, 'customize_preview_init'), 1, 1);
            add_action('customize_save', array($this, 'customize_save'), 1, 1);
            add_filter('widget_update_callback', array($this, 'save_widget'), 10, 4);
        }
        function customize_controls_init()
        {
            acf_enqueue_scripts(array('context' => 'customize_controls'));
            add_action('acf/input/admin_footer', array($this, 'admin_footer'), 1);
        }
        function save_widget($instance, $new_instance, $old_instance, $widget)
        {
            if (!isset($_POST['wp_customize']) || !isset($new_instance['acf']) || !acf_verify_nonce('widget')) {
                return $instance;
            }
            $data = array('post_id' => "widget_{$widget->id}", 'values' => array(), 'fields' => array());
            $data['values'] = $new_instance['acf'];
            foreach ($data['values'] as $k => $v) {
                $field = acf_get_field($k);
                if (!$field) {
                    continue;
                }
                $data['fields'][$field['name']] = $field['key'];
            }
            $instance['acf'] = $data;
            return $instance;
        }
        function settings($customizer)
        {
            $data = array();
            $settings = $customizer->settings();
            if (empty($settings)) {
                return false;
            }
            foreach ($settings as $setting) {
                $id = $setting->id;
                if (substr($id, 0, 6) == 'widget' || substr($id, 0, 7) == 'nav_menu') {
                } else {
                    continue;
                }
                $value = $setting->post_value();
                if (!is_array($value) || !isset($value['acf'])) {
                    continue;
                }
                $setting->acf = $value['acf'];
                $data[] = $setting;
            }
            if (empty($data)) {
                return false;
            }
            return $data;
        }
        function customize_preview_init($customizer)
        {
            $settings = $this->settings($customizer);
            if (empty($settings)) {
                return;
            }
            foreach ($settings as $setting) {
                $data = $setting->acf;
                $this->preview_values[$data['post_id']] = $data['values'];
                $this->preview_fields[$data['post_id']] = $data['fields'];
            }
            if (empty($this->preview_values)) {
                return;
            }
            add_filter('acf/pre_load_value', array($this, 'pre_load_value'), 10, 3);
            add_filter('acf/pre_load_reference', array($this, 'pre_load_reference'), 10, 3);
        }
        function pre_load_value($value, $post_id, $field)
        {
            if (isset($this->preview_values[$post_id][$field['key']])) {
                return $this->preview_values[$post_id][$field['key']];
            }
            return $value;
        }
        function pre_load_reference($field_key, $field_name, $post_id)
        {
            if (isset($this->preview_fields[$post_id][$field_name])) {
                return $this->preview_fields[$post_id][$field_name];
            }
            return $field_key;
        }
        function customize_save($customizer)
        {
            $settings = $this->settings($customizer);
            if (empty($settings)) {
                return;
            }
            foreach ($settings as $setting) {
                $data = $setting->acf;
                acf_save_post($data['post_id'], $data['values']);
                $id_data = $setting->id_data();
                add_filter('pre_update_option_' . $id_data['base'], array($this, 'pre_update_option'), 10, 3);
            }
        }
        function pre_update_option($value, $option, $old_value)
        {
            if (empty($value)) {
                return $value;
            }
            foreach ($value as $i => $widget) {
                if (!isset($widget['acf'])) {
                    continue;
                }
                unset($value[$i]['acf']);
            }
            return $value;
        }
        function admin_footer()
        {
            ?>
<script type="text/javascript">
(function($) {
	
	// customizer saves widget on any input change, so unload is not needed
	acf.unload.active = 0;
	
	
	// hack customizer function to remove bug caused by WYSIWYG field using aunique ID
	// customizer compares returned AJAX HTML with the HTML of the widget form.
	// the _getInputsSignature() function is used to generate a string based of input name + id.
	// because ACF generates a unique ID on the WYSIWYG field, this string will not match causing the preview function to bail.
	// an attempt was made to remove the WYSIWYG unique ID, but this caused multiple issues in the wp-admin and altimately doesn't make sense with the tinymce rule that all editors must have a unique ID.
	// source: wp-admin/js/customize-widgets.js
	
	// vars
	var WidgetControl = wp.customize.Widgets.WidgetControl.prototype;
	
	
	// backup functions
	WidgetControl.__getInputsSignature = WidgetControl._getInputsSignature;
	WidgetControl.__setInputState = WidgetControl._setInputState;
	
	
	// modify __getInputsSignature
	WidgetControl._getInputsSignature = function( inputs ) {
		
		// vars
		var signature = this.__getInputsSignature( inputs );
			safe = [];
		
		
		// split
		signature = signature.split(';');
		
		
		// loop
		for( var i in signature ) {
			
			// vars
			var bit = signature[i];
			
			
			// bail ealry if acf is found
			if( bit.indexOf('acf') !== -1 ) continue;
			
			
			// append
			safe.push( bit );
			
		}
		
		
		// update
		signature = safe.join(';');
		
		
		// return
		return signature;
		
	};
	
	
	// modify _setInputState
	// this function deosn't seem to run on widget title/content, only custom fields
	// either way, this function is not needed and will break ACF fields 
	WidgetControl._setInputState = function( input, state ) {
		
		return true;
			
	};
		
})(jQuery);	
</script>
			<?php 
        }
    }
    new acf_form_customizer();
}