<?php namespace Eae\Backoffice\Generic\Fields;

use Illuminate\Database\Eloquent\Builder;
use Eae\Database\Eloquent\Relations\BelongsToManyWebsite;
use Eae\Support\Contracts\SavableFieldInterface;
use Eae\Support\Contracts\SearchableFieldInterface;
use LaravelLocalization;
use View;
use DB;
use Input;
use MediaItem;
use Config;
use Image;

class MediaPickerField extends BaseField implements SavableFieldInterface, SearchableFieldInterface{
    protected $websiteFilter = false;
    protected $maxSize = false;
    protected $minSize = 0;
    protected $multiple = false;
    protected $thumbnailSizes = array();
    protected $relatedContentType = false;
    
    public function __construct($config){
        unset($config["inList"]);
        unset($config["search"]);
        unset($config["sort"]);

        parent::__construct($config);
        
        if(!empty($config["mediaType"])){
            $this->mediaType = $config["mediaType"];    
        }
        
        if(!empty($config["fieldId"])){
            $this->fieldId = $config["fieldId"];    
        } 
        
        if(!empty($config["maxSize"])){
            $this->maxSize = $config["maxSize"];    
        }
        
        if(!empty($config["minSize"])){
            $this->minSize = $config["minSize"];    
        }
        
        if(!empty($config["multiple"])){
            $this->multiple = $config["multiple"];    
        }
        
        if(!empty($config["thumbnailSizes"])){
            $this->thumbnailSizes = $config["thumbnailSizes"];    
        }
        
        if(!empty($config["relatedContentType"])){
            $this->relatedContentType = $config["relatedContentType"];    
        }
        
        if($this->multiple || $this->multiLanguage){
            $this->relationField = true;
        }
    }
    
    public function getMediaType(){
        return $this->mediaType;    
    }
    
    public function setMediaType($mediaType){
        $this->mediaType = $mediaType;
    }
    
    public function isMultiple(){
        return $this->multiple;    
    }
    
    public function setMultiple($multiple){
        $this->multiple = $multiple;
    }
    
    public function getValidation(){
        $rules = "array";
        
        if($this->minSize > 0){
            $rules .= "|required|min:" . $this->minSize;    
        }
        
        if($this->maxSize > 0){
            $rules .= "|max:" . $this->maxSize;    
        }
        
        return $rules;
    }
    
