/*
 * *********************************************************************************************************************
 *
 *          !!
 *        .F88X
 *        X8888Y
 *      .}888888N;
 *        i888888N;        .:!              .I$WI:
 *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
 *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
 *            +888888N;  .8888888Y                                  "&&8Y.}8,
 *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
 *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
 *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
 *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
 *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
 *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
 *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
 *      .:R888888I
 *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
 *        ~8888'
 *        .!88~                                                                     All rights reserved.
 *
 * *********************************************************************************************************************
 */

package com.persagy.server.datacenter.services.objects

import com.persagy.database.SFilter
import com.persagy.database.extensions.keyValue
import com.persagy.mybatis.SMybatisDao
import com.persagy.server.Opt
import com.persagy.server.datacenter.models.entities.dictnew.DefFuncIdProject
import com.persagy.server.datacenter.models.entities.graphtype.RelationTypeProject
import com.persagy.server.datacenter.wanda.obj.Equipment
import com.persagy.server.datacenter.wanda.rel.REq2Sy
import com.persagy.server.services.base.Service
import com.persagy.server.services.log.DataCenterLogsService
import com.persagy.server.utils.IdUtils
import com.persagy.server.utils.ShaftNameUtil
import com.persagy.service.SBaseService
import com.persagy.service.SObjectService
import com.persagy.service.models.enums.SResponseType
import com.persagy.service.models.requests.SUpdateRequest
import com.persagy.service.models.responses.SBaseResponse
import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.xssf.usermodel.XSSFCell
import org.apache.poi.xssf.usermodel.XSSFRow
import org.apache.poi.xssf.usermodel.XSSFSheet
import org.apache.poi.xssf.usermodel.XSSFWorkbook
import org.slf4j.LoggerFactory
import org.springframework.web.multipart.MultipartFile
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.util.*
import javax.servlet.http.HttpServletResponse


/**
 * 设备信息服务
 *
 * @author 张维新
 */
object EquipmentService : Service<Equipment>(SMybatisDao(Equipment::class.java)) {

    private val logger = LoggerFactory.getLogger(EquipmentService::class.java)

    /** 关系总览服务 */
    val relationTypeProjectservice = SBaseService(SMybatisDao(RelationTypeProject::class.java))

    /** 设备和系统关系 */
    private val rEq2SyService = SObjectService(SMybatisDao(REq2Sy::class.java))

    /** 设备与信息点关系 */
    private val defFuncIdProjectService = SObjectService(SMybatisDao(DefFuncIdProject::class.java))

    /**
     * 创建前赋值操作
     *
     * @param   equip   设备对象
     */
    override fun onCreateBefore(equip: Equipment): Boolean {
        /** 查询准备类型 */
        if (!equip.id.isNullOrEmpty()) {
            val isStartsWith = equip.id.toString().startsWith("Eq")
            if (!isStartsWith) {
                /** 资产id */
                equip.id = IdUtils.equipmentIdCreate(Opt.projectId!!)
            }
        } else {
            /** 资产id */
            equip.id = IdUtils.equipmentIdCreate(Opt.projectId!!)
        }
        /** 项目id */
        equip.projectId = Opt.projectId
        if (equip.classCode.isNullOrEmpty()) {
            return false
        }
        if(equip.classCode!!.length<6){
            val entity = defClassService.select(
                    SFilter.eq("projectId", equip.projectId!!),
                    SFilter.endWith("code", equip.classCode!!)
            ).entity()
            if (entity!=null){
                equip.classCode = entity.code
            } else {
                return false
            }
        }
        /** 设备名字 */
        if (equip.name.isNullOrEmpty()) {
            val entity = defClassService.select(
                SFilter.eq("projectId", equip.projectId!!),
                SFilter.eq("code", equip.classCode!!)
            ).entity()
            if (entity!=null) {
                equip.name = ShaftNameUtil.shaftName(entity.name+"-")
            }else {
                equip.name = ShaftNameUtil.shaftName("设备-")
            }
        }
        equip.objectType = "equipment"
        equip.codeType = 1
        return true
    }

