'''
这是容纳自由运动的代理人的网格，允许代理人旋转运动。

'''
import numpy as np
from takagiabm.agents.gridagents.freegrid.freegridcell import Cell
from itertools import chain

try:

    from numba import jit
except:
    print('检测到未安装numba.如果装有numba,可以让仿真速度更快。')
    from takagiabm.toolbox.numbaUtils import fakeJit

    jit = fakeJit


# @jit
# def xLoop(width, pos):
#     if (pos[0] < 0):
#         pos[0] = width - 1
#     elif (pos[0] >= width):
#         pos[0] = 0
#
#
# @jit
# def yLoop(height, pos):
#     if (pos[1] < 0):
#         pos[1] = height - 1
#     elif (pos[1] >= height):
#         pos[1] = 0
#
#
# @jit
# def xBlock(width, pos):
#     if (pos[0] < 0):
#         pos[0] = 0
#     elif (pos[0] >= width):
#         pos[0] = width - 1
#
#
# @jit
# def yBlock(height, pos):
#     if (pos[1] < 0):
#         pos[1] = 0
#     elif (pos[1] >= height):
#         pos[1] = height - 1
#
#
# @jit
# def xyWrap(height, width, pos):
#     if (pos[0] < 0):
#         pos[0] = width - 1
#     else:
#         pos[0] = 0
#     if (pos[1] < 0):
#         pos[1] = height - 1
#     else:
#         pos[1] = 0
#
#
# @jit
# def inBody(width, height, pos):
#     return (0 < pos[0] < width - 1) & (0 < pos[1] < height - 1)
#
#
# neighborDic = {'': [[1, 0], [1, 1], [0, 1], [-1, 1], \
#                              [-1, 0], [-1, -1], [0, -1], [1, -1]], \
#                '+': [[1, 0], [0, 1], [-1, 0], [0, -1]], \
#                'x': [[1, 1], [-1, 1], [-1, -1], [1, -1]]
#                }





class BaseGrid():
    neighborList = [None] * 8

    def __init__(self, model=None, width=0, height=0):  # 分别是表格的宽度和高度.
        self.model = model
        self.width = width  # 网格的宽度(列数)
        self.height = height  # 网格的高度(行数)
        self.colorList = [[[1,1,1] for i in range(width)] for j in range(self.height)]
        self.cellList = [[set() for i in range(width)] for j in range(height)]

        # 使用tuple来进行存储或许可以提升寻址速度？maybe.如果出现错误就改过来吧。


    def setWrapAction(self, policyName: str):
        '''
        设置回绕方式。方法在继承它的子类中被改写。
        '''
        pass

    def getNeighbors(self, pos: np.ndarray, shape='') -> list:
        '''获取邻居列表。'''
        pass

    def getNeighborProperties(self, pos, propertyName: str, shape='') -> list:
        nbd = self.neighborDic[shape]
        l = [None] * len(nbd)
        if (propertyName in self.mat.keys()):
            if inBody(self.width, self.height, pos):  # 若位于中腹
                a = self.mat['alive'][(pos[0] - 1):(pos[0] + 2), (pos[1] - 1):(pos[1] + 2)]  # 直接从矩阵上获取值。
                l = a.tolist()
                l[1].pop(1)
                p = sum(l, [])
                return p

            else:
                for i in range(len(nbd)):
                    arrayVar = pos + nbd[i]
                    arrayVar = self.getCellPos(arrayVar)
                    l[i] = self.cells[arrayVar[1]][arrayVar[0]].properties[propertyName]
                return l

    def getCellPos(self, pos: np.ndarray):  # 这个函数的目的是检测pos是否在网格内部，如果不是，就依据边界策略
        # 将网格的位置调整一下。允许的入口参数类型为numpy的浮点数。
        # 单元的位置是一个numpy.ndarray数组.因此直接在内存中修改即可.
        s1 = np.floor(pos)  # .astype(np.int)
        vari = pos - s1
        pos = s1
        self.xWrapAction(self.width, pos)  # 这俩是这个Grid类的属性,不是其方法.因此不用传入self.
        self.yWrapAction(self.height, pos)
        vari += pos  # .astype(np.float)
        return vari  # pos.astype(np.int)


    def getAllCellsIter(self):  # iterator:
        iterChain = chain.from_iterable(self.cells)  # (*self.cells),返回一个迭代器.

        return iterChain

    def getAllCells(self) -> list:
        return list(self.getAllCellsIter())

    def getCellColor(self, pos: list) -> str:
        return self.cells[pos[1]][pos[0]].getColor()


    def setCellColor(self, pos: list, color: str) -> None:

        cell = self.cells[pos[1]][pos[0]]  # 先行后列,逐个定位.
        cell.setColor(color)

    def placeAgent(self, agent) -> None:
        pos = agent.getPosOnGrid()
        agent.grid = self
        self.cellList[pos[1]][pos[0]].add(agent)

    def moveAgent(self, agent, deltaPos):
        lastPos = agent.pos
        pos = deltaPos + lastPos
        self.moveAgentTo(agent, pos)

    def moveAgentTo(self, agent, targetPos0):
        targetPos = self.getCellPos(targetPos0)
        lastPos =agent.pos

        if agent in self.cellList[lastPos[1]][lastPos[0]]:
            self.cellList[lastPos[1]][lastPos[0]].remove(agent)  # 索引是先行后列，但是位置是先列（x）后行(y)
        else:
            raise Exception('未找到此Agent,可能已经"死亡"或被从网格中移除。')
        agent.pos = targetPos
        self.cellList[targetPos[1]][targetPos[0]].add(agent)

    def isCellEmpty(self, pos):
        return self.getAgentNumInCell(pos) == 0

    def getAgentNumInCell(self, pos):  # 输入位置,返回单元格内对象的数目.
        return len(self.cellList[pos[0]][pos[1]])

    def getAgentsByPos(self, pos):
        return list(self.cellList[pos[1]][pos[0]])

    def removeAgent(self, agent):
        pos = self.getCellPos(agent.pos)

        self.cellList[pos[1]][pos[0]].remove(agent)


if __name__ == '__main__':
    g = FreeGrid(width=70, height=70)
    g.setWrapAction('torus')
    s = g.getCellPos(np.array([69.52483393, 19.15510416]))
    print(s)
    # s=g.getCellByPos(np.array((1, 2)))
    # t0=time.time()
    # for j in range(10000):
    #     l=[]
    #     for i in range(8):
    #         l+=[g.cells[56][56]]
    #
    # t1=time.time()
    # for i in range(10000):
    #     s=g.mat['alive'][56:59,56:59]
    #     l=s.tolist()
    #     # print(s)
    #     l[1].pop(1)
    #     p=sum(l, [])
    #     # for j in range(8):
    #     #     l+=[g.mat['a'][56][56]]
    # print(p)
    # t2=time.time()

    # print(t1-t0,t2-t1)
    # print('posfffff',s.pos)
    # print(s.getNeighbors())
    #
    # print(g.getCellPos(np.array((1,2))))
