<?php

namespace Gigneo\Theme_Option;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

use Carbon_Fields\Field\Field;
use Carbon_Fields\Datastore\Datastore;

/**
 * Class Serialized
 *
 * Serialized datastore for Carbon Fields.
 *
 * @since 0.0.1
 */
class Serialized extends Datastore {

	/**
	 * Initialize the datastore
	 */
	public function init() {
	}

	/**
	 * Load the field value(s)
	 *
	 * @param Field $field The field to load value(s) in.
	 *
	 * @return array
	 */
	public function load( Field $field ) {
		$key = $this->get_key_for_field( $field );

		return get_option( $key, null );
	}

	protected function get_key_for_field( Field $field ) {
		return '_' . $field->get_base_name();
	}

	/**
	 * Save the field value(s)
	 *
	 * @param Field $field The field to save.
	 */
	public function save( Field $field ) {
		if ( ! empty( $field->get_hierarchy() ) ) {
			return; // only applicable to root fields
		}
		$key   = $this->get_key_for_field( $field );
		$value = $field->get_full_value();
		if ( is_a( $field, '\\Carbon_Fields\\Field\\Complex_Field' ) ) {
			$value = $this->sanitize_complex_field( $field->get_value_tree() );
		} elseif ( is_a( $field, '\\Carbon_Fields\\Field\\Multiselect_Field' ) ) {
			$value = $field->get_value();
		} elseif ( is_a( $field, '\\Carbon_Fields\\Field\\Media_Gallery_Field' ) ) {
			$value = $field->get_value();
		}

		$this->save_key_value_pair_with_autoload( $key, $value, $field->get_autoload() );
	}

	/**
	 * Save a single key-value pair to the database with autoload
	 *
	 * @param string $key
	 * @param string $value
	 * @param bool $autoload
	 */
	protected function save_key_value_pair_with_autoload( $key, $value, $autoload ) {

		$autoload = $autoload ? 'yes' : 'no';

			// Use core option APIs only; they manage the options/notoptions object cache.
			if ( false === get_option( $key, false ) ) {
				add_option( $key, $value, '', $autoload );
			} else {
			update_option( $key, $value, $autoload );
		}
	}

	/**
	 * Delete the field value(s)
	 *
	 * @param Field $field The field to delete.
	 */
	public function delete( Field $field ) {
		if ( ! empty( $field->get_hierarchy() ) ) {
			return; // only applicable to root fields
		}
		$key = $this->get_key_for_field( $field );
		delete_option( $key );
	}

	/**
	 * Recursively sanitize complex field values to properly store them.
	 *
	 * @param mixed $data The complex field data.
	 * @return mixed
	 */
	protected function sanitize_complex_field( $data ) {
		if ( ! is_array( $data ) ) {
			return $data; // Return scalar values as is
		}

		$cleaned_data = array();

		foreach ( $data as $key => $value ) {
			if ( is_array( $value ) ) {
				if ( isset( $value[0] ) && is_array( $value[0] ) && isset( $value[0]['value'] ) && count( $value[0] ) === 1 ) {
					$cleaned_data[ $key ] = $value[0]['value'];
				} elseif ( isset( $value[0] ) && is_array( $value[0] ) ) {
					$cleaned_data[ $key ] = array_map( array( $this, 'sanitize_complex_field' ), $value );
				} else {
					$cleaned_data[ $key ] = $this->sanitize_complex_field( $value );
				}
			} else {
				$cleaned_data[ $key ] = $value;
			}
		}

		return $cleaned_data;
	}
}