    public function toForm($model, $enabled = true, $hidden = false){
        $fieldName = $this->getName();
        $mediaItems = [];
        $html = "";

        if($this->isMultiLanguage()){
            $locales = LaravelLocalization::getSupportedLocales();
            $defaultLocale = LaravelLocalization::getDefaultLocale();
            $postData = Input::old($this->getName());
            foreach($locales as $locale => $localeData){
                $name = $fieldName . "[{$locale}]";
                $id = $fieldName . "_{$locale}";
                $errorKey = $fieldName . "." . $locale; 
                $value = null;
                $mediaItems = [];
                
                if(!empty($postData)){
                    $ids = json_decode($postData[$locale]);
                    if (sizeof($ids) > 0) {
                        $idsString = implode(',', $ids);
                        $mediaItems = MediaItem::whereIn('id', $ids)
                            ->orderByRaw(DB::raw("FIELD(id, $idsString)"))
                            ->get(); 
                    } 
                } else if ($model->exists) {
                    $relation = $model->$fieldName();
                    $query = $model->$fieldName()->wherePivot("language_id", $locale);
                    if ($this->multiple) {
                        $query->orderBy($model->$fieldName()->getTable() . '.position', 'asc');
                    }    
                    $mediaItemsLangs = $query->get();
                    if (!$this->multiple) {
                        if (!$mediaItemsLangs->isEmpty()) {
                            $mediaItems[] = $mediaItemsLangs->first();
                        }
                    } else {
                        foreach ($mediaItemsLangs as $mediaItem) {
                            $mediaItems[] = $mediaItem;
                        }
                    }
                } 

                $html .= View::make(
                    "admin.generic.components.forms.mediapicker", 
                    array(
                        "id"                => $id,
                        "name"              => $name,
                        "errorKey"          => $errorKey,
                        "label"             => $this->getLabel(),
                        "mediaType"         => $this->getMediaType(),
                        "mediaItems"        => $mediaItems,
                        "multiple"          => $this->multiple,
                        "minSize"           => $this->minSize,
                        "maxSize"           => $this->maxSize,
                        "language"          => $locale,
                        "defaultLang"       => $defaultLocale,
                        "hide"              => ($hidden || $locale != $defaultLocale),
                        "enabled"           => $enabled,
                        "relatedContentType"=> $this->relatedContentType,
                        "parentHidden"  => ($hidden && !empty($this->parent)),
                        "parent"        => $this->parent,
                        "info"          => $this->getInfo()    
                    ));    
            }    
        } else {
            $postData = Input::old($this->getName());
            if(!empty($postData)){
                $ids = json_decode($postData);
                if (sizeof($ids) > 0) {
                    $idsString = implode(',', $ids);
                    $mediaItems = MediaItem::whereIn('id', $ids)
                        ->orderByRaw(DB::raw("FIELD(id, $idsString)"))
                        ->get(); 
                } 
            } else if ($model->exists) { 
                if (!$this->multiple) {
                    if ($model->$fieldName) {
                        $mediaItems[] = $model->$fieldName;
                    }
                } else {
                    $items = $model->$fieldName()->orderBy('position', 'asc')->get();
                    foreach ($items as $mediaItem) {
                        $mediaItems[] = $mediaItem;
                    }
                }
            }
  
            $html .= View::make(
                "admin.generic.components.forms.mediapicker", 
                array(
                    "id"                => $this->getName(),
                    "name"              => $this->getName(),
                    "errorKey"          => $this->getName(),
                    "label"             => $this->getLabel(),
                    "mediaType"         => $this->getMediaType(),
                    "mediaItems"        => $mediaItems,
                    "multiple"          => $this->multiple,
                    "minSize"           => $this->minSize,
                    "maxSize"           => $this->maxSize,
                    "hide"              => $hidden,
                    "enabled"           => $enabled,
                    "relatedContentType"=> $this->relatedContentType,
                    "parentHidden"  => ($hidden && !empty($this->parent)),
                    "parent"        => $this->parent,
                    "info"          => $this->getInfo()    
                )); 
        }
        return $html;
    }
    
    public function getValidationData($copyAllLang = false){
        $validation = array(
            "rules" => array(), 
            "values" => "", 
            "labels" => array());
        
        $fieldName = $this->getName();
        $value = Input::get($fieldName);
        if ($this->isMultiLanguage()) {
            foreach ($value as $lang => $langValue) {
                $value[$lang] = json_decode($langValue, true);
            }
            
            $defaultLocale = \Config::get('app.locale');
            $locales = LaravelLocalization::getSupportedLanguagesKeys();
            
            if($copyAllLang){
                foreach($locales as $locale){
                    if($locale == $defaultLocale){
                        continue;
                    }  

                    if(empty($value[$locale])){
                        $value[$locale] = $value[$defaultLocale];        
                    }
                }    
            }
            
        } else { 
            $value = json_decode($value,true);    
        } 

        $rules = $this->getValidation(); 
        if(!empty($rules)){
            if ($this->isMultiLanguage()) {
                $validation["rules"] = generateLangRules(
                    array($fieldName => $rules), 
                    $locales);
                    
                $validation["labels"] = generateLangLabels(
                    $fieldName, $this->getLabel(), $locales); 
            } else {
                $validation["rules"][$fieldName] = $this->getValidation();
                $validation["labels"][$fieldName] = $this->getLabel();
            }
        }
        $validation["values"][$fieldName] = $value;
        return $validation;
    }
    
    public function save($model, $values){  
        if($this->isMultiLanguage()){
            $this->_saveMultipleLanguages($model, $values);    
        }else{
            if ($this->isRelationField()) {
                $this->_saveSingleLanguage($model, $values);
            } else {
                $this->_saveSingle($model, $values);
            }  
        }   
    }
    
