# Modelado de una torre de contral
# con OVs (objetos volantes),
# que pueden colisionar.


import math


class Pos:
    """Pos: x, y, z"""
    X = 0
    Y = 1
    Z = 2
    ORG = None
    
    @staticmethod
    def org():
        """Devuelve el origen de coordenadas.
                :return: el objeto Pos(0, 0, 0)
        """
        if not Pos.ORG:
            Pos.ORG = Pos(0, 0, 0)
        ...
        
        return Pos.ORG
    ...
    
    def __init__(self, x, y, z):
        self._pos = [x, y, z]
    ...
    
    def __len__(self):
        return len(self._pos)
    ...
    
    def __getitem__(self, item):
        return self._pos[item]
    ...
    
    @property
    def x(self):
        return self._pos[0]
    ...
    
    @property
    def y(self):
        return self._pos[1]
    ...
    
    @property
    def z(self):
        return self._pos[2]
    ...
    
    def distancia_a(self, otro):
        """Calcula la distancia entre esta pos. y otra dada.
                :param otro: Una pos. dada.
                :return: la distancia, como un decimal.
        """
        delta__sq_x = (self.x - otro.x) ** 2
        delta__sq_y = (self.y - otro.y) ** 2
        delta__sq_z = (self.z - otro.z) ** 2
        return math.sqrt(delta__sq_x + delta__sq_y + delta__sq_z)
    ...
    
    def __sub__(self, otro):
        return self.distancia_a(otro)
    ...
    
    def __eq__(self, otro):
        return (otro
                and self.x == otro.x
                and self.y == otro.y
                and self.z == otro.z)
    ...
    
    def __ne__(self, otro):
        return not(self == otro)
    ...
    
    def __str__(self):
        return f"({self.x}, {self.y}, {self.z})"
    ...
...


class OV:
    """Cualquier objecto volante."""
    def __init__(self, x, y, z):
        self._pos = Pos(x, y, z)
    ...
    
    @property
    def pos(self):
        return self._pos
    ...
    
    def __str__(self):
        return f"{self.pos}"
    ...
...


class OVNI(OV):
    """Cualquier objeto volante no identificado."""
    def __init__(self, x, y, z):
        super().__init__(x, y, z)
    ...    

    def __str__(self):
        return "ovni/" + super().__str__()
    ...
...


class OVI(OV):
    """Cualquier objeto volante con empresa y num. de vuelo."""
    def __init__(self, com, num_vuelo, x, y, z):
        super().__init__(x, y, z)
        self._com = str(com).capitalize()
        self._num_vuelo = num_vuelo
    ...
    
    @property
    def com(self):
        """Devuelve el nombre de la empresa."""
        return self._com
    
    @property
    def num_vuelo(self):
        """Devuelve el num. de vuelo."""
        return self._num_vuelo
    ...

    def __str__(self):
        return f"{self.com} {str(self.num_vuelo)}/{super().__str__()}"
    ...
...


class TorreControl:
    """Desde la torre de control se controlan los vuelos."""
    def __init__(self):
        self._vuelos = []
    ...
    
    def __add__(self, otro: OV):
        self._vuelos += [otro]
        return self
    ...
    
    @property
    def vuelos(self):
        """Devuelve una lista con los vuelos actuales."""
        return list(self._vuelos)
    ...
    
    def avisos_colision(self, limite: float):
        toret = []
        
        for i in range(len(self.vuelos)):
            for j in range(i + 1, len(self._vuelos)):
                if (self._vuelos[i].pos - self._vuelos[j].pos) < limite:
                     toret += [(self._vuelos[i], self._vuelos[j])]
                ...
            ...
        ...
    
        return toret
    ... 
        
    def __str__(self):
        return str.join(", ", [str(v) for v in self._vuelos])
    ...
...


if __name__ == "__main__":
    t = TorreControl()
    ov1 = OVI("iberia", 1212, 10, 100, 15000)
    ov2 = OVI("qantas", 3456, 100, 150, 12000)
    ov3 = OVNI(110, 160, 13000)
    colisiones = t.avisos_colision(500)
    
    t += ov1
    t += ov2
    t += ov3
    
    print(f"torre: {t}")
    print(f"Avisos colisión:\n{str.join(", ", [str(v1) + " !! " + str(v2) for (v1, v2) in colisiones])}")
...
