<?php

if ( class_exists( 'WP_Customize_Control' ) && ! class_exists( 'SiteOrigin_Customize_Fonts_Control' ) ) {
	/**
	 * A customizer control for choosing web fonts
	 */
	class SiteOrigin_Customize_Fonts_Control extends WP_Customize_Control {
		public function __construct( $manager, $id, $args = array() ) {
			$google_web_fonts = include get_template_directory() . '/inc/settings/data/fonts.php';

			// Add the default fonts
			$choices = apply_filters( 'vantage_websafe', array(
				'Arial' => 'Arial',
				'Courier New' => 'Courier New',
				'Georgia' => 'Georgia',
				'Helvetica Neue' => 'Helvetica Neue',
				'Lucida Grande' => 'Lucida Grande',
				'Tahoma' => 'Tahoma',
				'Trebuchet MS' => 'Trebuchet MS',
				'Verdana' => 'Verdana',
			) );

			foreach ( $google_web_fonts as $font => $variants ) {
				foreach ( $variants['variants'] as $variant ) {
					if ( $variant == 'regular' || $variant == 400 ) {
						$choices[ $font ] = $font;
					} else {
						$choices[ $font . ':' . $variant ] = $font . ' (' . $variant . ')';
					}
				}
			}

			$args = wp_parse_args( $args, array(
				'type' => 'select',
				'choices' => $choices,
			) );
			parent::__construct( $manager, $id, $args );
		}

		/**
		 * Render the control. Renders the control wrapper, then calls $this->render_content().
		 */
		protected function render() {
			$id = 'customize-control-' . str_replace( '[', '-', str_replace( ']', '', $this->id ) );
			$class = 'customize-control customize-control-' . $this->type . ' customize-control-font';

			?>
			<li id="<?php echo esc_attr( $id ); ?>" class="<?php echo esc_attr( $class ); ?>">
				<?php $this->render_content(); ?>
			</li>
			<?php
		}
	}
}

