# Path: sc2/protocol.py
# class Protocol:
#     def __init__(self, ws):
#         assert ws
#         self._ws = ws
#         self._status = None
# 
#     async def __request(self, request):
#         logger.debug(f"Sending request: {request !r}")
#         try:
#             await self._ws.send_bytes(request.SerializeToString())
#         except TypeError:
#             raise ConnectionAlreadyClosed("Cannot send: Connection already closed.")
#         logger.debug(f"Request sent")
# 
#         response = sc_pb.Response()
#         try:
#             response_bytes = await self._ws.receive_bytes()
#         except TypeError:
#             raise ConnectionAlreadyClosed("Cannot receive: Connection already closed.")
#         except asyncio.CancelledError:
#             # If request is sent, the response must be received before reraising cancel
#             try:
#                 await self._ws.receive_bytes()
#             except asyncio.CancelledError:
#                 log.critical("Requests must not be cancelled multiple times")
#                 sys.exit(2)
#             raise
# 
#         response.ParseFromString(response_bytes)
#         logger.debug(f"Response received")
#         return response
# 
#     async def _execute(self, **kwargs):
#         assert len(kwargs) == 1, "Only one request allowed"
# 
#         request = sc_pb.Request(**kwargs)
# 
#         response = await self.__request(request)
# 
#         new_status = Status(response.status)
#         if new_status != self._status:
#             logger.info(f"Client status changed to {new_status} (was {self._status})")
#         self._status = new_status
# 
#         if response.error:
#             logger.debug(f"Response contained an error: {response.error}")
#             raise ProtocolError(f"{response.error}")
# 
#         return response
# 
#     async def ping(self):
#         result = await self._execute(ping=sc_pb.RequestPing())
#         return result
# 
#     async def quit(self):
#         try:
#             await self._execute(quit=sc_pb.RequestQuit())
#         except ConnectionAlreadyClosed:
#             pass
# 
# Path: sc2/player.py
# class Computer(AbstractPlayer):
#     def __init__(self, race, difficulty=Difficulty.Easy):
#         super().__init__(PlayerType.Computer, race, difficulty=difficulty)
# 
#     def __str__(self):
#         return f"Computer({self.race}, {self.difficulty})"


from s2clientprotocol import sc2api_pb2 as sc_pb
from .protocol import Protocol
from .player import Computer
import logging

logger = logging.getLogger(__name__)

class Controller(Protocol):
    def __init__(self, ws, process):
        super().__init__(ws)
        self.__process = process

    @property
    def running(self):
        return self.__process._process is not None

    async def create_game(self, game_map, players, realtime, random_seed=None):
        assert isinstance(realtime, bool)
        req = sc_pb.RequestCreateGame(
            local_map=sc_pb.LocalMap(
                map_path=str(game_map.relative_path)
            ),
            realtime=realtime
        )
        if random_seed is not None:
            req.random_seed = random_seed

        for player in players:

# Path: sc2/protocol.py
# class Protocol:
#     def __init__(self, ws):
#         assert ws
#         self._ws = ws
#         self._status = None
# 
#     async def __request(self, request):
#         logger.debug(f"Sending request: {request !r}")
#         try:
#             await self._ws.send_bytes(request.SerializeToString())
#         except TypeError:
#             raise ConnectionAlreadyClosed("Cannot send: Connection already closed.")
#         logger.debug(f"Request sent")
# 
#         response = sc_pb.Response()
#         try:
#             response_bytes = await self._ws.receive_bytes()
#         except TypeError:
#             raise ConnectionAlreadyClosed("Cannot receive: Connection already closed.")
#         except asyncio.CancelledError:
#             # If request is sent, the response must be received before reraising cancel
#             try:
#                 await self._ws.receive_bytes()
#             except asyncio.CancelledError:
#                 log.critical("Requests must not be cancelled multiple times")
#                 sys.exit(2)
#             raise
# 
#         response.ParseFromString(response_bytes)
#         logger.debug(f"Response received")
#         return response
# 
#     async def _execute(self, **kwargs):
#         assert len(kwargs) == 1, "Only one request allowed"
# 
#         request = sc_pb.Request(**kwargs)
# 
#         response = await self.__request(request)
# 
#         new_status = Status(response.status)
#         if new_status != self._status:
#             logger.info(f"Client status changed to {new_status} (was {self._status})")
#         self._status = new_status
# 
#         if response.error:
#             logger.debug(f"Response contained an error: {response.error}")
#             raise ProtocolError(f"{response.error}")
# 
#         return response
# 
#     async def ping(self):
#         result = await self._execute(ping=sc_pb.RequestPing())
#         return result
# 
#     async def quit(self):
#         try:
#             await self._execute(quit=sc_pb.RequestQuit())
#         except ConnectionAlreadyClosed:
#             pass
# 
# Path: sc2/player.py
# class Computer(AbstractPlayer):
#     def __init__(self, race, difficulty=Difficulty.Easy):
#         super().__init__(PlayerType.Computer, race, difficulty=difficulty)
# 
#     def __str__(self):
#         return f"Computer({self.race}, {self.difficulty})"


# Path: sc2/controller.py
from s2clientprotocol import sc2api_pb2 as sc_pb
from .protocol import Protocol
from .player import Computer
import logging


logger = logging.getLogger(__name__)

class Controller(Protocol):
    def __init__(self, ws, process):
        super().__init__(ws)
        self.__process = process

    @property
    def running(self):
        return self.__process._process is not None

    async def create_game(self, game_map, players, realtime, random_seed=None):
        assert isinstance(realtime, bool)
        req = sc_pb.RequestCreateGame(
            local_map=sc_pb.LocalMap(
                map_path=str(game_map.relative_path)
            ),
            realtime=realtime
        )
        if random_seed is not None:
            req.random_seed = random_seed

        for player in players:

            p = req.player_setup.add()