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

use Illuminate\Database\Eloquent\Builder;
use Eae\Database\Eloquent\Relations\BelongsToManyWebsite;
use Eae\Support\Contracts\SavableFieldInterface;
use Eae\Exception\InvalidConfigurationException;
use LaravelLocalization;
use View;
use DB;
use Input;
use WebsiteObject;
use Eae\Backoffice\Generic\ContentType;
use Config;
use ContentTypes;

class MultiplePickerField extends BaseField implements SavableFieldInterface{
    protected $order = false;
    protected $objectTypes = false;
    protected $maxSize = false;
    protected $longList = false;
    protected $minSize = 0;
    protected $websiteFiltered = false;
    protected $allowInsert = false;

    public function __construct($config){
        unset($config["multiLanguage"]);
        unset($config["inList"]);
        unset($config["search"]);
        unset($config["sort"]);

        parent::__construct($config);

        $this->relationField = true;

        if(empty($config["objectTypes"])){
            throw new InvalidConfigurationException("The {$this->name} configuration is missing the object types");
        }

        $this->objectTypes = $config["objectTypes"];

        if(!empty($config["websiteFiltered"])){
            $this->websiteFiltered = $config["websiteFiltered"];
        }

        if($this->websiteFiltered === false && count($this->objectTypes) > 1){
            throw new InvalidConfigurationException("The {$this->name} multi picker field cannot have more than one object type if it is not multi website");
        }

        if(!empty($config["order"])){
            $this->order = $config["order"];
        }

        if(!empty($config["maxSize"])){
            $this->maxSize = $config["maxSize"];
        }

        if(!empty($config["minSize"])){
            $this->minSize = $config["minSize"];
        }

        if(!empty($config["allowInsert"]) && !$this->isMultipleTypes()){
            $this->allowInsert = $config["allowInsert"];
        }


        if(!empty($config["longList"])){
            $this->longList = $config["longList"];
        }

    }

    public function isOrderable(){
        return $this->order;
    }

    public function setOrderable($order){
        $this->order = $order;
    }

    public function getObjectTypes(){
        return $this->objectTypes;
    }

    public function getObjectTypesModelsType(){
        $modelsType = array();
        foreach($this->objectTypes as $objectType){
            $contentType = ContentTypes::find($objectType);
            $modelsType[] = $contentType->getModelType();

        }
        return $modelsType;
    }

    public function getContentTypes(){
        $contentTypes = array();
        foreach($this->objectTypes as $objectType){
            $contentType = ContentTypes::find($objectType);
            $contentTypes[] = $contentType;
        }
        return $contentTypes;
    }

    public function setObjectTypes($objectTypes = array()){
        $this->objectTypes = $objectTypes;
    }

    public function isMultipleTypes(){
        return !empty($this->objectTypes) && count($this->objectTypes) > 1;
    }

    public function setWebsiteFiltered($websiteFiltered){
        $this->websiteFiltered = $websiteFiltered;
    }

    public function isWebsiteFiltered(){
        return $this->websiteFiltered;
    }

    public function getMaxSize(){
        return $this->maxSize;
    }

    public function setMaxSize($maxSize){
        $this->maxSize = $maxSize;
    }

    public function getMinSize(){
        return $this->minSize;
    }

    public function setMinSize($minSize = 0){
        $this->minSize = $minSize;
    }

    public function getAllowInsert(){
        return $this->allowInsert;
    }

    public function setAllowInsert($allowInsert){
        $this->allowInsert = $allowInsert;
    }

    public function isLongList(){
        return $this->longList;
    }

    public function setLongList($longList){
        $this->longList = $longList;
    }

    public function getValidation(){
        $rules = "array";

        if($this->minSize > 0){
            if($this->parent){
                $rules .= "|required_if:{$this->parent["name"]}," . implode(",", $this->parent["values"]);
                $parentValue = Input::get($this->parent["name"], null);
                if(!is_null($parentValue) && in_array($parentValue,$this->parent["values"])){
                    $rules .= "|min:" . $this->minSize;
                }
            }else{
                $rules .= "|required|min:" . $this->minSize;
            }
        }

        if($this->maxSize > 0){
            $rules .= "|max:" . $this->maxSize;
        }

        return $rules;
    }

    public function toForm($model, $enabled = true, $hidden = false){
        if(!$this->isLongList()){
            if($this->isWebsiteFiltered()){
                return $this->_toFormWebsite($model, $enabled, $hidden);
            }else{
                return $this->_toFormNoWebsite($model, $enabled, $hidden);
            }
        }else{
            if($this->isWebsiteFiltered() || $this->isMultipleTypes()){
                throw new InvalidConfigurationException("A long list multipickerfield cannot be website or multiple types");
            }
            return $this->_toFormLongListNoWebsite($model, $enabled, $hidden);
        }
    }