if ( ! class_exists( 'SiteOrigin_Customizer_CSS_Builder' ) ) {
	/**
	 * This is used for building custom CSS.
	 */
	class SiteOrigin_Customizer_CSS_Builder {
		private $css;
		private $raw_css;
		private $google_fonts;
		private $web_safe;
		private $defaults;
		private $fonts;

		// These are web safe fonts

		public function __construct( $defaults ) {
			$this->css = array();
			$this->raw_css = '';
			$this->google_fonts = array();
			$this->web_safe = apply_filters( 'vantage_websafe_fallback', array(
				'Arial' => 'Arial, Helvetica, sans-serif',
				'Courier New' => 'Courier, mono',
				'Georgia' => '"Times New Roman", Times, serif',
				'Helvetica Neue' => 'Arial, Helvetica, Geneva, sans-serif',
				'Lucida Grande' => 'Lucida, Verdana, sans-serif',
				'Tahoma' => 'Tahoma, Verdana, Segoe, sans-serif',
				'Trebuchet MS' => 'Trebuchet MS, Lucida Grande, Lucida Sans Unicode, Lucida Sans, Tahoma, sans-serif',
				'Verdana' => 'Verdana, Geneva, sans-serif',
			) );
			$this->defaults = $defaults;
		}

		/**
		 * Echo all the CSS
		 */
		public function css() {
			// Start by importing Google web fonts
			$return = '<style type="text/css" id="customizer-css">';

			if ( apply_filters( 'vantage_import_google_fonts', true ) ) {
				$import = array();

				foreach ( $this->google_fonts as $font ) {
					$import[ ] = urlencode( $font[ 0 ] ) . ':' . $font[ 1 ];
				}
				$import = array_unique( $import );

				if ( ! empty( $import ) ) {
					$return .= '@import url(' . esc_url( apply_filters( 'siteorigin_web_font_url', 'https://fonts.googleapis.com/css' ) . '?family=' . implode( '|', $import ) . '&display=block ' ) . ');';
				}
			}

			foreach ( $this->css as $selector => $rules ) {
				$return .= $selector . ' { ' . implode( '; ', $rules ) . ' } ';
			}

			if ( ! empty( $this->raw_css ) ) {
				$return .= $this->raw_css;
			}

			$return .= '</style>';

			return $return;
		}

		/**
		 * Add a raw CSS value
		 */
		public function add_css( $selector, $property, $value ) {
			if ( empty( $value ) ) {
				return;
			}
			$selector = preg_replace( '/\s+/m', ' ', $selector );

			if ( $property == 'font' ) {
				if ( strpos( $value, ':' ) !== false ) {
					list( $family, $variant ) = explode( ':', $value, 2 );
				} else {
					$family = $value;
					$variant = 400;
				}

				if ( ! empty( $this->web_safe[ $family ] ) ) {
					$family = '"' . $family . '", ' . $this->web_safe[ $family ];
				} else {
					$this->google_fonts[ ] = array( $family, $variant );
					$family = '"' . $family . '"';
				}

				$this->add_css( $selector, 'font-family', $family );

				if ( $variant != 400 ) {
					$this->add_css( $selector, 'font-weight', $variant );
				}

				return;
			}

			if ( empty( $this->css[ $selector ] ) ) {
				$this->css[ $selector ] = array();
			}

			$this->css[ $selector ][ ] = $property . ': ' . $value;
		}

		/**
		 * Add some basic, raw CSS.
		 *
		 * @param string $css The raw CSS.
		 */
		public function add_raw_css( $css ) {
			$this->raw_css .= ' ' . $css;
		}

		/**
		 * Adds a Google web font or web safe font
		 *
		 * @param string $selector The selector we want to use the web font with.
		 * @param string $mod      The theme mod where the font is stored.
		 */
		public function add_web_font( $selector, $mod ) {
			$font = get_theme_mod( $mod );

			if ( empty( $font ) || empty( $this->defaults[ $mod ] ) || $font == $this->defaults[ $mod ] ) {
				return;
			}

			if ( empty( $this->css[ $selector ] ) ) {
				$this->css[ $selector ] = array();
			}

			if ( strpos( $font, ':' ) !== false ) {
				list( $family, $variant ) = explode( ':', $font, 2 );
			} else {
				$variant = 400;
				$family = $font;
			}

			if ( ! empty( $this->web_safe[ $family ] ) ) {
				$family = '"' . $family . '", ' . $this->web_safe[ $family ];
			} else {
				$this->google_fonts[ ] = array( $family, $variant );
				$family = '"' . $family . '"';
			}

			$this->add_css( $selector, 'font-family', $family );

			if ( ! empty( $variant ) ) {
				if ( $variant != 400 && $variant != 'regular' ) {
					if ( ! is_numeric( $variant ) ) {
						$variant = filter_var( $variant, FILTER_SANITIZE_NUMBER_INT );
						$this->add_css( $selector, 'font-style', 'italic' );
					}
					$this->add_css( $selector, 'font-weight', $variant );
				} else {
					$this->add_css( $selector, 'font-weight', 400 );
				}
			}
		}

		/**
		 * Adds a color property.
		 */
		public function add_color( $selector, $property, $mod ) {
			$color = get_theme_mod( $mod );

			if ( empty( $color ) || empty( $this->defaults[ $mod ] ) || $color == $this->defaults[ $mod ] ) {
				return;
			}

			$this->add_css( $selector, $property, $color );
		}

		/**
		 * Add an image URL
		 */
		public function add_image( $selector, $property, $mod ) {
			$image = get_theme_mod( $mod );

			if ( ! empty( $image ) ) {
				$this->add_css( $selector, $property, 'url("' . esc_url( $image ) . '")' );
			}
		}

		/**
		 * Adds a measurement property
		 *
		 * @param string $units
		 */
		public function add_measurement( $selector, $property, $mod, $units = 'px' ) {
			$value = get_theme_mod( $mod );
			$measurement = floatval( $value );

			if ( ! is_float( $value ) || empty( $this->defaults[ $mod ] ) || $measurement == $this->defaults[ $mod ] ) {
				return;
			}

			$this->add_css( $selector, $property, $measurement . $units );
		}

		/**
		 * Convert a HEX value to an RGB array
		 *
		 * @return array
		 */
		public static function hex2rgb( $hex ) {
			$hex = str_replace( '#', '', $hex );

			if ( strlen( $hex ) == 3 ) {
				$r = hexdec( substr( $hex, 0, 1 ) . substr( $hex, 0, 1 ) );
				$g = hexdec( substr( $hex, 1, 1 ) . substr( $hex, 1, 1 ) );
				$b = hexdec( substr( $hex, 2, 1 ) . substr( $hex, 2, 1 ) );
			} else {
				$r = hexdec( substr( $hex, 0, 2 ) );
				$g = hexdec( substr( $hex, 2, 2 ) );
				$b = hexdec( substr( $hex, 4, 2 ) );
			}

			return array( $r, $g, $b );
		}

		/**
		 * Adjust brightness.
		 */
		public static function adjustBrightness( $hex, $steps ) {
			$steps = max( -255, min( 255, $steps ) );

			$hex = str_replace( '#', '', $hex );

			if ( strlen( $hex ) == 3 ) {
				$hex = str_repeat( substr( $hex, 0, 1 ), 2 ) . str_repeat( substr( $hex, 1, 1 ), 2 ) . str_repeat( substr( $hex, 2, 1 ), 2 );
			}

			$r = hexdec( substr( $hex, 0, 2 ) );
			$g = hexdec( substr( $hex, 2, 2 ) );
			$b = hexdec( substr( $hex, 4, 2 ) );

			// Adjust number of steps and keep it inside 0 to 255.
			$r = max( 0, min( 255, $r + $steps ) );
			$g = max( 0, min( 255, $g + $steps ) );
			$b = max( 0, min( 255, $b + $steps ) );

			$r_hex = str_pad( dechex( $r ), 2, '0', STR_PAD_LEFT );
			$g_hex = str_pad( dechex( $g ), 2, '0', STR_PAD_LEFT );
			$b_hex = str_pad( dechex( $b ), 2, '0', STR_PAD_LEFT );

			return '#' . $r_hex . $g_hex . $b_hex;
		}
	}
}

