/*
 * ********************************************************************************************************************
 *
 *                     :*$@@%$*:                         ;:                ;;    ;;
 *                   :@@%!  :!@@%:                       %!             ;%%@@%$ =@@@@@@@%;     @%@@@%%%%@@@@@
 *                  :@%;       :$=                       %%$$$%$$         ;$$  ;$@=   !@$
 *                  =@!                                  %!              @ $=;%   !@@@%:      !$$$$$$$$$$$$$$=
 *                  =@*                                  %!              @ $= % %@=   =%@!      %=
 *             *$%%! @@=        ;=$%%%$*:                %!              @ $= % =%%%%%%@$      *%:         =%
 *           %@@!:    !@@@%=$@@@@%!  :*@@$:              %!              @ $= % $*     ;@      @*          :%*
 *         ;@@!          ;!!!;:         ;@%:      =======@%========*     @ $$ % $%*****$@     :@$=*********=@$
 *         $@*   ;@@@%=!:                *@*
 *         =@$    ;;;!=%@@@@=!           =@!
 *          %@$:      =@%: :*@@@*       %@=                    Copyright (c) 2016-2019.  北京上格云技术有限公司
 *           ;%@@$=$@@%*       *@@@$=%@@%;
 *              ::;::             ::;::                                              All rights reserved.
 *
 * ********************************************************************************************************************
 */

package com.persagy.server

import com.alibaba.fastjson.annotation.JSONField
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.PropertyName
import com.fasterxml.jackson.databind.introspect.Annotated
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector
import com.fasterxml.jackson.databind.module.SimpleModule
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import springfox.documentation.builders.ApiInfoBuilder
import springfox.documentation.builders.ParameterBuilder
import springfox.documentation.builders.PathSelectors
import springfox.documentation.builders.RequestHandlerSelectors
import springfox.documentation.schema.ModelRef
import springfox.documentation.schema.configuration.ObjectMapperConfigured
import springfox.documentation.service.ApiInfo
import springfox.documentation.service.Contact
import springfox.documentation.service.Parameter
import springfox.documentation.spi.DocumentationType
import springfox.documentation.spring.web.plugins.Docket
import springfox.documentation.swagger2.annotations.EnableSwagger2
import javax.annotation.PostConstruct

/**
 * RESTful API文档生成器Swagger2配置
 *
 * @author  PLX
 */
@Configuration
@EnableSwagger2
open class Swagger2Config {
    companion object {
        // 日志
        private val logger = LoggerFactory.getLogger(Swagger2Config::class.java)
    } // Companion object

    @Autowired
    lateinit var applicationContext: ApplicationContext

    private val version = "2.0"

    /**
     * 设置Json解析器（默认使用的是jackson）,这里改为FastJson
     */
    @PostConstruct
    fun setObjectMapper() {
        val objectMapper = ObjectMapper()
        val module = SimpleModule()
        objectMapper.registerModule(module)
        // objectMapper.setAnnotationIntrospector(SFastjsonAnnotationIntrospector())

        objectMapper.setAnnotationIntrospector(object : JacksonAnnotationIntrospector() {

            override fun isAnnotationBundle(ann: Annotation): Boolean {
                println("isAnnotationBundle")

                return if (ann.annotationClass == JSONField::class.java) {
                    true
                } else super.isAnnotationBundle(ann)
            }

            override fun findNameForSerialization(a: Annotated): PropertyName? {
                println("findNameForSerialization")
                val nameForSerialization = super.findNameForSerialization(a)
                if (nameForSerialization == null || nameForSerialization === PropertyName.USE_DEFAULT) {
                    val jsonField = _findAnnotation(a, JSONField::class.java)
                    if (jsonField != null) {
                        return PropertyName.construct(jsonField.name)
                    }
                }
                return nameForSerialization
            }

            override fun findNameForDeserialization(a: Annotated): PropertyName? {
                println("findNameForDeserialization")
                val nameForDeserialization = super.findNameForDeserialization(a)
                if (nameForDeserialization == null || nameForDeserialization === PropertyName.USE_DEFAULT) {
                    val jsonField = _findAnnotation(a, JSONField::class.java)
                    if (jsonField != null) {
                        return PropertyName.construct(jsonField.name)
                    }
                }
                return nameForDeserialization
            }
        })
        //////////////////////////////////

        val objectMapperConfigured = ObjectMapperConfigured(applicationContext, objectMapper)
        applicationContext.publishEvent(objectMapperConfigured)
        return
    } // Function setObjectMapper()