    /**
     * 修改设备信息之前的操作
     */
    override fun onUpdateBefore(entity: Equipment): Boolean {
            try {
                /** 日志 */
                DataCenterLogsService.addLogs(Opt.projectId!!,"update-before",entity.objectType!!,
                    entity.id!!,entity,Opt.account,Opt.coming)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        return true
    }




    /**
     * 删除之前操作
     */
    override fun onDeleteBefore(entity: Equipment): Boolean {
            try {
                val equipment = this.select(SFilter.eq("id", entity.id!!)).entity()
                /** 日志 */
                DataCenterLogsService.addLogs(Opt.projectId!!,"delete",entity.objectType!!,
                    entity.id!!,equipment!!,Opt.account,Opt.coming)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        return super.onDeleteBefore(entity)
    }


    override fun onCreateSuccess(entityList: ArrayList<Equipment>) {
        entityList.forEach {
            try {
                /** 发送消息 */
                rabbitMqService.sendObjects(Opt.projectId!!, Opt.CREATE,it.keyValue("id").toString())
            } catch (e: Exception) {
                e.printStackTrace()
            }
            try {
                val entity = EquipmentService.select(SFilter.eq("id", it.keyValue("id")!!)).entity()
                if (entity != null) {
                    try {
                        /** 日志 */
                        DataCenterLogsService.addLogs(Opt.projectId!!,"create",entity.objectType!!,
                            entity.id!!,entity,Opt.account,Opt.coming)
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    } //

    /**
     * 更新成功能回调函数
     *
     * @param   entityList      更新成功对象列表
     */
    override fun onUpdateSuccess(entityList: ArrayList<Equipment>) {
        try {
            for (entity in entityList) {
                try {
                    val equip = EquipmentService.select(SFilter.eq("id", entity.keyValue("id")!!)).entity()
                    if (equip != null) {
                        /** 日志 */
                        DataCenterLogsService.addLogs(Opt.projectId!!,"update-after",entity.objectType!!,
                            entity.id!!,entity,Opt.account,Opt.coming)
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
                try {
                    /** 发送消息 */
                    rabbitMqService.sendObjects(Opt.projectId!!, Opt.UPDATE,entity.id!!)
                } catch (e: Exception) {
                    e.toString()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * @Description:删除成功之后
     */
    override fun onDeleteSuccess(entityList: ArrayList<Equipment>) {
        super.onDeleteSuccess(entityList)
        try {
            for (entity in entityList) {
                try {
                    rabbitMqService.sendObjects(Opt.projectId!!, Opt.DELETE,entity.id!!)
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun exportExcel(response: HttpServletResponse, projectId: String, classCode: String) {
        response.contentType = "application/octet-stream"
        response.setHeader("Content-disposition", "attachment;filename=equip-$classCode.xlsx")
        response.flushBuffer()
        val defFuncIds = defFuncIdProjectService.select(SFilter.eq("projectId",projectId), SFilter.eq("classCode",classCode)).exec()

        val equipments = select(SFilter.eq("projectId",projectId), SFilter.eq("classCode",classCode)).exec()
        val list = ArrayList<List<Any>>()
        val firstList = ArrayList<String>()
        val codeList = ArrayList<String>()
        codeList.add("id")
        codeList.add("bimTypeId")
        codeList.add("systemCategory")
        codeList.add("codeName")
        codeList.add("localId")
        firstList.add("设备ID-id")
        firstList.add("BIM构件编码-bimTypeId")
        firstList.add("系统分类-systemCategory")
        firstList.add("设备类型名称-codeName")
        firstList.add("本地编码-localId")
        for (defFuncId in defFuncIds) {
            codeList.add(defFuncId.code!!)
            firstList.add("${defFuncId.name}-${defFuncId.code}")
        }


        list.add(firstList)
        for (equipment in equipments) {
            val itemList = ArrayList<Any>()
            val infos = equipment.infos
            for (s in codeList) {
                if(s == "id"){
                    itemList.add(equipment.id?:"")
                } else if(s == "bimTypeId"){
                    itemList.add(equipment.bimTypeId?:"")
                }else if(s == "systemCategory"){
                    itemList.add(equipment.systemCategory?:"")
                }else if(s == "codeName"){
                    itemList.add(equipment.codeName?:"")
                }else if(s == "localId"){
                    itemList.add(equipment.localId?:"")
                }else{
                    if(infos != null && infos[s] != null){
                        itemList.add(infos[s]!!)
                    }else{
                        itemList.add("")
                    }
                }

                
            }
            list.add(itemList)

        }
        writeExcel(list,response.outputStream)


    } // Fun exportExcel


    /**
     * 把内容写入Excel
     * @param list 传入要写的内容，此处以一个List内容为例，先把要写的内容放到一个list中
     * @param outputStream 把输出流怼到要写入的Excel上，准备往里面写数据
     */
    fun writeExcel(list: List<List<*>>, outputStream: OutputStream){
        //创建工作簿
        var xssfWorkbook = XSSFWorkbook()

        //创建工作表
        val xssfSheet: XSSFSheet
        xssfSheet = xssfWorkbook.createSheet("设备绑点")

        //创建行
        var xssfRow: XSSFRow

        //创建列，即单元格Cell
        var xssfCell: XSSFCell

        //把List里面的数据写到excel中
        for (i in list.indices) {
            //从第一行开始写入
            xssfRow = xssfSheet.createRow(i)
            //创建每个单元格Cell，即列的数据
            val sub_list = list[i]
            for (j in sub_list.indices) {
                xssfCell = xssfRow.createCell(j) //创建单元格
                xssfCell.setCellValue(sub_list[j] as String?) //设置单元格内容
            }
        }

        //用输出流写到excel
        try {
            xssfWorkbook.write(outputStream)
            outputStream.flush()
            outputStream.close()
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }

    fun importExcel(file: MultipartFile,projectId: String, classCode: String) : SBaseResponse {
        try {
            val equipments = select(SFilter.eq("projectId",projectId), SFilter.eq("classCode",classCode)).exec()
            val equipMap = HashMap<String,Equipment>()
            for (equipment in equipments) {
                equipMap[equipment.id!!] = equipment
            }
            val content = ArrayList<Equipment>()
            val list = readExcel(file.inputStream,"")
            for (map in list) {
                val infos = HashMap<String,Any?>()
                var equipId : String? = null
                for (key in map.keys) {
                    val code = key.substring(key.lastIndexOf("-"),key.length)
                    if(code == "id"){
                        equipId = map[key]!!
                    } else if(code == "bimTypeId"){

                    }else if(code == "systemCategory"){

                    }else if(code == "codeName"){

                    }else if(code == "localId"){

                    }else{
                        if(!map[key].isNullOrEmpty()){
                            infos[key] = map[key]
                        }
                    }
                }

                val equipment = equipMap[equipId]
                if(equipment != null){
                    content.add(equipment)
                }
            }
            val request = SUpdateRequest<Equipment>()
            request.content = content
            updateList(request)


        }catch (e : Exception){
            return SBaseResponse(SResponseType.failure,"error:" + e.message)
        }
        return SBaseResponse(SResponseType.success, "")
    }

    /**
     * 读取Excel文件的内容
     * @param inputStream excel文件，以InputStream的形式传入
     * @param sheetName sheet名字
     * @return 以List返回excel中内容
     */
    fun readExcel(inputStream: InputStream?, sheetName: String): List<Map<String, String>> {

        //定义工作簿
        var xssfWorkbook: XSSFWorkbook? = null
        try {
            xssfWorkbook = XSSFWorkbook(inputStream)
        } catch (e: Exception) {
            println("Excel data file cannot be found!")
        }

        //定义工作表
        val xssfSheet: XSSFSheet
        xssfSheet = if (sheetName == "") {
            // 默认取第一个子表
            xssfWorkbook!!.getSheetAt(0)
        } else {
            xssfWorkbook!!.getSheet(sheetName)
        }
        val list = ArrayList<LinkedHashMap<String, String>>()

        //定义行
        //默认第一行为标题行，index = 0
        val titleRow = xssfSheet.getRow(0)

        //循环取每行的数据
        for (rowIndex in 1 until xssfSheet.physicalNumberOfRows) {
            val xssfRow = xssfSheet.getRow(rowIndex) ?: continue
            val map = LinkedHashMap<String, String>()
            //循环取每个单元格(cell)的数据
            for (cellIndex in 0 until xssfRow.physicalNumberOfCells) {
                val titleCell = titleRow.getCell(cellIndex)
                val xssfCell = xssfRow.getCell(cellIndex)
                map[getString(titleCell)] = getString(xssfCell)
            }
            list.add(map)
        }
        return list
    }

    /**
     * 把单元格的内容转为字符串
     * @param xssfCell 单元格
     * @return 字符串
     */
    fun getString(xssfCell: XSSFCell?): String {
        if (xssfCell == null) {
            return ""
        }
        return if (xssfCell.cellType == CellType.NUMERIC) {
            xssfCell.numericCellValue.toString()
        } else if (xssfCell.cellType == CellType.BOOLEAN) {
            xssfCell.booleanCellValue.toString()
        } else {
            xssfCell.stringCellValue
        }
    }
}