/**
 * Sanitize a Google font.
 *
 * @param string $font
 *
 * @return string
 */
function siteorigin_customizer_sanitize_google_font( $font ) {
	// Check the default fonts too.
	$default_fonts = apply_filters( 'vantage_websafe', array(
		'Arial' => 'Arial',
		'Courier New' => 'Courier New',
		'Georgia' => 'Georgia',
		'Helvetica Neue' => 'Helvetica Neue',
		'Lucida Grande' => 'Lucida Grande',
		'Tahoma' => 'Tahoma',
		'Trebuchet MS' => 'Trebuchet MS',
		'Verdana' => 'Verdana',
	) );

	$google_fonts = include get_template_directory() . '/inc/settings/data/fonts.php';
	$font_name_parts = explode( ':', $font, 2 );
	$font_name = $font_name_parts[0];

	if ( empty( $google_fonts[ $font_name ] ) && empty( $default_fonts[ $font_name ] ) ) {
		$font = '';
	}

	return $font;
}

/**
 * Sanitize a float value
 *
 * @return float
 */
function siteorigin_customizer_sanitize_floatval( $value ) {
	return floatval( $value );
}

/**
 * Sanitize an integer value
 *
 * @return int
 */
function siteorigin_customizer_sanitize_intval( $value ) {
	return intval( $value );
}

/**
 * Sanitize an image URL
 *
 * @return string
 */
function siteorigin_customizer_sanitize_image( $image ) {
	return esc_url_raw( $image );
}