    /**
     * 创建RestApi文档生成器
     *
     * @return  返回文档生成器对象
     */
    @Bean
    open fun createRestApi(): Docket {
        logger.debug("createRestApi")
        val builder = ParameterBuilder()
        val builderComming = ParameterBuilder()
        val builderPhone = ParameterBuilder()
        val pars = ArrayList<Parameter>()
        builder.name("ProjectId").description("项目ID").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        builderComming.name("Coming").description("来源").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        builderPhone.name("Account").description("账号信息").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        pars.add(builder.build())
        pars.add(builderComming.build())
        pars.add(builderPhone.build())
        return Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.persagy.server"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(pars)
    } // Function createRestApi()

    /**
     * 对象Api
     *
     * @return  返回文档生成器对象
     */
    @Bean
    open fun objectApi(): Docket {
        val builder = ParameterBuilder()
        val builderComming = ParameterBuilder()
        val builderPhone = ParameterBuilder()
        val pars = ArrayList<Parameter>()
        builder.name("ProjectId").description("项目ID").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        builderComming.name("Coming").description("来源").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        builderPhone.name("Account").description("账号信息").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        pars.add(builder.build())
        pars.add(builderComming.build())
        pars.add(builderPhone.build())
        return Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfos("对象-API", "对象操作", version))
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.persagy.server"))
                .paths(PathSelectors.ant("/object/**"))
                .build()
                .groupName("1. 对象-API")
                .pathMapping("/")
                .globalOperationParameters(pars)
    } // Function objectApi()

    /**
     * 关系Api
     *
     * @return  返回文档生成器对象
     */
    @Bean
    open fun relationApi(): Docket {
        val builder = ParameterBuilder()
        val builderComming = ParameterBuilder()
        val builderPhone = ParameterBuilder()
        val pars = ArrayList<Parameter>()
        builder.name("ProjectId").description("项目ID").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        builderComming.name("Coming").description("来源").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        builderPhone.name("Account").description("账号信息").modelRef(ModelRef("string")).parameterType("header").required(false).build()
        pars.add(builder.build())
        pars.add(builderComming.build())
        pars.add(builderPhone.build())
        return Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfos("关系-API", "关系操作", version))
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.persagy.server"))
                .paths(PathSelectors.ant("/rel/**"))
                .build()
                .groupName("3. 关系-API")
                .pathMapping("/")
                .globalOperationParameters(pars)
    } // Function relationApi()


    /**
     * 返回API信息基本
     *
     * @return  返回Api基本信息
     */
    private fun apiInfo(): ApiInfo {
        return ApiInfoBuilder()
                .title("数据中心API")
                .description("接口中Comming来源信息：扫楼：App-scanBuildingApp、慧运营运维平台：adm、Revit算法：RevitAlgorithm")
                .termsOfServiceUrl("http://www.persagy.cn/")
                .contact(Contact("张维新", "", "zhangweixin@sagacloud.cn"))
                .version("2.0")
                .build()
    } // Function apiInfo()

    /**
     * 运回API信息基本
     *
     * @param   title           Api 标题
     * @param   description     API 描述
     * @param   version         API 版本号
     * @return  返回Api基本信息
     */
    private fun apiInfos(title: String, description: String, version: String): ApiInfo {
        return ApiInfoBuilder()
                .title(title)
                .description(description)
                .termsOfServiceUrl("http://www.persagy.cn/")
                .contact(Contact("张维新", "", "zhangweixin@sagacloud.cn"))
                .version(version)
                .build()
    } // Function apiInfo()
} // Class Swagger2Config