    protected function _saveSingle($model, $value) {
        $fieldName = $this->getName();
        $fkName = $model->$fieldName()->getForeignKey();
        $model->$fkName = empty($value) ? null : $value[0];
        if (!empty($value)) {
            $this->_generateThumbnails($value[0]);
        }
    }
    
    protected function _generateThumbnails($mediaItemId) {
        if (sizeof($this->thumbnailSizes) == 0) {
            return;
        } 
        $mediaItem = MediaItem::find($mediaItemId);

        if (empty($mediaItem) || $mediaItem->media_type != MediaItem::MEDIA_TYPE_IMAGE) {
            return;
        }
         
        foreach ($this->thumbnailSizes as $size) {
            if (!isset($size["name"]) || empty($size["width"]) || empty($size["width"])) {
                throw new InvalidConfigurationException("All the sizes for generic backoffice fields of type 'image' must have a name, width and height in the configuration");    
            }
            $destinationPath = Config::get('path.internal.thumbs');
            $fileName = $mediaItem->filename;
            $thumbFilename = getFileNameSize("{$destinationPath}/{$fileName}",$size["name"]);
           
            $originalImage = Config::get('path.internal.media') . '/' . $fileName; 

            if (file_exists($thumbFilename)) {
                continue;
            }

            $quality = 90;
            if ($size["width"] > 1000) {
                $quality = 60;
            } else if ($size["width"] > 600) {
                $quality = 75;
            }
          
            switch($size["type"]){
                case "fit":   
                    Image::make($originalImage)
                        ->fit($size["width"], $size["height"])
                        ->save($thumbFilename, $quality);
                    break;    
                case "resize":
                    if(!isset($size["keepRatio"]) || $size["keepRatio"] === true){
                        Image::make($originalImage)
                            ->resize($size["width"], $size["height"], function ($constraint){
                                $constraint->aspectRatio();           
                            })
                            ->resizeCanvas($size["width"], $size["height"])
                            ->save($thumbFilename, $quality);    
                    }else{ 
                        Image::make($originalImage)
                            ->resize($size["width"], $size["height"])
                            ->save($thumbFilename, $quality);    
                    }
                    break;
                default:
                    throw new InvalidConfigurationException("The types allowed for for generic backoffice fields of type 'image' are fit or resize in the configuration");
            }
        }
    }
    
    protected function _saveMultipleLanguages($model, $values){
        $relationName = $this->getName();
        $relation = $model->$relationName();

        $locales = LaravelLocalization::getSupportedLocales();
        foreach($locales as $locale => $localeData){
            $langValues = $values[$locale];
            $syncData = array();
            $position = 1;
            
            foreach($langValues as $id){
                $syncData[$id] = array("language_id" => $locale);
                
                if($this->isMultiple()){
                    $syncData[$id]["position"] = $position;
                    $position = $position + 1;    
                }
                
                $this->_generateThumbnails($id);    
            }    
            
            $model->$relationName()->wherePivot("language_id", $locale)->sync($syncData);    
        }
          
    }
    
    protected function _saveSingleLanguage($model, $values){
        $relationName = $this->getName();
        $relation = $model->$relationName();

        $syncData = array();
        $position = 1;
        foreach($values as $id){
            $syncData[$id] = array("position" => $position);
            $position = $position + 1;
            
            $this->_generateThumbnails($id);
        }
        $model->$relationName()->sync($syncData);       
    }
    
    public function getSearchStructure($model, $view = false){
        $searchData = array();
        
        if($this->isMultiLanguage() || $this->isRelationField()){
            return $searchData;                                                                
        }
       
        $fieldName = $this->getName();
        $fkName = $model->$fieldName()->getForeignKey();

        if(!empty($model->$fkName)){
            $languages = LaravelLocalization::getSupportedLocales();
            
            foreach($languages as $language){
                
                $searchData[$language] = $model->$fkName;           
            }
        }
  
        return $searchData;
    }
    
    public function toArray(){
        $array = parent::toArray();
        //$array["maxSize"] = $this->maxSize;
        //$array["minSize"] = $this->minSize;
        return $array;  
    }
    
    public static function getScript(){
        return array("mediaPicker" => 
            Config::get('path.backoffice.js_path') . '/view/generic/backend-media-picker.js');
        
    }
}