<?php namespace Concore\Foundation\Services;

use Concore\Sculpt\Exceptions\FileExistsException;
use Concore\Sculpt\Exceptions\ImageTooHighResolutionException;
use File, Storage, Config, Image, Cache;

class MediaService {

	public function getMedia($type, $filename) {
		$media = app('Concore\Foundation\Models\Media');
        return $media->where('type','=',$type)->where('filename','=',$filename)->first();
	}

	public function fileExists($path) {
		return Storage::exists($path);
	}

	public function getFile($media) {
        if($this->fileExists($media->path)) {
            return Storage::get($media->path);
        }
        return false;
	}

    public function upload($uploaded_file, $media, $allow_duplicates = false) {
        // open and closing brackets causes problems when trying to reach image using path
        $media->filename = $this->sanitize_filename($media->filename);
    	if($this->fileExists($media->path)) {
            $duplicate_in_db = $media->where('filename','=',$media->filename)->first();
            // If we're not allowing duplicates and the duplicate is indeed in the database
            if(!$allow_duplicates && $duplicate_in_db) {
                throw new FileExistsException('', 0, null, $media->where('filename','=',$media->filename)->first());
            }
            // If we're allowing duplicates or the media isn't in the database, increment the number and add it
            else {
                $increment = 1;
                $incremented = preg_replace('/\.(\w{2,4})$/','-' . $increment . '.$1',$media->path);
                while($this->fileExists($incremented)) {
                    $increment++;
                    $incremented = preg_replace('/\-\d+\.(\w{2,4})$/','-' . $increment . '.$1',$incremented);
                }
                $path_parts = explode('/',$incremented);
                $media->filename = array_pop($path_parts);
            }
        }
        $max_size = setting_or_config('foundation.media.max_image_pixel_size');
        if(substr($media->mimetype, 0, 5) == 'image') {
            if($max_size) {
                list($width, $height) = getimagesize($uploaded_file->getPathName());
                if(max($width, $height) > $max_size) {
                    throw new ImageTooHighResolutionException;
                }
            }
            $stream = Image::make($uploaded_file->getRealPath())->stream($media->mimetype)->detach();
        } else {
            $stream = fopen($uploaded_file->getRealPath(), 'r');
        }
        return Storage::disk()->put($media->path, $stream, setting_or_config('foundation.media.default-visibility'));
    }

	public function deleteFile($media) {
        if(!Storage::exists($media->path)) {
            return true;
        } else {
            // Delete resized versions
            if($media->type == 'image' && $media->generated_sizes) {
                foreach($media->getGeneratedSizes() as $size_string) {
                    if(Storage::exists($media->getSizePath($size_string))) {
                        Storage::delete($media->getSizePath($size_string));
                    }
                }
            }
            return Storage::delete($media->path);
        }
	}

    public function isAllowed($media) {
        if (setting_or_config('foundation.media.allow_all_mimetypes', false) === true) {
            return true;
        }
        return in_array(strtolower($media->mimetype),array_flatten(setting_or_config('foundation.media.allowed_mimetypes')));
    }

    public function getType($mimetype) {
    	foreach(setting_or_config('foundation.media.allowed_mimetypes') as $type => $mimetypes) {
    		if(in_array(strtolower($mimetype),$mimetypes)) {
    			return $type;
    		}
    	}
        if (setting_or_config('foundation.media.allow_all_mimetypes', false) === true) {
            return 'document';
        }
    	return null;
    }

    // Next two methods borrowed from http://stackoverflow.com/questions/13076480/php-get-actual-maximum-upload-size

    public function maxAllowedFileSize() {
        return $this->getMaxFileUploadSize();
    }

    public function getMaxFileUploadSize() {
        static $max_size = -1;

        if ($max_size < 0) {
            // Start with post_max_size.
            $max_size = $this->parse_size(ini_get('post_max_size'));

            // If upload_max_size is less, then reduce. Except if upload_max_size is
            // zero, which indicates no limit.
            $upload_max = $this->parse_size(ini_get('upload_max_filesize'));
            if ($upload_max > 0 && $upload_max < $max_size) {
            $max_size = $upload_max;
            }
        }
        return $max_size;
    }

    public function getImage($size_string, $filename) {
        $quality = 90;
        if (strpos($size_string, '@') !== false) {
            list($size,$quality) = explode('@', $size_string);
        }
        if ($image_object = $this->getImageObject($size_string, $filename)) {
            return $image_object->response(null,$quality);
        }
        else {
            return false;
        }
    }

    public function getImageObject($size_string, $filename) {
        $media = $this->getMedia('image', $filename);
        $quality = 90;
        if(!$media || !$this->fileExists($media->path)) {
            return false;
        }
        $media_service = $this;
        $cache_duration = 10;
        if (strpos($size_string, '@') !== false) {
            list($size,$quality) = explode('@', $size_string);
        } else {
            $size = $size_string;
        }
        if (strpos($size, 'x') !== false) {
            list($width, $height) = explode('x', $size);
            if (empty($width)) {
                $width = null;
            }
        } else {
            $width = $size;
            $height = null;
        }
        // Cache individual operations and resulting image object
        $image = Image::cache(function ($image) use ($media_service, $media, $size_string, $width, $height, $quality) {
            $media_service->processImage($image, $media_service, $media, $size_string, $width, $height);
        }, $cache_duration, false);
        return Image::make($image);
    }

    protected function processImage(&$image, $media_service, $media, $size_string, $width, $height) {
        $image->make($media_service->getFile($media), false);
        $image->interlace(true);
        if ($size_string !== 'original') {
            if ($width && !$height) {
                $image->widen($width);
            } else if ($height && !$width) {
                $image->heighten($height);
            } else {
                $image->fit($width, $height);
            }
        }
    }

    function parse_size($size) {
        $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
        $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
        if ($unit) {
            // Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
            return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
        }
        else {
            return round($size);
        }
    }

    protected function sanitize_filename($string) {
        return preg_replace("([^\w\s\d\-_~,;\[\]\(\).])", '', $string);
    }

}