    public function _toFormWebsite($model, $enabled, $hidden){
        if(empty($this->objectTypes)){
            return "";
        }

        $websiteModel = new WebsiteObject;
        $relation = $websiteModel->related();

        $modelsTypes = $this->getObjectTypesModelsType();


        if(empty($modelsTypes)){
            return "";
        }

        $query = WebsiteObject::with("objectable")
            ->whereIn("object_type", $modelsTypes);


        $objects = $query->get();

        $fullList = array();

        foreach($this->getContentTypes($websiteId) as $contentType){

            $fullList[$contentType->getModelType()] = array(
                "label" => ucfirst($contentType->getLabel()),
                "list" => array());
        }

        foreach($objects as $object){
            //    var_dump($objects); die;
            $fullList[$object->object_type]["list"][] = (object) array(
                "id" => $object->id,
                "title" => $object->objectable->title,
                "object_id" => $object->objectable->id
            );
        }

        foreach($fullList as $listType){
            usort($listType["list"], function( $firstItem, $secondItem){
                if ($firstItem->title == $secondItem->title) {
                    return 0;
                }

                return ($firstItem->title < $secondItem->title) ? -1 : 1;
            });

        }

        $postData = Input::old($this->getName());
        $pickedList = array();
        if(!empty($postData)){
            $pickedList = json_decode($postData);
        }elseif($model->exists){
            $websiteObjectModel = $model->getActiveWebsiteEntry();

            $query = DB::table($relation->getTable())
                ->where($relation->getForeignKey(), '=' , $websiteObjectModel->id)
                ->select($relation->getOtherKey() . " as id");

            if($this->isOrderable()){
                $query->orderBy($relation->getTable() . ".position", "asc");
            }

            $pickedList = $query->get();
        }

        return View::make(
            "admin.generic.components.forms.multiplepicker",
            array(
                "id"                => $this->getName(),
                "name"              => $this->getName(),
                "errorKey"          => $this->getName(),
                "label"             => $this->getLabel(),
                "order"             => $this->isOrderable(),
                "maxSize"           => $this->getMaxSize(),
                "fullList"          => $fullList,
                "pickedList"        => $pickedList,
                "multipleTypes"     => $this->isMultipleTypes(),
                "hide"              => $hidden,
                "enabled"           => $enabled,
                "parentHidden"      => ($hidden && !empty($this->parent)),
                "parent"            => $this->getParent(),
                "allowInsert"       => $this->getAllowInsert(),
                "websiteFiltered"   => $this->isWebsiteFiltered(),
                "info"              => $this->getInfo()
            ));
    }

    public function _toFormLongListNoWebsite($model, $enabled, $hidden){
        $contentType = head($this->getContentTypes());
        $relationshipName = $this->name;
        $relationship = $model->$relationshipName();
        $relationTableName = $relationship->getTable();
        $relationModel = $relationship->getRelated();

        $query = $relationModel->full()
            ->select("id", "title", "id as object_id")
            ->join($relationTableName, $relationship->getOtherKey() , "=", $relationModel->getQualifiedKeyName());

        if($this->isOrderable()){
            $query->orderBy("{$relationTableName}.position", "asc");
        }else{
            $query->orderBy("title", "asc");
        }

        $postData = Input::old($this->getName());

        if($model->exists){
            $query->where($relationship->getForeignKey(), '=' , $model->id);
            $pickedList = $query->get();
        }elseif(!empty($postData) && is_array($postData)){
            $query->whereIn($relationModel->getQualifiedKeyName(), $postData);
            $pickedList = $query->get();
        }else{
            $pickedList = $relationModel->newCollection();
        }

        $pickedList = array(
            $contentType->getType() =>
                array("label" => ucfirst($contentType->getSingularLabel()),
                    "list" => $pickedList)
        );

        return View::make(
            "admin.generic.components.forms.multiplepickersearch",
            array(
                "id"                => $this->getName(),
                "name"              => $this->getName(),
                "errorKey"          => $this->getName(),
                "label"             => $this->getLabel(),
                "order"             => $this->isOrderable(),
                "maxSize"           => $this->getMaxSize(),
                "pickedList"        => $pickedList,
                "multipleTypes"     => false,
                "hide"              => $hidden,
                "enabled"           => $enabled,
                "parentHidden"      => ($hidden && !empty($this->parent)),
                "parent"            => $this->getParent(),
                "allowInsert"       => $this->getAllowInsert(),
                "websiteFiltered"   => $this->isWebsiteFiltered(),
                "info"              => $this->getInfo(),
                "searchUrl"         => lang_url("admin/content/auto-complete/" . $contentType->getType())
            ));


    }

