<?php

if (!defined('BASEPATH')) {
    exit('No direct script access allowed');
}

/**
 * Resize image on fly
 *
 * @author Igor Ratsun
 */
class Image
{

    protected $options = [
        'sourcePath'      => 'assets/uploads/multimedia/images',
        'croppedPath'     => 'assets/uploads/cropped',
        'proccessLibrary' => 'image_lib', // image_change or image_lib
        'watermark'       => [],
        'quality'         => 80,
        'backgroundRGB'   => [255, 255, 255],
    ];
    protected $mobile = [
        'width'  => 0,
        'height' => 0,
        'file'   => '',
    ];

    public function __construct($options = [])
    {
        // Set options
        if (is_array($options)) {
            foreach ($options as $option => $value) {
                $method = 'set' . ucfirst($option);
                $this->{$method}($value);
            }
        }
    }

    /**
     * Getters and setters magic
     * @param string $name
     * @param mixed $arg
     */
    public function __call(string $name, $arg)
    {
        $key = lcfirst(str_replace(['set', 'get'], '', $name));
        if (str_starts_with($name, 'set') && isset($arg[0], $this->options[$key])) {
            $this->options[$key] = $arg[0];

            return $this;
        }

        if (str_starts_with($name, 'get') && isset($this->options[$key])) {

            return $this->options[$key];
        }
    }

    /**
     * Create image if needed and return full image path
     * @param string $file
     * @param int $width
     * @param int $height
     * @return string
     */
    public function getImage(string $file = '', int $width = 0, int $height = 0): string
    {
        // If mobile
        if (!empty($this->mobile['width']) && !empty($this->mobile['height'])) {
            $width = $this->mobile['width'];
            $height = $this->mobile['height'];
            if (!empty($this->mobile['file'])) {
                $file = $this->mobile['file'];
            }
            // Clear mobile, avoid collision
            $this->mobile = [];
        }

        $srcFile = trim(str_replace(array('./', '../', $this->getSourcePath()), '', trim($file, '/')), '/');
        $srcFullPath = $this->getSourcePath() . '/' . $srcFile;
        if (empty($srcFile) || !file_exists($srcFullPath) || is_dir($srcFullPath)) {

            return '';
        }

        // prepare width, height
        if (empty($width) || empty($height)) {
            list($width, $height) = $this->prepareImageParams($srcFullPath, $width, $height);
        }

        // get cropped file
        $croppedFile = $srcFullPath;
        if (!empty($width) && !empty($height)) {
            $croppedFile = $this->createCrropedPath($srcFile, $width, $height)
                    . '/' . pathinfo($srcFile, PATHINFO_FILENAME)
                    . '.' . pathinfo($srcFile, PATHINFO_EXTENSION);
            if (!file_exists($croppedFile)) {
                $this->resize($srcFullPath, $croppedFile, $width, $height);
                $this->watermark($croppedFile);
            }
        }

        return base_url($croppedFile);
    }

    /**
     * Clear file from all cropped folders
     * @param string $file
     */
    public function clearCropped(string $file = ''): int
    {
        $cleared = 0;
        $root = trim($this->getCroppedPath(), '/');
        if (file_exists($root) && is_dir($root)) {
            foreach (array_diff(scandir($root), ['..', '.']) as $folder) {
                if (is_dir($root . '/' . $folder) && file_exists($root . '/' . $folder . '/' . $file)) {
                    unlink($root . '/' . $folder . '/' . $file);
                    $cleared++;
                }
            }
        }

        return $cleared;
    }

    /**
     * Resize image
     * @param string $srcFile
     * @param string $newFile
     * @param integer $width
     * @param integer $height
     * @return boolean
     */
    public function resize(string $srcFile, string $newFile, int $width, int $height): bool
    {
        $ci = & get_instance();

        if ($this->getProccessLibrary() == 'image_lib') {
            $config['image_library'] = 'gd2';
            $config['source_image'] = $srcFile;
            $config['new_image'] = $newFile;
            $config['maintain_ratio'] = false;
            $config['width'] = $width;
            $config['height'] = $height;
            $config['quality'] = $this->getQuality();
            $ci->load->library('image_lib');
            $ci->image_lib->initialize($config);

            return $ci->image_lib->resize();
        }

        if ($this->getProccessLibrary() == 'image_change') {
            copy($srcFile, $newFile);
            $ci->load->library('image_change', $newFile);
            $image = new Image_change($newFile);
            $image->set_background_rgb($this->getBackgroundRGB())->resize($width, $height);

            return $image->save($newFile, $this->getQuality());
        }

        return false;
    }

    /**
     * Set watermark to image
     * @param string $srcImage
     * @return boolean
     */
    public function watermark($srcImage)
    {
        if (!empty($this->getWatermark())) {
            $ci = & get_instance();
            $ci->load->library('image_lib');
            $config = $this->getWatermark();
            $config['source_image'] = $srcImage;
            $ci->image_lib->initialize($config);
            $ci->image_lib->watermark();

            return true;
        }

        return false;
    }

    /**
     * Change configuration for mobile devices
     * @param integer $width
     * @param integer $height
     * @param string $file
     * @return $this
     */
    public function mobile($width = 0, $height = 0, $file = '')
    {
        if (!empty($width) && !empty($height) && get_instance()->load->library('user_agent')->is_mobile()) {
            $this->mobile = compact('width', 'height', 'file');
        }

        return $this;
    }

    protected function createCrropedPath($file = '', $width = 0, $height = 0)
    {
        $filePath = trim(pathinfo($file, PATHINFO_DIRNAME), '/');
        $path = trim($this->getCroppedPath(), '/') . '/' . $width . '_' . $height . ($filePath == '.' ? '' : '/' . $filePath);

        if (!file_exists($path)) {
            if (!mkdir($path, 0775, true)) {
                show_error('Can\'t create folder `' . $path . '`');
            }
        }

        return $path;
    }

    /**
     * Prepare image params
     *
     * @param str $file
     * @param int $width
     * @param int $height
     *
     * @return array
     */
    protected function prepareImageParams($file, $width, $height)
    {
        if (file_exists($file)) {
            list($fileWidth, $fileHeigth) = getimagesize($file);

            if (empty($width)) {
                $width = $fileWidth * ($height / $fileHeigth);
            } elseif (empty($height)) {
                $height = $fileHeigth * ($width / $fileWidth);
            }
        }

        return [(int) $width, (int) $height];
    }
}
