<?php

namespace Comitium5\DesignerBundle\Entity;

use Comitium5\DesignerBundle\Helper\Utils;
use Comitium5\DesignerBundle\Model\Interfaces\Layout\LayoutPageWidgetInterface;
use Comitium5\DesignerBundle\Model\Interfaces\SerializeInterface;
use Doctrine\ORM\PersistentCollection;
use Doctrine\Common\Collections\ArrayCollection;

/**
 * Class AbstractSerializeEntity
 *
 * @author Carles Gómez <carles@bab-soft.com>
 * @package Comitium5\DesignerBundle\Entity
 */
abstract class AbstractSerializeEntity extends AbstractEntity implements SerializeInterface
{
    /**
     * @param  array  $allowedFields (optional)
     * @param  array  $deniedFields  (optional)
     * @param  array  $entityFields  (optional)
     * @return array
     */
    public function toArray(
        $allowedFields = array(),
        $deniedFields = array(),
        $entityFields = array()
    ) {
        $result = array();

        $defaultLocale = null;

//        if ($this instanceof LangCollectionInterface) {
//            $defaultLocale = $this->getDefaultLocale();
//            $deniedFields = array_merge($deniedFields, array(
//                'langs', 'defaultSubsite', 'defaultLocale', 'defaultLang'
//            ));
//        }

        $deniedFields = array_merge($deniedFields, array(
            'class', 'className', 'entityClass', 'contentSearchTitle', 'objectId',
            'route', 'routeParams', 'textSearch', 'contentSearchName', 'contentSearchEntity',
            'contentSearch', 'relatedContentInstance', 'controllerNameSpace',
            'controllerInstance', 'folderPath', 'routingProvider'
        ));

        $reflectionObject = new \ReflectionObject($this);
        $reflectionMethods = $reflectionObject->getMethods(
            \ReflectionMethod::IS_PUBLIC
        );

        foreach ($reflectionMethods as $method) {
            if ($this->isGetMethod($method)) {
                $attributeName = lcfirst(substr(
                    $method->name, 0 === strpos($method->name, 'is') ? 2 : 3
                ));

                if (!in_array($attributeName, $deniedFields) && (
                    count($allowedFields) == 0 || in_array($attributeName, $allowedFields)
                )) {
                    $value = $method->invoke($this);
                    if ($value instanceof AbstractEntity) {
                        if (in_array($attributeName, $entityFields)) {
//                            if (
//                                $defaultLocale != null
//                                && ($value instanceof LangCollectionInterface)
//                            ) {
//                                $value->setDefaultLocale($defaultLocale);
//                            }
                            $result[$attributeName] = $value->toArray();
                        } else {
//                            if ($value instanceof LocaleInterface) {
//                                $result[$attributeName] = $value->getCode();
//                            } else {
                                $result[$attributeName] = $value->getId();
//                            }
                        }
                    } elseif (
                        $value instanceof PersistentCollection
                        || $value instanceof ArrayCollection
                    ) {
                        $result[$attributeName] = array();
                        foreach ($value as $item) {
                            if (in_array($attributeName, $entityFields)) {
//                                if (
//                                    $defaultLocale != null
//                                    && ($item instanceof LangCollectionInterface)
//                                ) {
//                                    $item->setDefaultLocale($defaultLocale);
//                                }
                                $result[$attributeName][] = $item->toArray();
                            } else {
                                $result[$attributeName][] = $item->getId();
                            }
                        }
                    } else {
                        $result[$attributeName] = $value;
                    }
                }
            }
        }

//        if ($defaultLocale != null) {
//            $lang = $this->getDefaultLang();
//
//            if (!empty($lang)) {
//                //$result['langs'] = array();
//                //$result['langs'][] = $lang->toArray();
//                $result['lang'] = $lang->toArray();
//            }
//        }

//        if ($this instanceof SelfContentTypeInterface) {
//            $result['permalink'] = self::$routingProvider->generate($this);
//        }

//        if ($this instanceof UserRelationInterface) {
//            $result['userData'] = [
//                'id'      => $this->getUser() !== null ? $this->getUser()->getId() : '',
//                'acronym' => $this->getUser() !== null ? $this->getUser()->acronym() : '',
//            ];
//        }

//        if ($this instanceof OriginSubSiteInterface) {
//            $originSubSite = $this->getOriginSubSite();
//
//            if ($originSubSite !== null) {
//                $originSubSite = [
//                    "id"      => $originSubSite->getId(),
//                    "acronym" => $originSubSite->getAcronym(),
//                    "name"    => $originSubSite->getName(),
//                ];
//            }
//
//            $result['originSubSite'] = $originSubSite;
//        }

        return $result;
    }

    /**
     * @param  array  $data (optional)
     * @return self
     */
    public function fromArray($data)
    {
        $reflectionObject = new \ReflectionObject($this);
        $reflectionMethods = $reflectionObject->getMethods(
            \ReflectionMethod::IS_PUBLIC
        );

        foreach ($reflectionMethods as $method) {
            if ($this->isSetMethod($method)) {
                $attributeName = lcfirst(substr(
                    $method->name, 0 === strpos($method->name, 'is') ? 2 : 3
                ));

                if(array_key_exists($attributeName, $data)) {
                    if (
                        is_array($data[$attributeName])
                        && !($this instanceof LayoutPageWidgetInterface)
                    ) {
                        $data[$attributeName] = new ArrayCollection($data[$attributeName]);
                    }
                    $method->invoke($this, $data[$attributeName]);
                }
            }
        }

        return $this;
    }

    /**
     * @param  \ReflectionMethod $method
     * @return boolean
     */
    public function isGetMethod(\ReflectionMethod $method)
    {
        $methodLength = strlen($method->name);

        return (
            ((0 === strpos($method->name, 'get') && 3 < $methodLength)
                || (0 === strpos($method->name, 'is') && 2 < $methodLength)
            ) && (0 === $method->getNumberOfRequiredParameters())
        );
    }

    /**
     * @param  \ReflectionMethod $method
     * @return boolean
     */
    public function isSetMethod(\ReflectionMethod $method)
    {
        $methodLength = strlen($method->name);

        return (
            (0 === strpos($method->name, 'set') && 3 < $methodLength)
            && (1 === $method->getNumberOfParameters())
        );
    }

    /**
     * @return string (JSON)
     */
    public function toJSON()
    {
        return Utils::toJSON($this->toArray());
    }

    /**
     * @param string $json (JSON)
     * @return self
     */
    public function fromJSON(string $json)
    {
        $data = Utils::fromJSON($json);
        if (!empty($data)) {
            $this->fromArray($data);
        }

        return $this;
    }
}
