<?php

class WP_Site_Icon_Admin_Processing {
	public function __construct() {

		add_action( 'delete_attachment', array( $this, 'delete_attachment_data' ), 10, 1 );
		add_filter( 'get_post_metadata', array( $this, 'get_post_metadata' ), 10, 4 );
	}

	/**
	 * Upload a Site Icon image.
	 *
	 * This method is only used by the no Javascript admin UI flow.
	 *
	 * @since 4.3.0
	 */
	public function upload_site_icon_image() {
		// Verify that the uploaded file is an image.
		$file_type = wp_check_filetype_and_ext( $_FILES['site-icon']['tmp_name'], $_FILES['site-icon']['name'] );
		if ( ! wp_match_mime_types( 'image', $file_type['type'] ) ) {
			wp_die( __( 'The uploaded file is not a valid image. Please try again.' ) );
		}

		// Upload image.
		$file_attributes = wp_handle_upload( $_FILES['site-icon'], array( 'test_form' => false ) );
		if ( isset( $file_attributes['error'] ) ) {
			wp_die( $file_attributes['error'], __( 'Image Upload Error' ) );
		}

		// Save image as an attachment.
		$attachment_id = wp_insert_attachment( array(
			'post_title'     => basename( $file_attributes['file'] ),
			'post_content'   => $file_attributes['url'],
			'post_mime_type' => $file_attributes['type'],
			'guid'           => $file_attributes['url'],
			'context'        => 'site-icon',
		),
			$file_attributes['file'] );

		if ( 0 === $attachment_id || is_wp_error( $attachment_id ) ) {
			wp_die( __( 'Could not save the uploaded image.' ) );
		}

		return $attachment_id;
	}

	public function get_image_size_from_attachment( $attachment_id ) {
		$image_file = get_attached_file( absint( $attachment_id ), true );

		if ( ! $image_file ) {
			wp_die( __( 'The uploaded image is corrupted.' ) );
		}

		return getimagesize( $image_file );
	}

	/**
	 * Checks whether the uploaded image is large enough to be a Site Icon.
	 *
	 * @param int $attachment_id ID of the attachment containing the image.
	 * @param int $min_width     Minimum width in pixels.
	 * @param int $min_height    Minimum height in pixels.
	 *
	 * @return bool|array True if the image is large enough. An array with the errors if the image is too small.
	 */
	public function verify_site_icon_image_min_size( $attachment_id, $min_width, $min_height ) {
		$image_file = get_attached_file( absint( $attachment_id ), true );

		if ( ! $image_file ) {
			wp_die( __( 'The uploaded image is corrupted.' ) );
		}

		$image_size = getimagesize( $image_file );

		$errors = array();
		if ( $image_size[0] < $min_width ) {
			$errors['width'] = true;
		}

		if ( $image_size[1] < $min_height ) {
			$errors['height'] = true;
		}

		if ( $errors ) {
			return $errors;
		}

		return true;
	}

	public function get_attachment_image_size( $attachment_id ) {
		$image_file = get_attached_file( absint( $attachment_id ), true );

		if ( ! $image_file ) {
			wp_die( __( 'The uploaded image is corrupted.' ) );
		}

		return getimagesize( $image_file );
	}

	public function get_site_icon_image_url( $attachment_id ) {
		$image_data = wp_get_attachment_image_src( $attachment_id, 'full' );

		if ( ! $image_data ) {
			return false;
		}

		return $image_data[0];
	}

	/**
	 * Calculate the size of the image displayed on the cropping screen.
	 *
	 * @param $attachment_id
	 * @param $max_size
	 */
	public function calculate_height_of_image_for_cropping( $attachment_id, $max_width ) {
		// Get the size of the full image.
		$full_size = $this->get_attachment_image_size( absint( $attachment_id ) );

		// Calculate the relationship between the height and the width of the full image.
		$ratio = $full_size[1] / $full_size[0];

		// Multiply the max width of the image in the admin to get the correct height to keeping the ratio intact.
		return (int) floor( $max_width * $ratio );
	}

	public function calculate_default_values_for_crop( $width, $height ) {
		if ( $width < $height ) {
			// Portrait
			$crop_x    = 0;
			$crop_y    = absint( ( $height - $width ) / 2 );
			$crop_size = $width;
		} elseif ( $width > $height ) {
			// Landscape
			$crop_x    = absint( ( $width - $height ) / 2 );
			$crop_y    = 0;
			$crop_size = $height;
		} else {
			// Square
			$crop_x    = 0;
			$crop_y    = 0;
			$crop_size = $width;
		}

		return compact( 'crop_x', 'crop_y', 'crop_size' );
	}