if ( ! class_exists( 'SiteOrigin_Customizer_Helper' ) ) {
	class SiteOrigin_Customizer_Helper {
		private $theme;
		private $settings;
		private $sections;
		private $defaults;

		public function __construct( $settings = array(), $sections = array(), $theme = 'generic', $root_url = false, $make_single = true ) {
			// Give child themes a chance to filter this.
			$this->theme = $theme;
			$this->defaults = array();
			$this->settings = array();

			$this->add_sections( $sections );
			$this->add_settings( $settings );

			// Add a script that will help us with our previews
			add_action( 'customize_preview_init', array( $this, 'enqueue' ) );
			add_action( 'customize_controls_enqueue_scripts', array( $this, 'admin_enqueue' ) );

			if ( $make_single ) {
				global $siteorigin_customize_helper_single;
				$siteorigin_customize_helper_single = $this;
			}
		}

		/**
		 * Get the global instance of the siteorigin customize helper
		 *
		 * @return mixed
		 */
		public static function single() {
			global $siteorigin_customize_helper_single;

			if ( empty( $siteorigin_customize_helper_single ) ) {
				new SiteOrigin_Customizer_Helper();
			}

			return $siteorigin_customize_helper_single;
		}

		/**
		 * Add sections to the customizer helper.
		 *
		 * @param array $sections
		 */
		public function add_sections( $sections = array() ) {
			$sections = apply_filters( $this->theme . '_siteorigin_theme_customizer_sections', $sections );
			$this->sections = wp_parse_args( $sections, $this->sections );
		}

		/**
		 * Add settings to the customzier helper.
		 *
		 * @param array $settings
		 */
		public function add_settings( $settings = array() ) {
			$settings = apply_filters( $this->theme . '_siteorigin_theme_customizer_settings', $settings );

			foreach ( $settings as $section_id => $section_settings ) {
				foreach ( $section_settings as $id => $setting ) {
					$setting['section'] = $section_id;
					$this->settings[ $section_id . '_' . $id ] = $setting;

					if ( ! empty( $setting['default'] ) ) {
						$this->defaults[ $section_id . '_' . $id ] = $setting['default'];
					}
				}
			}
		}

		/**
		 * Registers all the customizations with the WordPress customize manager. Should be called by function tied to customize_register action.
		 *
		 * @param WP_Customize_Manager $wp_customize
		 */
		public function customize_register( $wp_customize ) {
			// Add the panel that will contain all the theme settings
			$theme = wp_get_theme();
			$wp_customize->add_panel( 'siteorigin_theme_settings', array(
				'priority'       => 50,
				'capability'     => 'edit_theme_options',
				'title'          => __( 'Theme Design', 'vantage' ),
				'description'    => sprintf( __( 'Theme Specific Customizations For %s.', 'vantage' ), $theme->get( 'Name' ) ),
			) );

			// Start by registering all the sections
			foreach ( $this->sections as $id => $section ) {
				$section = wp_parse_args( $section, array(
					'panel' => 'siteorigin_theme_settings',
				) );
				$wp_customize->add_section( $id, $section );
			}

			static $priority = 0;

			// Now add all the settings
			foreach ( $this->settings as $id => $setting ) {
				switch( $setting['type'] ) {
					case 'font' :
						$sanitize_callback = 'siteorigin_customizer_sanitize_google_font';
						break;

					case 'color' :
						$sanitize_callback = 'sanitize_hex_color';
						break;

					case 'measurement' :
						$sanitize_callback = 'siteorigin_customizer_sanitize_floatval';
						break;

					case 'image' :
						$sanitize_callback = 'siteorigin_customizer_sanitize_image';
						break;

					default:
						$sanitize_callback = 'sanitize_text_field';
						break;
				}

				$wp_customize->add_setting( $id, array(
					'default' => ! empty( $setting['default'] ) ? $setting['default'] : '',
					'sanitize_callback' => $sanitize_callback,
				) );

				// Can't use live changes with a callback
				if ( ! empty( $setting['callback'] ) ) {
					$setting['no_live'] = true;
				}

				// Set $setting['description' ] if this setting doesn't have a description
				if ( ! isset( $setting['description' ] ) ) {
					$setting['description'] = '';
				}

				// Now lets add a control for this setting
				switch( $setting['type'] ) {
					case 'font':
						$wp_customize->add_control( new SiteOrigin_Customize_Fonts_Control( $wp_customize, $this->theme . '_' . $id, array(
							'label' => $setting['title'],
							'section' => $setting['section'],
							'settings' => $id,
							'priority' => $priority++,
							'description' => esc_html( $setting['description'] ),
						) ) );
						break;

					case 'color':
						$wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, $this->theme . '_' . $id, array(
							'label' => $setting['title'],
							'section' => $setting['section'],
							'settings' => $id,
							'priority' => $priority++,
							'description' => esc_html( $setting['description'] ),
						) ) );

						if ( empty( $setting['no_live'] ) ) {
							$wp_customize->get_setting( $id )->transport = 'postMessage';
						}
						break;

					case 'measurement':
						$wp_customize->add_control( $id, array(
							'label' => $setting['title'],
							'section' => $setting['section'],
							'type'    => 'text',
							'priority' => $priority++,
							'description' => esc_html( $setting['description'] ),
						) );

						if ( empty( $setting['no_live'] ) ) {
							$wp_customize->get_setting( $id )->transport = 'postMessage';
						}
						break;

					case 'image':
						$wp_customize->add_control( new WP_Customize_Image_Control( $wp_customize, $this->theme . '_' . $id, array(
							'label' => $setting['title'],
							'section' => $setting['section'],
							'settings' => $id,
							'priority' => $priority++,
							'description' => esc_html( $setting['description'] ),
						) ) );
						break;

					case 'image_select':
						$wp_customize->add_control( new SiteOrigin_Customize_Image_Select_Control( $wp_customize, $this->theme . '_' . $id, array(
							'label' => $setting['title'],
							'section' => $setting['section'],
							'settings' => $id,
							'priority' => $priority++,
							'description' => esc_html( $setting['description'] ),
						) ) );
						break;

					default:
						$wp_customize->add_control( $id, array(
							'label' => $setting['title'],
							'section' => $setting['section'],
							'type'    => $setting['type'],
							'priority' => $priority++,
							'choices' => isset( $setting['choices'] ) ? $setting['choices'] : null,
							'description' => esc_html( $setting['description'] ),
						) );
						break;
				}
			}
		}

		/**
		 * Create the CSS builder with all the current values
		 *
		 * @return SiteOrigin_CSS_Builder
		 */
		public function create_css_builder() {
			$builder = new SiteOrigin_Customizer_CSS_Builder( $this->defaults );

			foreach ( $this->settings as $id => $setting ) {
				if ( ! empty( $setting['selector'] ) ) {
					foreach ( (array) $setting['selector'] as $selector ) {
						switch( $setting['type'] ) {
							case 'font':
								$builder->add_web_font( $selector, $id );
								break;

							case 'color':
								foreach ( (array) $setting['property'] as $property ) {
									$builder->add_color( $selector, $property, $id );
								}
								break;

							case 'measurement':
								foreach ( (array) $setting['property'] as $property ) {
									$builder->add_measurement( $selector, $property, $id, $setting['unit'] );
								}
								break;

							case 'image':
								foreach ( (array) $setting['property'] as $property ) {
									$builder->add_image( $selector, $property, $id );
								}
								break;

							default:
								if ( isset( $setting['property'] ) ) {
									foreach ( (array) $setting['property'] as $property ) {
										$builder->add_css( $selector, $property, get_theme_mod( $id ) );
									}
								}
								break;
						}
					}
				}

				if ( isset( $setting['callback'] ) ) {
					$val = get_theme_mod( $id );

					if ( isset( $setting['default'] ) && $val != $setting['default'] ) {
						call_user_func( $setting['callback'], $builder, $val, array_merge( $setting, array( 'id' => $id ) ) );
					}
				}
			}

			$builder = apply_filters( $this->theme . '_siteorigin_customizer_custom_css', $builder, $this->settings, $this->defaults );

			return $builder;
		}

		/**
		 * Enqueue the customizer scripts
		 */
		public function enqueue() {
			wp_enqueue_script(
				'siteorigin-customizer-preview',
				get_template_directory_uri() . '/inc/customizer/js/live-customizer' . SITEORIGIN_THEME_JS_PREFIX . '.js',
				array(
					'jquery',
					'customize-preview'
				),
				SITEORIGIN_THEME_VERSION
			);

			wp_localize_script(
				'siteorigin-customizer-preview',
				'customizeSettings',
				$this->settings
			);
		}

		/**
		 * Enqueue scripts for the actual customizer admin
		 */
		public function admin_enqueue() {
			wp_enqueue_script(
				'siteorigin-customizer-admin',
				get_template_directory_uri() . '/inc/customizer/js/admin' . SITEORIGIN_THEME_JS_PREFIX . '.js',
				array(
					'jquery',
					'customize-controls'
				),
				SITEORIGIN_THEME_VERSION
			);

			wp_localize_script(
				'siteorigin-customizer-admin',
				'soCustomizeAdmin',
				array(
					'confirm' => __( 'Are you sure you want to reset your theme customizations?', 'vantage' ),
					'button' => __( 'Reset Customizations', 'vantage' ),
					'action' => wp_nonce_url(
						add_query_arg( array(
							'return' => add_query_arg( false, false ),
							'action' => 'so_customize_reset',
						), admin_url( 'admin-ajax.php' ) ),
						'so_customize_reset'
					),
				)
			);

			wp_enqueue_style(
				'siteorigin-customizer-admin',
				get_template_directory_uri() . '/inc/customizer/css/admin.css',
				array(),
				SITEORIGIN_THEME_VERSION
			);
		}

		/**
		 * Reset all defaults
		 */
		public function reset_defaults() {
			foreach ( $this->settings as $id => $values ) {
				remove_theme_mod( $id );
			}
		}
	}
}