    public function _toFormNoWebsite($model, $enabled, $hidden){
        $contentType = head($this->getContentTypes());

        $relationModelType = $contentType->getModelType();
        $relationModel = new $relationModelType;

        $query = $relationModel->full()
            ->select("id", "title", "id as object_id")->orderBy("title", "asc");
        $fullList = $query->get();

        $relationName = $this->getName();
        $relation = $model->$relationName();

        $fullList = array(
            $contentType->getType() =>
                array("label" => ucfirst($contentType->getSingularLabel()),
                    "list" => $fullList)
        );

        $postData = Input::old($this->getName());
        $pickedList = array();
        if(!empty($postData)){
            $pickedList = json_decode($postData);
        }elseif($model->exists){
            //var_dump($relation); die;
            $query = DB::table($relation->getTable())
                ->where($relation->getForeignKey(), '=' , $model->id)
                ->select($relation->getOtherKey() . " as id");

            if($this->isOrderable()){
                $query->orderBy($relation->getTable() . ".position", "asc");
            }

            $pickedList = $query->get();
        }

        return View::make(
            "admin.generic.components.forms.multiplepicker",
            array(
                "id"                => $this->getName(),
                "name"              => $this->getName(),
                "errorKey"          => $this->getName(),
                "label"             => $this->getLabel(),
                "order"             => $this->isOrderable(),
                "maxSize"           => $this->getMaxSize(),
                "fullList"          => $fullList,
                "pickedList"        => $pickedList,
                "multipleTypes"     => $this->isMultipleTypes(),
                "hide"              => $hidden,
                "enabled"           => $enabled,
                "parentHidden"      => ($hidden && !empty($this->parent)),
                "parent"            => $this->getParent(),
                "allowInsert"       => $this->getAllowInsert(),
                "websiteFiltered"   => $this->isWebsiteFiltered(),
                "info"              => $this->getInfo()
            ));
    }

    public function getValidationData($copyAllLang = false){
        $contentTypes = $this->getContentTypes();
        if($this->isWebsiteFiltered() && empty($contentTypes)){
            return null;
        }

        $validation = array(
            "rules" => array(),
            "values" => array(),
            "labels" => array());

        $fieldName = $this->getName();
        $value = Input::get($fieldName);
        $value = json_decode($value,true);
        $rules = $this->getValidation();

        if(!empty($rules)){
            $validation["rules"][$fieldName] = $this->getValidation();
            $validation["labels"][$fieldName] = $this->getLabel();
        }
        $validation["values"][$fieldName] = $value;
        return $validation;
    }

    public function save($model, $values){
        if($this->isWebsiteFiltered()){
            return $this->_saveWebsite($model, $values);
        }else{
            return $this->_saveNoWebsite($model, $values);
        }
    }

    protected function _saveNoWebsite($model, $values){
        $relationName = $this->getName();
        $relation = $model->$relationName();

        $ids = array_flatten($values);

        if($this->isOrderable()){
            $syncData = array();
            $position = 1;
            foreach($ids as $id){
                $syncData[$id] = array("position" => $position);
                $position = $position + 1;
            }
            $model->$relationName()->sync($syncData);
        }else{
            $model->$relationName()->sync($ids);
        }
    }

    protected function _saveWebsite($model, $values){
        if(empty($this->objectTypes)){
            return;
        }

        $type = $this->getName();
        $websiteObject = $model->getActiveWebsiteEntry();
        $relation = $websiteObject->related();

        $ids = array_flatten($values);

        if($this->isOrderable()){
            $syncData = array();
            $position = 1;
            foreach($ids as $id){
                $syncData[$id] = array("position" => $position, "type" => $type);
                $position = $position + 1;
            }
            $relation->wherePivot("type", $type)->sync($syncData);
        }else{
            $syncData = array();
            foreach($ids as $id){
                $syncData[$id] = array("type" => $type);
            }
            $relation->wherePivot("type", $type)->sync($syncData);
        }
    }

    public function toArray(){
        $array = parent::toArray();
        $array["maxSize"] = $this->maxSize;
        $array["minSize"] = $this->minSize;
        return $array;
    }

    public static function getScript(){
        return array("multiplePicker" =>
            Config::get('path.backoffice.js_path') . '/view/generic/backend-multiple-picker.js',
            Config::get('path.backoffice.js_path') . '/view/generic/backend-multiple-picker-search.js');

    }
}