	/**
	 * This function is used to pass data to the localize script
	 * so that we can center the cropper and also set the minimum
	 * cropper.
	 *
	 * @since 4.3.0
	 *
	 * @param float $ratio
	 * @param array $cropped_size
	 * @return array
	 */
	public function calculate_default_values_for_javascript_cropper( $ratio, $max_size,  $resized_width, $resized_height, $orginial_width, $original_height ) {
		$init_x = $init_y = $init_size = 0;
		$min_crop_size  = ( $max_size / $ratio );

		if ( $resized_width < $resized_height ) {
			// Portrait
			$init_y    = ( $max_size - $resized_width ) / 2;
			$init_size = $resized_height;
		} elseif ( $resized_width > $resized_height ) {
			// Landscape
			$init_x    = ( $max_size - $resized_height ) / 2;
			$init_size = $resized_height;
		} else {
			// Square
			$init_size = $resized_height;
		}

		return array(
			'init_x'    => (int) floor( $init_x ),
			'init_y'    => (int) floor($init_y ),
			'init_size' => $init_size,
			'min_size'  => (int) floor( $min_crop_size ),
			'width'     => $orginial_width,
			'height'    => $original_height,
		);
	}

	/**
	 * Converts the coordinates from the downsized image to the original image for accurate cropping.
	 *
	 * @since 4.3.0
	 *
	 * @param int   $crop_x
	 * @param int   $crop_y
	 * @param int   $crop_width
	 * @param int   $crop_height
	 * @param float $ratio
	 * @return array
	 */
	public function convert_coordinates_from_resized_to_full( $crop_x, $crop_y, $crop_width, $crop_height, $ratio ) {
		return array(
			'crop_x'      => floor( $crop_x * $ratio ),
			'crop_y'      => floor( $crop_y * $ratio ),
			'crop_width'  => floor( $crop_width * $ratio ),
			'crop_height' => floor( $crop_height * $ratio ),
		);
	}

	/**
	 * Create an attachment 'object'.
	 *
	 * @since 4.3.0
	 *
	 * @param string $cropped              Cropped image URL.
	 * @param int    $parent_attachment_id Attachment ID of parent image.
	 * @return array Attachment object.
	 */
	public function create_attachment_object( $cropped, $parent_attachment_id ) {
		$parent     = get_post( $parent_attachment_id );
		$parent_url = $parent->guid;
		$url        = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );

		$size       = @getimagesize( $cropped );
		$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';

		$object = array(
			'ID'             => $parent_attachment_id,
			'post_title'     => basename( $cropped ),
			'post_content'   => $url,
			'post_mime_type' => $image_type,
			'guid'           => $url,
			'context'        => 'site-icon'
		);

		return $object;
	}

	/**
	 * Insert an attachment and its metadata.
	 *
	 * @since 4.3.0
	 *
	 * @param array  $object  Attachment object.
	 * @param string $cropped Cropped image URL.
	 * @return int Attachment ID.
	 */
	public function insert_attachment( $object, $cropped ) {
		$attachment_id = wp_insert_attachment( $object, $cropped );
		$metadata      = wp_generate_attachment_metadata( $attachment_id, $cropped );

		/**
		 * Filter the site icon attachment metadata.
		 *
		 * @since 4.3.0
		 *
		 * @see wp_generate_attachment_metadata()
		 *
		 * @param array $metadata Attachment metadata.
		 */
		$metadata = apply_filters( 'site_icon_attachment_metadata', $metadata );
		wp_update_attachment_metadata( $attachment_id, $metadata );

		return $attachment_id;
	}

	/**
	 * Deletes all additional image sizes, used for site icons.
	 *
	 * @since 4.3.0
	 *
	 * @return bool
	 */
	public function delete_site_icon() {
		// We add the filter to make sure that we also delete all the added images.
		add_filter( 'intermediate_image_sizes', array( WP_Site_Icon::get_instance(), 'intermediate_image_sizes' ) );
		wp_delete_attachment( get_option( 'site_icon' ), true );
		remove_filter( 'intermediate_image_sizes', array( WP_Site_Icon::get_instance(), 'intermediate_image_sizes' ) );

		return delete_option( 'site_icon' );
	}

	/**
	 * Deletes the Site Icon when the image file is deleted.
	 *
	 * @since 4.3.0
	 *
	 * @param int $post_id Attachment ID.
	 */
	public function delete_attachment_data( $post_id ) {
		$site_icon_id = get_option( 'site_icon' );

		if ( $site_icon_id && $post_id == $site_icon_id ) {
			delete_option( 'site_icon' );
		}
	}

	/**
	 * Adds custom image sizes when meta data for an image is requested, that happens to be used as Site Icon.
	 *
	 * @since 4.3.0
	 *
	 * @param null|array|string $value    The value get_metadata() should
	 *                                    return - a single metadata value,
	 *                                    or an array of values.
	 * @param int               $post_id  Post ID.
	 * @param string            $meta_key Meta key.
	 * @param string|array      $single   Meta value, or an array of values.
	 * @return array|null|string
	 */
	public function get_post_metadata( $value, $post_id, $meta_key, $single ) {
		$site_icon_id = get_option( 'site_icon' );

		if ( $post_id == $site_icon_id && '_wp_attachment_backup_sizes' == $meta_key && $single ) {
			add_filter( 'intermediate_image_sizes', array( $this, 'intermediate_image_sizes' ) );
		}

		return $value;
	}

}