<?php

namespace Core;

use DI\ContainerBuilder;
use Doctrine\Common\Annotations\AnnotationReader;

class BeanFactory
{

    //配置文件
    private static $env = [];
    //IOC容器
    private static $container;
    private static $handlers = [];

    //初始化函数
    public static function init()
    {
        self::$env = parse_ini_file(ROOT_PATH . "/.env");
        //初始容器Builder
        $builder = new ContainerBuilder();
        //启用注释 主要是用它的Inject注释
        $builder->useAttributes(true);
        //容器初始化
        self::$container = $builder->build();

        $handlers = glob(ROOT_PATH . "/core/annotationhandlers/*.php");
        foreach ($handlers as $handler) {
            self::$handlers = array_merge(self::$handlers, require_once($handler));
        }
        //扫描(重点)
        $scans = [
            //必须扫描的文件夹
            ROOT_PATH . "/core/init"                      => "Core\\",
            //用户配置的扫描路径
            self::_getEnv("scan_dir", ROOT_PATH . "/app") => self::_getEnv("scan_root_namespace", "APP\\")
        ];
        //$scanDir = self::_getEnv("scan_dir",ROOT_PATH."/app");
        //$scanRootNamespace = self::_getEnv("scan_root_namespace","APP\\");
        foreach ($scans as $scanDir => $scanRootNamespace) {
            self::ScanBeans($scanDir, $scanRootNamespace);
        }
        //self::ScanBeans();

    }

    private static function getAllBeanFiles($dir)
    {
        $ret   = [];
        $files = glob($dir . "/*");
        foreach ($files as $file) {
            if (is_dir($file)) {
                //递归合并,防止数组变成嵌套数组
                $ret = array_merge($ret, self::getAllBeanFiles($file));
            } elseif (pathinfo($file)["extension"] == "php") {
                $ret[] = $file;
            }
        }
        return $ret;
    }

    //获取env文件的配置内容
    private static function _getEnv(string $key, string $default = '')
    {
        if (isset(self::$env[$key]))
            return self::$env[$key];
        return $default;
    }

    public static function ScanBeans($scanDir, $scanRootNamespace)
    {
        //$files = glob($scanDir."/*.php");
        $files = self::getAllBeanFiles($scanDir);
        foreach ($files as $file) {
            require_once $file;
        }
        //注释类对象

        $reader = new AnnotationReader();
        //get_declared_classes返回由已定义类的名字所组成的数组
        foreach (get_declared_classes() as $class) {
            if (strstr($class, $scanRootNamespace)) {
                $refClass = new \ReflectionClass($class);
                //获取所有类的注释
                $classAnnos = $reader->getClassAnnotations($refClass);
                $instance   = self::$container->get($refClass->getName());
                foreach ($classAnnos as $classAnno) {
                    //根据注释的类型获取对应处理方法
                    $hander = self::$handlers[get_class($classAnno)];
                    //$hander($instance, self::$container);

                    self::handlerPropAnno($instance,$refClass,$reader);
                    //处理方法注解
                    self::handlerMethodAnno($instance,$refClass,$reader);

                    //处理类注解
                    $hander($instance,self::$container,$classAnno);
                }
                //self::handlerMethodAnno($instance, $refClass, $reader);
            }
        }
    }


    public static function getBean($name)
    {
        try {
            return self::$container->get($name);
        } catch (\Exception $exception) {
            return false;//没有找到直接返回false
        }

    }

    public static function setBean($name, $value)
    {
        return self::$container->set($name, $value);
    }


    private static function handlerPropAnno(&$instance, \ReflectionClass $refClass, AnnotationReader $reader)
    {
        //读取反射对象的属性
        $props = $refClass->getProperties();
        foreach ($props as $prop) {
            //$prop必须是反射对象属性
            $propAnnos = $reader->getPropertyAnnotations($prop);
            foreach ($propAnnos as $propAnno) {
                //返回对象实例 obj 所属类的名字。如果 obj 不是一个对象则返回 FALSE
                $handler = self::$handlers[get_class($propAnno)];
                $handler($prop, $instance, $propAnno);
            }
        }
    }


    /**
     * 处理方法注解
     * @param                                               $instance
     * @param \ReflectionClass $refClass
     * @param \Doctrine\Common\Annotations\AnnotationReader $reader
     */
    private static function handlerMethodAnno(&$instance, \ReflectionClass $refClass, AnnotationReader $reader)
    {
        //读取反射对象的属性
        $methods = $refClass->getMethods();//取出所有的方法
        foreach ($methods as $method) {
            //$prop必须是反射对象属性
            $methodAnnos = $reader->getMethodAnnotations($method);
            foreach ($methodAnnos as $methodAnno) {
                //返回对象实例 obj 所属类的名字。如果 obj 不是一个对象则返回 FALSE
                $handler = self::$handlers[get_class($methodAnno)];
                $handler($method, $instance, $methodAnno);
            }
        }
    }
}