from re import split

from .pacman import *

class Level:
    def __init__(self, randomized=False):
        self.lvlWidth = 0
        self.lvlHeight = 0
        self.edgeLightColor = (255, 255, 0, 255)
        self.edgeShadowColor = (255, 150, 0, 255)
        self.fillColor = (0, 255, 255, 255)
        self.pelletColor = (255, 255, 255, 255)

        self.map = {}

        self.pellets = 0
        self.powerPelletBlinkTimer = 0

        self.gui = False
        self.randomized = randomized

        # TODO: Refactor entire level setup because this is definitely not OOP.
        self.preload_width = {}
        self.preload_height = {}
        self.preload_edge_light = {}
        self.preload_edge_shadow = {}
        self.preload_fill = {}
        self.preload_pellet_color = {}
        self.preload_map = {}
        self.preload_pellets = {}
        self.preload_fruit_type = {}
        self.preload_player_home = {}
        self.preload_ghosts_home = {}

    def SetMapTile(self, row_col, newValue):
        (row, col) = row_col
        self.map[(row * self.lvlWidth) + col] = newValue

    def GetMapTile(self, row_col):
        (row, col) = row_col
        if 0 <= row < self.lvlHeight and 0 <= col < self.lvlWidth:
            return self.map[(row * self.lvlWidth) + col]
        else:
            return 0

    @staticmethod
    def IsWall(row_col, thisLevel):
        (row, col) = row_col
        if row > thisLevel.lvlHeight - 1 or row < 0:
            return True

        if col > thisLevel.lvlWidth - 1 or col < 0:
            return True

        # check the offending tile ID
        result = thisLevel.GetMapTile((row, col))

        # if the tile was a wall
        if 100 <= result <= 199:
            return True
        else:
            return False

    def CheckIfHitWall(self, possiblePlayerX_possiblePlayerY, row_col):
        (possiblePlayerX, possiblePlayerY) = possiblePlayerX_possiblePlayerY
        (row, col) = row_col
        numCollisions = 0

        # check each of the 9 surrounding tiles for a collision
        for iRow in range(row - 1, row + 2, 1):
            for iCol in range(col - 1, col + 2, 1):

                if (possiblePlayerX - (iCol * TILE_WIDTH) < TILE_WIDTH) and (
                        possiblePlayerX - (
                        iCol * TILE_WIDTH) > -TILE_WIDTH) and (
                        possiblePlayerY - (
                        iRow * TILE_HEIGHT) < TILE_HEIGHT) and (
                        possiblePlayerY - (iRow * TILE_HEIGHT) > -TILE_HEIGHT):

                    if self.IsWall((iRow, iCol), self):
                        numCollisions += 1

        if numCollisions > 0:
            return True
        else:
            return False

    @staticmethod
    def CheckIfHit(playerX_playerY, x_y, cushion):
        (playerX, playerY) = playerX_playerY
        (x, y) = x_y
        if (playerX - x < cushion) and (playerX - x > -cushion) and (
                playerY - y < cushion) and (
                playerY - y > -cushion):
            return True
        else:
            return False

    @staticmethod
    def CheckIfHitSomething(playerX_playerY, row_col, thisLevel, tileID,
                            player, thisGame, ghosts, scorer):
        (playerX, playerY) = playerX_playerY
        (row, col) = row_col
        for iRow in range(row - 1, row + 2, 1):
            for iCol in range(col - 1, col + 2, 1):

                if (playerX - (iCol * TILE_WIDTH) < TILE_WIDTH) and (
                        playerX - (iCol * TILE_WIDTH) > -TILE_WIDTH) and (
                        playerY - (iRow * TILE_HEIGHT) < TILE_HEIGHT) and (
                        playerY - (iRow * TILE_HEIGHT) > -TILE_HEIGHT):
                    # check the offending tile ID
                    result = thisLevel.GetMapTile((iRow, iCol))

                    if result == tileID['pellet']:
                        # got a pellet
                        thisLevel.SetMapTile((iRow, iCol), 0)
                        # snd_pellet[player.pelletSndNum].play()
                        player.pelletSndNum = 1 - player.pelletSndNum

                        thisLevel.pellets -= 1

                        thisGame.AddToScore(10, thisGame)
                        scorer.score_pellet_eat()

                        if thisLevel.pellets == 0:
                            # no more pellets left!
                            # WON THE LEVEL
                            if thisGame.mode != 6:
                                thisGame.SetMode(6)
                                scorer.score_level_finished()

                    elif result == tileID['pellet-power']:
                        # got a power pellet
                        thisGame.SetMode(9)
                        thisLevel.SetMapTile((iRow, iCol), 0)
                        # snd_powerpellet.play()

                        # thisGame.AddToScore(100, thisGame)
                        thisGame.AddToScore(50, thisGame)
                        scorer.score_power_pellet_eat()
                        thisGame.ghostValue = 200

                        thisGame.ghostTimer = 360
                        for i in range(0, 4, 1):
                            if ghosts[i].state == 1:
                                ghosts[i].state = 2

                    elif result == tileID['door-h']:
                        # ran into a horizontal door
                        scorer.score_door_entry()
                        for i in range(0, thisLevel.lvlWidth, 1):
                            if not i == iCol:
                                if thisLevel.GetMapTile((iRow, i)) == tileID[
                                    'door-h']:
                                    player.x = i * TILE_WIDTH

                                    if player.velX > 0:
                                        player.x += TILE_WIDTH
                                    else:
                                        player.x -= TILE_WIDTH

                    elif result == tileID['door-v']:
                        # ran into a vertical door
                        scorer.score_door_entry()
                        for i in range(0, thisLevel.lvlHeight, 1):
                            if not i == iRow:
                                if thisLevel.GetMapTile((i, iCol)) == tileID[
                                    'door-v']:
                                    player.y = i * TILE_HEIGHT

                                    if player.velY > 0:
                                        player.y += TILE_HEIGHT
                                    else:
                                        player.y -= TILE_HEIGHT
        return 0

    def GetGhostBoxPos(self, tileID):
        for row in range(0, self.lvlHeight, 1):
            for col in range(0, self.lvlWidth, 1):
                if self.GetMapTile((row, col)) == tileID['ghost-door']:
                    return row, col

        return False

    def GetPathwayPairPos(self, tileID, thisLevel, random):
        doorArray = []

        for row in range(0, self.lvlHeight, 1):
            for col in range(0, self.lvlWidth, 1):
                if self.GetMapTile((row, col)) == tileID['door-h']:
                    # found a horizontal door
                    doorArray.append((row, col))
                elif self.GetMapTile((row, col)) == tileID['door-v']:
                    # found a vertical door
                    doorArray.append((row, col))

        if len(doorArray) == 0:
            return False

        chosenDoor = random.randint(0, len(doorArray))  # - 1)

        if self.GetMapTile(doorArray[chosenDoor]) == tileID['door-h']:
            # horizontal door was chosen
            # look for the opposite one
            for i in range(0, thisLevel.lvlWidth, 1):
                if not i == doorArray[chosenDoor][1]:
                    if thisLevel.GetMapTile((doorArray[chosenDoor][0], i)) == \
                            tileID['door-h']:
                        return doorArray[chosenDoor], (
                            doorArray[chosenDoor][0], i)
        else:
            # vertical door was chosen
            # look for the opposite one
            for i in range(0, thisLevel.lvlHeight, 1):
                if not i == doorArray[chosenDoor][0]:
                    if thisLevel.GetMapTile((i, doorArray[chosenDoor][1])) == \
                            tileID['door-v']:
                        return doorArray[chosenDoor], (
                            i, doorArray[chosenDoor][1])

        return False

    def PrintMap(self):
        for row in range(0, self.lvlHeight, 1):
            outputLine = ""
            for col in range(0, self.lvlWidth, 1):
                outputLine += str(self.GetMapTile((row, col))) + ", "

    def DrawMap(self, thisGame, tileID, screen, tileIDImage):
        if not self.gui:
            GetImageCrossRef(tileIDImage, self)
            self.gui = True

        self.powerPelletBlinkTimer += 1
        if self.powerPelletBlinkTimer == 40:
            self.powerPelletBlinkTimer = 0

        for row in range(-1, thisGame.screenTileSize[0] + 1, 1):
            for col in range(-1, thisGame.screenTileSize[1] + 1, 1):

                # row containing tile that actually goes here
                actualRow = thisGame.screenNearestTilePos[0] + row
                actualCol = thisGame.screenNearestTilePos[1] + col

                useTile = self.GetMapTile((actualRow, actualCol))
                if useTile != 0 and useTile != tileID['door-h'] and useTile != \
                        tileID['door-v']:
                    # if this isn't a blank tile
                    if useTile == tileID['pellet-power']:
                        if self.powerPelletBlinkTimer < 20:
                            screen.blit(tileIDImage[useTile], (
                                col * TILE_WIDTH - thisGame.screenPixelOffset[
                                    0],
                                row * TILE_HEIGHT - thisGame.screenPixelOffset[
                                    1]))

                    elif useTile == tileID['showlogo']:
                        screen.blit(thisGame.imLogo, (
                            col * TILE_WIDTH - thisGame.screenPixelOffset[0],
                            row * TILE_HEIGHT - thisGame.screenPixelOffset[1]))

                    elif useTile == tileID['hiscores']:
                        screen.blit(thisGame.imHiscores, (
                            col * TILE_WIDTH - thisGame.screenPixelOffset[0],
                            row * TILE_HEIGHT - thisGame.screenPixelOffset[1]))

                    else:
                        screen.blit(tileIDImage[useTile], (
                            col * TILE_WIDTH - thisGame.screenPixelOffset[0],
                            row * TILE_HEIGHT - thisGame.screenPixelOffset[1]))

    def LoadLevel(self, levelNum, thisFruit, player, ghosts, path,
                  thisGame, tileID, tileIDName, random):
        levelNum = str(levelNum)
        # TODO: Find better way to mitigate IO bottleneck.
        if levelNum in self.preload_width:
            self.lvlWidth = self.preload_width[levelNum]
            self.lvlHeight = self.preload_height[levelNum]
            self.edgeLightColor = self.preload_edge_light[levelNum]
            self.edgeShadowColor = self.preload_edge_shadow[levelNum]
            self.pelletColor = self.preload_pellet_color[levelNum]
            self.fillColor = self.preload_fill[levelNum]
            self.pelletColor = self.preload_pellet_color[levelNum]
            self.map = self.preload_map[levelNum].copy()
            self.pellets = self.preload_pellets[levelNum]
            thisFruit.fruitType = self.preload_fruit_type[levelNum]
            player.homeX, player.homeY = self.preload_player_home[levelNum]
            for i in range(4):
                ghosts[i].homeX, ghosts[i].homeY = \
                    self.preload_ghosts_home[levelNum][i]
            # load map into the pathfinder object
            path.ResizeMap((self.lvlHeight, self.lvlWidth))
            for row in range(0, path.size[0], 1):
                for col in range(0, path.size[1], 1):
                    if self.IsWall((row, col), self):
                        path.SetType((row, col), 1)
                    else:
                        path.SetType((row, col), 0)
            # do all the level-starting stuff
            self.Restart(thisGame, player, ghosts, tileID, path, thisFruit,
                         random)
            return

        self.map = {}
        self.preload_ghosts_home[levelNum] = [(0, 0)] * 4
        self.pellets = 0

        f = open(
            os.path.join(SCRIPT_PATH, "res", "levels", str(levelNum) + ".txt"),
            'r')
        lineNum = -1
        rowNum = 0
        isReadingLevelData = False

        for line in f:

            lineNum += 1

            # print " ------- Level Line " + str(lineNum) + " -------- "
            while len(line) > 0 and (
                    line[-1] == "\n" or line[-1] == "\r"): line = line[:-1]
            while len(line) > 0 and (
                    line[0] == "\n" or line[0] == "\r"): line = line[1:]
            # str_splitBySpace = line.split(' ')
            # TODO: Check if whitespace split is fine.
            str_splitBySpace = split("\\s+", line)

            j = str_splitBySpace[0]

            if j == "'" or j == "":
                # comment / whitespace line
                # print " ignoring comment line.. "
                useLine = False
            elif j == "#":
                # special divider / attribute line
                useLine = False

                firstWord = str_splitBySpace[1]

                if firstWord == "lvlwidth":
                    self.lvlWidth = int(str_splitBySpace[2])

                elif firstWord == "lvlheight":
                    self.lvlHeight = int(str_splitBySpace[2])

                elif firstWord == "edgecolor":
                    # edge color keyword for backwards compatibility (single edge color) mazes
                    red = int(str_splitBySpace[2])
                    green = int(str_splitBySpace[3])
                    blue = int(str_splitBySpace[4])
                    self.edgeLightColor = (red, green, blue, 255)
                    self.edgeShadowColor = (red, green, blue, 255)

                elif firstWord == "edgelightcolor":
                    red = int(str_splitBySpace[2])
                    green = int(str_splitBySpace[3])
                    blue = int(str_splitBySpace[4])
                    self.edgeLightColor = (red, green, blue, 255)

                elif firstWord == "edgeshadowcolor":
                    red = int(str_splitBySpace[2])
                    green = int(str_splitBySpace[3])
                    blue = int(str_splitBySpace[4])
                    self.edgeShadowColor = (red, green, blue, 255)

                elif firstWord == "fillcolor":
                    red = int(str_splitBySpace[2])
                    green = int(str_splitBySpace[3])
                    blue = int(str_splitBySpace[4])
                    self.fillColor = (red, green, blue, 255)

                elif firstWord == "pelletcolor":
                    red = int(str_splitBySpace[2])
                    green = int(str_splitBySpace[3])
                    blue = int(str_splitBySpace[4])
                    self.pelletColor = (red, green, blue, 255)

                elif firstWord == "fruittype":
                    self.preload_fruit_type[levelNum] = int(
                        str_splitBySpace[2])
                    thisFruit.fruitType = int(str_splitBySpace[2])

                elif firstWord == "startleveldata":
                    isReadingLevelData = True
                    # print "Level data has begun"
                    rowNum = 0

                elif firstWord == "endleveldata":
                    isReadingLevelData = False
            # print "Level data has ended"

            else:
                useLine = True

            # this is a map data line
            if useLine:

                if isReadingLevelData:

                    # print str( len(str_splitBySpace) ) + " tiles in this column"

                    for k in range(0, self.lvlWidth, 1):
                        self.SetMapTile((rowNum, k), int(str_splitBySpace[k]))

                        thisID = int(str_splitBySpace[k])
                        if thisID == 4:
                            # starting position for pac-man

                            player.homeX = k * TILE_WIDTH
                            player.homeY = rowNum * TILE_HEIGHT
                            self.preload_player_home[levelNum] = (
                                player.homeX, player.homeY)
                            self.SetMapTile((rowNum, k), 0)

                        elif 10 <= thisID <= 13:
                            # one of the ghosts

                            ghosts[thisID - 10].homeX = k * TILE_WIDTH
                            ghosts[thisID - 10].homeY = rowNum * TILE_HEIGHT
                            self.preload_ghosts_home[levelNum][thisID - 10] = (
                                k * TILE_WIDTH, rowNum * TILE_HEIGHT)
                            self.SetMapTile((rowNum, k), 0)

                        elif thisID == 2:
                            # pellet

                            self.pellets += 1

                    rowNum += 1
        f.close()
        # reload all tiles and set appropriate colors
        GetCrossRef(tileIDName, tileID)

        # load map into the pathfinder object
        path.ResizeMap((self.lvlHeight, self.lvlWidth))

        for row in range(0, path.size[0], 1):
            for col in range(0, path.size[1], 1):
                if self.IsWall((row, col), self):
                    path.SetType((row, col), 1)
                else:
                    path.SetType((row, col), 0)

        # do all the level-starting stuff
        self.preload_width[levelNum] = self.lvlWidth
        self.preload_height[levelNum] = self.lvlHeight
        self.preload_edge_light[levelNum] = self.edgeLightColor
        self.preload_edge_shadow[levelNum] = self.edgeShadowColor
        self.preload_fill[levelNum] = self.fillColor
        self.preload_pellet_color[levelNum] = self.pelletColor
        self.preload_map[levelNum] = self.map.copy()
        self.preload_pellets[levelNum] = self.pellets
        self.Restart(thisGame, player, ghosts, tileID, path, thisFruit, random)

    def Restart(self, thisGame, player, ghosts, tileID, path, thisFruit,
                random):
        # if thisGame.levelNum == 2:
        # player.speed = 4

        for i in range(0, 4, 1):
            # move ghosts back to home
            ghosts[i].x = ghosts[i].homeX
            ghosts[i].y = ghosts[i].homeY
            if self.randomized:
                # (randRow, randCol) = (0, 0)
                # while not self.GetMapTile((randRow, randCol)) == tileID[
                # 'pellet'] or (randRow, randCol) == (0, 0):
                while True:
                    randRow = random.randint(1, self.lvlHeight - 1)  # 2)
                    randCol = random.randint(1, self.lvlWidth - 1)  # 2)
                    tile = self.GetMapTile((randRow, randCol))
                    if tile == tileID["ghost-door"] or \
                            tile == tileID["pellet"] or \
                            tile == tileID["pellet-power"]:
                        break
                ghosts[i].x = randCol * TILE_WIDTH
                ghosts[i].y = randRow * TILE_HEIGHT
            ghosts[i].velX = 0
            ghosts[i].velY = 0
            ghosts[i].state = 1
            ghosts[i].speed = 2
            ghosts[i].Move(path, player, self, tileID, random)

            # give each ghost a path to a random spot (containing a pellet)
            (randRow, randCol) = (0, 0)

            while not self.GetMapTile((randRow, randCol)) == tileID[
                'pellet'] or (randRow, randCol) == (0, 0):
                randRow = random.randint(1, self.lvlHeight - 1)  # 2)
                randCol = random.randint(1, self.lvlWidth - 1)  # 2)

            # print "Ghost " + str(i) + " headed towards " + str((randRow, randCol))
            ghosts[i].currentPath = path.FindPath(
                (ghosts[i].nearestRow, ghosts[i].nearestCol),
                (randRow, randCol))
            ghosts[i].FollowNextPathWay(path, player, self, tileID, random)

        thisFruit.active = False

        thisGame.fruitTimer = 0

        player.x = player.homeX
        player.y = player.homeY
        if self.randomized:
            # (randRow, randCol) = (0, 0)
            # while not self.GetMapTile((randRow, randCol)) == tileID[
            # 'pellet'] or (randRow, randCol) == (0, 0):
            while True:
                randRow = random.randint(1, self.lvlHeight - 1)  # 2)
                randCol = random.randint(1, self.lvlWidth - 1)  # 2)
                tile = self.GetMapTile((randRow, randCol))
                if tile == tileID["pellet"] or tile == tileID["pellet-power"]:
                    break
            player.x = randCol * TILE_WIDTH
            player.y = randRow * TILE_HEIGHT

        player.nearestRow = int(((player.y + (TILE_WIDTH / 2)) / TILE_WIDTH))
        player.nearestCol = int(((player.x + (TILE_HEIGHT / 2)) / TILE_HEIGHT))
        player.velX = 0
        player.velY = 0

        player.anim_pacmanCurrent = player.anim_pacmanS
        player.animFrame = 3


import datetime
from typing import Any, Dict, Type, TypeVar, Union

import attr
from dateutil.parser import isoparse

from ..types import UNSET, Unset

T = TypeVar("T", bound="CodatPullMessagesContractsValidationMessage")

@attr.s(auto_attribs=True)
class CodatPullMessagesContractsValidationMessage:
    """
    Attributes:
        rule_id (Union[Unset, None, str]):
        item_id (Union[Unset, None, str]):
        validator_name (Union[Unset, None, str]):
        log_level (Union[Unset, None, str]):
        message (Union[Unset, None, str]):
        log_date_time_utc (Union[Unset, None, datetime.datetime]):
    """

    rule_id: Union[Unset, None, str] = UNSET
    item_id: Union[Unset, None, str] = UNSET
    validator_name: Union[Unset, None, str] = UNSET
    log_level: Union[Unset, None, str] = UNSET
    message: Union[Unset, None, str] = UNSET
    log_date_time_utc: Union[Unset, None, datetime.datetime] = UNSET

    def to_dict(self) -> Dict[str, Any]:
        rule_id = self.rule_id
        item_id = self.item_id
        validator_name = self.validator_name
        log_level = self.log_level
        message = self.message
        log_date_time_utc: Union[Unset, None, str] = UNSET
        if not isinstance(self.log_date_time_utc, Unset):
            log_date_time_utc = self.log_date_time_utc.isoformat() if self.log_date_time_utc else None

        field_dict: Dict[str, Any] = {}
        field_dict.update({})
        if rule_id is not UNSET:
            field_dict["ruleId"] = rule_id
        if item_id is not UNSET:
            field_dict["itemId"] = item_id
        if validator_name is not UNSET:
            field_dict["validatorName"] = validator_name
        if log_level is not UNSET:
            field_dict["logLevel"] = log_level
        if message is not UNSET:
            field_dict["message"] = message
        if log_date_time_utc is not UNSET:
            field_dict["logDateTimeUtc"] = log_date_time_utc

        return field_dict

    @classmethod
    def from_dict(cls: Type[T], src_dict: Dict[str, Any]) -> T:
        d = src_dict.copy()
        rule_id = d.pop("ruleId", UNSET)

        item_id = d.pop("itemId", UNSET)

        validator_name = d.pop("validatorName", UNSET)

        log_level = d.pop("logLevel", UNSET)

        message = d.pop("message", UNSET)

        _log_date_time_utc = d.pop("logDateTimeUtc", UNSET)
        log_date_time_utc: Union[Unset, None, datetime.datetime]
        if _log_date_time_utc is None:
            log_date_time_utc = None
        elif isinstance(_log_date_time_utc, Unset):
            log_date_time_utc = UNSET
        else:
            log_date_time_utc = isoparse(_log_date_time_utc)

        codat_pull_messages_contracts_validation_message = cls(
            rule_id=rule_id,
            item_id=item_id,
            validator_name=validator_name,
            log_level=log_level,
            message=message,
            log_date_time_utc=log_date_time_utc,
        )

        return codat_pull_messages_contracts_validation_message


# -*- coding: utf-8 -*-

from urllib import parse
from aiohttp import web
import asyncio
import inspect
import logging

from utils.apis import APIError, APIBadRequest, APIMissingParams
import web.middleware as middleware

app = web.Application(middlewares=middleware.middlewares, client_max_size=(1024 ** 2) * 32)

def func_args_filter(func, _filter):
    """Filter the function args list with the given filter

    Args:
        func: (function) Detect the args from the function
        _filter: (function) Args filter

    Returns:
        tuple: Filtered args list
    """
    params = inspect.signature(func).parameters
    args = [name
            for (name, param) in params.items()
            if _filter(param)]
    return tuple(args)

class HandleRequest:
    def __init__(self, func):
        """Init class HandleRequest

        Args:
            func: (function) Handler function
        """
        self.func = func
        self.named_args = func_args_filter(func, lambda param: param.kind == inspect.Parameter.KEYWORD_ONLY)
        self.required_args = func_args_filter(func,
            lambda param: param.kind == inspect.Parameter.KEYWORD_ONLY and param.default == inspect.Parameter.empty)
        self.has_var_args = len(func_args_filter(func, lambda param: param.kind == inspect.Parameter.VAR_KEYWORD)) > 0

    @staticmethod
    async def get_request_params(request):
        """Get request params or payload from `request`

        Args:
            request: (aiohttp.web.Request) Request instance

        Returns:
            dict: Request params or payload

        Raises:
            APIBadRequest: An error occurred if the request body is invalid
        """
        kw = None
        if request.method == 'POST':
            if not request.content_type:
                raise APIBadRequest('Missing Content-Type.')
            ct = request.content_type.lower()
            if ct.startswith('application/json') or ct.startswith('application/csp-report'):
                params = await request.json()
                if not isinstance(params, dict):
                    raise APIBadRequest('JSON body must be object.')
                kw = dict(**params)
            elif ct.startswith('application/x-www-form-urlencoded') or ct.startswith('multipart/form-data'):
                params = await request.post()
                kw = dict(**params)
            else:
                raise APIBadRequest(f'Unsupported Content-Type: {request.content_type}')

            # replace the character that python does not allow to be appear in variable name
            kw = {k.replace('-', '_'): v for (k, v) in kw.items()}
        elif request.method == 'GET':
            qs = request.query_string
            if qs:
                kw = dict()
                for k, v in parse.parse_qs(qs, True).items():
                    kw[k] = v[0]
        if kw is None:
            kw = dict(**request.match_info)
        return kw

    def filter_params(self, kw, request):
        """Filter and check the required request data for handler function

        Args:
            kw: (dict) Request data
            request: (aiohttp.web.Request) Request instance

        Returns:
            dict: Request data needed by the handler

        Raises:
            APIMissingParams: An error occurred if the params is missing
        """
        # copy the args needed by the handler
        if not self.has_var_args and len(self.named_args):
            copy = dict()
            for name in self.named_args:
                if name in kw:
                    copy[name] = kw[name]
            kw = copy
        for k, v in request.match_info.items():
            if k in kw:
                logging.warning(f'Duplicate arg name in named arg and kw args: {k}')
            kw[k] = v
        if 'request' in self.named_args:
            kw['request'] = request

        # check the required args
        if len(self.required_args):
            for name in self.required_args:
                if not name in kw:
                    raise APIMissingParams(name)
        return kw

    async def __call__(self, request):
        """Call the handler function
        """
        try:
            kw = dict()
            if self.has_var_args or len(self.required_args) or len(self.named_args):
                kw = await self.get_request_params(request)
            kw = self.filter_params(kw, request)
            logging.debug(f'call with args: {str(kw)}')
            resp = await self.func(**kw)
        except APIError as e:
            return web.json_response(dict(error=e.error, msg=e.msg), status=400)
        except Exception:
            return web.json_response(dict(error='server:server_internal_error'), status=500)
        return resp

def add_route(method, path, func):
    """Add a route to `app`

    Args:
        method: (str) Request method
        path: (str) Request path
        func: (function) Request handler
    """
    if not asyncio.iscoroutinefunction(func) and not inspect.isgeneratorfunction(func):
        func = asyncio.coroutine(func)
    logging.info(
        f'Add route {method.upper()} {path} => {func.__name__}({", ".join(inspect.signature(func).parameters.keys())})')
    app.router.add_route(method, path, HandleRequest(func))

def decorator_factory(method):
    """Request method decorator factory

    Args:
        method: (str) Request method

    Returns:
        function: Request method decorator
    """

    def router(path):
        def decorator(func):
            add_route(method, path, func)
            return func

        return decorator

    return router

# define request method decorator
get = decorator_factory('get')
post = decorator_factory('post')

def init_coroweb():
    pass


import pygame
from random import randint
from shapes import BlackBird
from shapes import BlueBird
from shapes import Plain
from shapes import Bullet
from shapes import Button
import sys
import os
from game_loop import my_function

pygame.init()
# Set up an assets folders, so the game could run on any computer
Angry_Birds_Game_folder = os.path.dirname(__file__)
img_folder = os.path.join(Angry_Birds_Game_folder, "img")
sound_folder = os.path.join(Angry_Birds_Game_folder, "sound")

# Some constant var
WINDOW_WIDTH = 802
WINDOW_HEIGHT = 466
user = "Tamar oling"
size = (WINDOW_WIDTH, WINDOW_HEIGHT)
PINK_BACKGROUND = (255, 20, 147)
LIGHT_PINK = (255, 174, 201)
LIFES = 0
FPS = 60 # frames per sec
SOUND_FILE = "Angry Birds Theme Song.mp3"

# setting of mouse movement:
LEFT = 1
SCROLL = 2
RIGHT = 3

## initialzing pygame and creating a window

# Init screen
pygame.init()
size = (WINDOW_WIDTH, WINDOW_HEIGHT)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Angry Birds Game")
img_background = pygame.image.load(os.path.join(img_folder, 'clouds background.jpg')).convert()
screen.blit(img_background, (0, 0)) # loading the image to coordinates (0,0)
# if we load to (150,0) the image will move more to the right on the screen
# so the bottom rightest pixel on the screen will be (801, 465)

# init player- the plain
pygame.mouse.set_visible(False) # in order to not see the mouse arrow

player_image = pygame.image.load(os.path.join(img_folder, 'plain.png')).convert()
player_image.set_colorkey(PINK_BACKGROUND)
screen.blit(player_image, [220, 300]) #the size of the plain
pygame.display.flip()

# refreshing screen rate for moving objects
clock = pygame.time.Clock()

# init music
pygame.mixer.init()
pygame.mixer.music.load('sound\Angry Birds Theme Song.mp3')
pygame.mixer.music.play(-1)

crash_sound = pygame.mixer.Sound("sound\Bomb Explosion 1-SoundBible.com-980698079.wav")
winning_sound = pygame.mixer.Sound("sound\Ta Da-SoundBible.com-1884170640.wav")
loser_sound = pygame.mixer.Sound("sound\Smashing-Yuri_Santana-1233262689.wav")
gunshot_sound = pygame.mixer.Sound("sound\gunshot_single-mike-koenig.wav")
#pygame.mixer.music.load(os.path.join(sound_folder, "Angry Birds Theme Song.mp3"))
#pygame.mixer.music.play(loops=-1)

all_bullets = pygame.sprite.Group()
all_birds = pygame.sprite.Group()
player = Plain()
pygame.time.set_timer(pygame.USEREVENT, 500)

score = 0 # player score
life_score = 0 # How many times the player can touch the birds before loosing
myfont = pygame.font.SysFont("monospace", 16)

# to play I need to call the game_loop function
# I need to do the start over button

life_score = my_function(clock, FPS, screen, all_birds, player, all_bullets, LEFT, score, life_score, myfont, gunshot_sound, crash_sound,  img_background, loser_sound)
if life_score < 0:
    # img_background = pygame.image.load(os.path.join(img_folder, 'the game you just lost it.jpg')).convert()
    # screen.blit(img_background, (0, 0))
    finish = False
    while not finish and life_score < 0:
        clock.tick(FPS)
        pygame.display.update()
        img_background = pygame.image.load(os.path.join(img_folder, 'the game you just lost it.jpg')).convert()
        screen.blit(img_background, (100, 50))
        pygame.mouse.set_visible(True)  # in order to see the mouse arrow
        # making the button
        start_over_button = Button(LIGHT_PINK, 335, 401, 150, 50, 'Start Over :)')
        # drawing and adding a frame in the color specified
        start_over_button.draw(screen, (0, 0, 0))
        for event in pygame.event.get():
            mouse_point = pygame.mouse.get_pos()
            if event.type == pygame.QUIT:
                finish = True
            if event.type == pygame.MOUSEMOTION:
                if start_over_button.isOver(mouse_point):
                    start_over_button.color = (255, 34, 106)
                else:
                    start_over_button.color = LIGHT_PINK

            if event.type == pygame.MOUSEBUTTONDOWN:
                if start_over_button.isOver(mouse_point):
                    score = 0
                    life_score = 0

                    # Init screen for restart the game
                    size = (WINDOW_WIDTH, WINDOW_HEIGHT)
                    screen = pygame.display.set_mode(size)
                    pygame.display.set_caption("Angry Birds Game")
                    img_background = pygame.image.load(os.path.join(img_folder, 'clouds background.jpg')).convert()
                    screen.blit(img_background, (0, 0))  # loading the image to coordinates (0,0)
                    # if we load to (150,0) the image will move more to the right on the screen
                    # so the bottom rightest pixel on the screen will be (801, 465)

                    #init the birds and bullets and the player
                    all_bullets = pygame.sprite.Group()
                    all_birds = pygame.sprite.Group()
                    player = Plain()

                    life_score = my_function(clock, FPS, screen, all_birds, player, all_bullets, LEFT, score,
                                             life_score, myfont, gunshot_sound, crash_sound, img_background,
                                             loser_sound)

pygame.quit()


# importing required Libraries
import RPi.GPIO as GPIO
import time
import datetime
import serial
from gtts import gTTS
import pyttsx3
import os
import sys

# connection of hardwares with GPIO pin of Raspberry Pi
GPIO.setmode(GPIO.BOARD)

GPIO_TRIGGER = 18
GPIO_ECHO = 24
buzzer = 16
button_date = 22
button_sms = 13
GPIO.setup(buzzer, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(button_date, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(GPIO_TRIGGER, GPIO.OUT)
GPIO.setup(GPIO_ECHO, GPIO.IN)

# code for obstactle ditection
def distance():
    GPIO.output(GPIO_TRIGGER, True)
    time.sleep(0.00001)
    GPIO.output(GPIO_TRIGGER, False)
    StartTime = time.time()
    StopTime = time.time()

    while GPIO.input(GPIO_ECHO) == 0:
        StartTime = time.time()
    while GPIO.input(GPIO_ECHO) == 1:
        StopTime = time.time()
    TimeElapsed = StopTime - StartTime
    distance = (TimeElapsed * 34300) / 2
    return distance

# code for sending message
def sms():
    serial_port = "/dev/serial0"
    mob_num = "9804089456"

    # Enable Serial Communication
    ser = serial.Serial(serial_port, baudrate = 9600, timeout = 5)

    # Transmitting AT Commands to the Modem
    # '\r' indicates the Enter key
    ser.write(('AT'+'\r').encode())

    # Disable the Echo
    ser.write(('ATE0'+'\r').encode())
    #  Select Message format as Text mode
    ser.write(("AT+CMGF=1"+"\r").encode())
    print ("Text mode enabled....")
    time.sleep(1)
    # Sending a message to a particular Number
    ser.write(('AT+CMGS='+mob_num+'\r').encode())
    msg = "Pannic button integration testing1"
    print ("sending message")
    time.sleep(2)
    ser.write((msg+chr(50)).encode())

# code for alerting about the object and the distance in the form of sound
try:
    while True:
        button_state_date= GPIO.input(button_date)
        button_state_sms= GPIO.input(button_sms)
        dist = distance()
        distt = round(dist, 2)
        dis = str(distt)
        now = datetime.datetime.now()
        current_date = now.strftime("%Y-%m-%d")
        current_time = now.strftime("%H:%M:%S")
        engine = pyttsx3.init()

        # Button for Current date (Buton-1)
        if button_state_date == False:
            print('Button for date Pressed...')
            engine.say('The Current Date and Time is ' + current_date +'and'+ current_time)
            engine.runAndWait()
            engine.stop()
            # tts_en = gTTS('The Current Date and Time is ' + current_date_time , lang='hi')
            # tts_en.save("CurrentDateTime.mp3")
            # os.system("mpg321 -q CurrentDateTime.mp3")
            time.sleep(0.1)

        # Button for SMS Alert (Buton-2)
        elif button_state_sms == False:
            print('Button For SMS Pressed...')
            sms()

        elif (dist < 15):
            GPIO.output(buzzer, GPIO.HIGH)
            time.sleep(0.1)
            GPIO.output(buzzer, GPIO.LOW)
            print("Measured Distance = "+dis + " cm")
            print("Soo near")
            time.sleep(0.1)

        elif (dist > 15.0 and dist <= 25) :
            GPIO.output(buzzer, GPIO.HIGH)
            time.sleep(0.5)
            GPIO.output(buzzer, GPIO.LOW)
            print("Measured Distance = "+dis + " cm")
            print("near")
            time.sleep(0.1)

        elif(dist > 25 and dist <=100):
            print("Measured Distance = "+dis + " cm")
            print("Far")
            engine.say('the object is ' + dis + 'cm ahead ! be alert!')
            engine.runAndWait()
            engine.stop()
            #tts_en = gTTS('the object is ' + dis + 'cm ahead ! be alert!!', lang='hi')
            #tts_en.save("distance.mp3")
            #os.system("mpg321 -q distance.mp3")
            time.sleep(0.1)

except KeyboardInterrupt:
    GPIO.cleanup()


def twoSum(self, nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: output: List[int]
    """
    output = []
    flag = False
    for ip, i in enumerate(nums):
        if flag:
            break
        for jp, j in enumerate(nums):
            if ip == jp:
                continue
            if (i+j) == target:
                output.append(ip)
                output.append(jp)
                flag = True
                break
    return output


from lib.disk_struct import Disk
from algorithms.page_replacement_algorithm import  page_replacement_algorithm
import numpy as np
## Keep a LRU list.
## Page hits:
##      Every time we get a page hit, mark the page and also move it to the MRU position
## Page faults:
##      Evict an unmark page with the probability proportional to its position in the LRU list.
class ARC(page_replacement_algorithm):

    def __init__(self, param):
        assert 'cache_size' in param
        self.N = param['cache_size']
        self.T1 = Disk(self.N)
        self.T2 = Disk(self.N)
        self.B1 = Disk(self.N)
        self.B2 = Disk(2*self.N)
        self.P = 0

        self.time = 0
        self.X = []
        self.Y = []

        self.unique = {}
        self.unique_cnt = 0
        self.pollution_dat_x = []
        self.pollution_dat_y = []

    def __contains__(self, q):
        return q in self.T1 or q in self.T2

    def getWeights(self):
#         return np.array([self. X, self.Y1, self.Y2,self.pollution_dat_x,self.pollution_dat_y ]).T
        return np.array([self.pollution_dat_x,self.pollution_dat_y ]).T

    def getStats(self):
        d={}
        d['pollution'] = np.array([self.pollution_dat_x, self.pollution_dat_y ]).T
        return d

    def visualize(self, plt):
#         l1, = plt.plot(self.X,self.Y,'r-', label='ARC p-value')
#         return [l1]
        return []

    def get_N(self) :
        return self.N

    def request(self,page) :
        page_fault = False
        self.time += 1
#         self.X.append(self.time)
#         self.Y.append(1.0*self.P / self.N)
        t1 = self.T1.size()
        t2 = self.T2.size()
        b1 = self.B1.size()
        b2 = self.B2.size()

        assert t1+t2 <= self.N, 'Error: t1+t2 should not be bigger than self.N. t1+t2=%d+%d=%d' % (t1,t2,t1+t2)
        assert t1+b1 <= self.N, 'Error: t1+b1 should not be bigger than self.N. t1+b1=%d+%d=%d' % (t1,b1,t1+b1)
        assert t1+t2+b1+b2 <= 2*self.N, 'Error: t1+t2+b1+b2 should not be bigger than 2*self.N. t1+t2+b1+b2=%d+%d+%d+%d=%d' % (t1,t2,b1,b2,t1+t2+b1+b2)

        if page in self.T1  or page in self.T2:
            if page in self.T1 :
                assert self.T1.delete(page)
            if page in self.T2 :
                assert self.T2.delete(page)

            assert self.T2.add(page), 'failed adding to T2 at Case 1'

        elif self.B1.inDisk(page) :

            if self.B2.size() > self.B1.size() :
                r = self.B2.size() / self.B1.size()
            else :
                r = 1
            self.P = min(self.P + r, self.N)
            self.__replace(page)
            assert self.B1.delete(page)
            assert self.T2.add(page), 'failed adding to T2 at case B1'
            page_fault = True
        elif self.B2.inDisk(page) :
            if self.B1.size() > self.B2.size() :
                r = self.B1.size() / self.B2.size()
            else :
                r = 1
            self.P = max(self.P - r, 0)
            self.__replace(page)
            assert self.B2.delete(page)
            assert self.T2.add(page), 'failed adding to T2  at case B2'
            page_fault = True
        else :
            if t1 + b1 == self.N :
                if t1 < self.N :
                    assert self.B1.deleteFront() is not None, 'Error deleting front of B1'
                    self.__replace(page)
                else :
                    assert self.T1.deleteFront() is not None, 'Error deleting front of T1'
            elif t1 + b1 < self.N :
                if t1 + t2 + b1 + b2 >= self.N :
                    if t1 + t2 + b1 + b2 == 2 * self.N :
                        assert self.B2.deleteFront() is not None,  'Error deleting front of B2'
                    self.__replace(page)

            # Add page to the MRU position in T1
            assert self.T1.add(page), 'failed adding page to T1 at case 4'
            page_fault = True

#         if page_fault :
#             self.unique_cnt += 1
#
#         self.unique[page] = self.unique_cnt
#
#         if self.time % self.N == 0:
#             pollution = 0
#             for pg in self.T1.getData() + self.T2.getData():
#                 if self.unique_cnt - self.unique[pg] >= 2*self.N:
#                     pollution += 1
#             self.pollution_dat_x.append(self.time)
#             self.pollution_dat_y.append(100 * pollution / self.N)

        return page_fault

    def __replace(self,x) :
        if self.T1.size() > 0 and (self.T1.size() > self.P or  (self.B1.inDisk(x) and self.T1.size() == int(self.P))):
            y = self.T1.deleteFront()
            assert y is not None, 'Error deleting front of T1 in replace (Case 1)'
            assert self.B1.add(y), 'failed adding page to B1 at replace 1(Case 1)'
        else:
            y = self.T2.deleteFront()
            assert y is not None, 'Error deleting front of T2 in replace (Case 2)'
            assert self.B2.add(y), 'failed adding page to B2 at replace 1(Case 2)'
#             s1 = self.T1.size()+self.T2.size()
#             s2 = self.B1.size()+self.B2.size()
#             print('sizes = %d + %d + %d + %d = %d + %d = %d' % (self.T1.size(),self.T2.size(),self.B1.size(),self.B2.size(), s1,s2,s1+s2))
#             print('failed adding at replace 2 %d ' %y)

    def get_data(self):
        return [self.T1.get_data(),self.T2.get_data(),self.B1.get_data(),self.B2.get_data()]

    def get_list_labels(self) :
        return ['T1','T2','B1','B2']


from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
    #note: depending on how you installed (e.g., using source code download versus pip install), you may need to import like this:
    #from vaderSentiment import SentimentIntensityAnalyzer
import csv

# input - File name
# Output - Create a csv file for each movie review page
# Output - Calculate Total Score,Min score,Max score,number of positive score,no of negative score

def sentiment(filename):
    filenameip = 'reviewfiles/' + filename + ".csv"
    filenameop = filename + "_results.txt"
    fileop = open(filenameop,'w')
    tot = 0.0
    minval = 9999
    maxval = -9999
    nopos = 0
    noneg = 0
    with open(filenameip) as csvfile:
        readCSV = csv.reader(csvfile, delimiter='|')
        for row in readCSV:
            sentences = row
            for sentence in sentences:
                analyzer = SentimentIntensityAnalyzer()
                vs = analyzer.polarity_scores(sentence)
                stringVS= str(vs)
#                print(stringVS)
                data = stringVS.split("'compound': ")[1]
#                print((sentence, data))
                if (sentence != ""):
                    fileop.write(sentence + "|" + data.rstrip('}') + '\n')
                    tot = tot + float(data.rstrip('}'))
                    if (float(data.rstrip('}')) < minval):
                        minval = float(data.rstrip('}'))
                    if (float(data.rstrip('}')) > maxval):
                        maxval = float(data.rstrip('}'))
                    if (float(data.rstrip('}')) > 0):
                        nopos = nopos + 1
                    else:
                        noneg = noneg + 1
            fileop.close()
    #print(tot)
    return tot,minval,maxval,nopos,noneg
#               newdata = sentence, data

fileinput = open("movieinput.txt",'r')
fileoutput = open("movieoutput.txt",'w')
# Read the input file and create an output file with the review scores
for i in fileinput:
#    print(i)
#    print(i.split("|")[0])
    critictot,criticmin,criticmax,criticsnopos,criticsnoneg = sentiment(i.split("|")[0] + "_critics")
    usertot,usermin,usermax,usernopos,usernoneg = sentiment(i.split("|")[0] + "_user")
    criticavg = critictot / (criticsnopos + criticsnoneg)
    useravg = usertot / (usernopos + usernoneg)
#    print(critictot)
#    print(criticavg)
#    print(useravg)
    fileoutput.write(i.rstrip('\n') + '|' + str(criticavg)  + '|' + str(useravg) + '|'  + str(criticmin)  + '|' + str(criticmax)  + '|' + str(usermin)  + '|' + str(usermax) + '|' + str(criticsnopos)  + '|' + str(criticsnoneg) + '|' + str(usernopos)  + '|' + str(usernoneg) + '\n' )

fileinput.close()
fileoutput.close()


import logging
from time import time_ns

import requests
from fastapi import FastAPI
from springhead.controllers import main_router
from springhead.core import Bootstrap, bootstrap, settings

from .dummy import custom_process_logger
from .schemas import SpringheadTimeCreateRequest

logger = logging.getLogger()

app = FastAPI()
app.include_router(main_router)

def init_logger(level):
    logger.setLevel(level)
    ch = logging.StreamHandler()
    formatter = logging.Formatter(
        "%(asctime)s.%(msecs)03d %(levelname)s %(pathname)s:%(lineno)d: %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )
    ch.setFormatter(formatter)
    logger.addHandler(ch)

@app.on_event("startup")
async def startup():
    init_logger(settings.log_level)

    logger = logging.getLogger(__name__)
    start_time = time_ns()
    app.state.bootstrap: Bootstrap = await bootstrap(
        specification_path="./app/specifications.yml",
        custom_functions={"springhead/dummy": custom_process_logger},
        side_car_address="http://sidecar/springhead/",
        type_test_case="all-combination",
        benchmark_mode=True,
    )  # type: ignore
    end_time = time_ns()
    bootstrap_object = app.state.bootstrap
    if bootstrap_object.benchmark_mode:
        elapsed_time = end_time - start_time
        requests.post(
            bootstrap_object.side_car_address,
            json=SpringheadTimeCreateRequest(
                time_ns=elapsed_time,
                type_test_case=bootstrap_object.type_test_case,
                type_timer="bootstrap",
            ).dict(),
        )
        logger.info(f"elapsed springhead bootstrap: {end_time-start_time}")

    logger.debug(bootstrap_object.handler.functions._functions)
    logger.info("Bootstrap is done")


from matplotlib import pyplot as plt
from multiprocess_experiment import compute_experiment
from constants import P_MIN, P_MAX, NO_PLAYER, PLAYER_STR
import numpy as np
from minmax import minmax_competition
import time
from game_board import BoardState

def graph_depth_comparisons(jobs, samples, n):
    plt.rcParams["figure.figsize"] = 7, 5 * len(jobs)
    fig, axes = plt.subplots(len(jobs), 1)

    if not type(axes) == np.ndarray:
        axes = list([axes])
    else:
        axes = axes.flatten()

    fig.suptitle(
        f"Results of {n}x{n} games from MIN player's perspective over {samples} samples")

    # For each job
    for i, job in enumerate(jobs):
        d_min, player = job
        d_maxs = jobs[job]

        axes[i].set_title(
            f"...given d_min = {d_min} and some d_max with {PLAYER_STR[player]} starting the game")
        axes[i].set_xlabel("d_max")

        Y_wins = []
        Y_ties = []
        Y_defeats = []
        X = []

        # For each depth in job (each bar in graph)
        for d_max in d_maxs:
            X.append(d_max)
            results = compute_experiment(samples, n, player, d_min, d_max)
            if sum(results.values()) != samples:
                raise Exception("SYNC ERROR")
            Y_wins.append(results[P_MIN])
            Y_ties.append(results[NO_PLAYER])
            Y_defeats.append(results[P_MAX])

        # All data collected, graph it
        X = list(map(str, X))
        Y_wins = np.array(Y_wins)
        Y_ties = np.array(Y_ties)
        Y_defeats = np.array(Y_defeats)

        axes[i].bar(X, Y_defeats, color="r", label="loss")
        axes[i].bar(X, Y_ties, bottom=Y_defeats, color="y", label="tie")
        axes[i].bar(X, Y_wins, bottom=Y_defeats + Y_ties, color="g", label="win")

        # Add labels for each bar
        for bar in axes[i].patches:
            font_size = 10
            value = bar.get_height()
            text = f"{round(bar.get_height() / samples * 100, 1)}%"
            x_pos = bar.get_x() + bar.get_width() / 2
            y_pos = max(0, min(samples, value / 2 + bar.get_y()))
            if value == 0:
                continue

            axes[i].text(
                x_pos,
                y_pos,
                text,
                ha='center',
                color='k',
                weight='bold',
                size=font_size
            )

        axes[i].legend()

    # plt.tight_layout()
    plt.show()

def graph_run_times(ns: list, depths: list, samples: int):
    times = []
    X = []
    for n, depth in zip(ns, depths):
        t_start = time.time()
        for i in range(samples):
            b = BoardState(n)
            minmax_competition(b, P_MIN, depth, depth)
            del b
        t_end = time.time()
        times.append((t_end - t_start)/samples)
        X.append(f"{n}x{n}@d={depth}")

    plt.rcParams["figure.figsize"] = 7, 5
    plt.bar(X, times)
    plt.tick_params('x', labelrotation=45)
    plt.ylabel("Execution time (s)")
    plt.title(f"Average execution time of 1 full game with given parameters over {samples} samples")
    plt.show()


#!/usr/bin/env python3
# coding: utf8

# Author: Adrian van der Lek, 2015

'''
Send an email with attachments.
'''

# Adapted from:
# http://stackoverflow.com/a/3363254/5272432
# http://stackoverflow.com/questions/73781

import smtplib
from os.path import basename
from collections import namedtuple
from subprocess import Popen, PIPE
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import COMMASPACE, formatdate

ConnectionSet = namedtuple('ConnectionSet',
                           'address server port user pwd')

def send_mail(send_from, send_to, connection, **msg_contents):
    '''
    Send an email with attachments.
    '''
    if not isinstance(send_to, list):
        raise TypeError('Argument `send_to`: expected list, got %s' %
                        type(send_to))

    msg = compose_message(send_from, send_to, **msg_contents)

    if connection.server:
        # Use a remote SMTP server.
        send_with_smtplib(msg, send_from, send_to, connection)
    else:
        # Use Unix `sendmail`.
        send_with_ssmtp(msg)

def compose_message(send_from, send_to, subject='', text='', files=()):
    '''
    Generate a properly formatted MIME message.
    '''
    msg = MIMEMultipart()
    msg['From'] = send_from
    msg['To'] = COMMASPACE.join(send_to)
    msg['Date'] = formatdate(localtime=True)
    msg['Subject'] = subject

    msg.attach(MIMEText(text))

    for f in files or []:
        with open(f, "rb") as fil:
            msg.attach(MIMEApplication(
                fil.read(),
                Content_Disposition='attachment; filename="%s"' % basename(f),
                Name=basename(f)
            ))

    return msg.as_string()

def send_with_ssmtp(msg):
    '''
    Use Unix' sendmail/ssmtp command for sending.
    '''
    p = Popen(['sendmail', '-t', '-oi'], stdin=PIPE)
    p.communicate(msg.encode('utf8'))

def send_with_smtplib(msg, send_from, send_to, connection):
    '''
    Login to an SMTP server for sending.
    '''
    server = smtplib.SMTP(connection.server, connection.port)
    server.ehlo()
    server.starttls()
    server.login(connection.user, connection.pwd)
    server.sendmail(send_from, send_to, msg)
    server.close()


import sys
sys.path.insert(1, './')

from db_config import neo

def createNewUserNodeDAO(username):
    query = """
    MERGE (n:User{name:$username}) return n.name as name
    """
    formatter = {"username": username}
    neo.run(query, formatter)
    return

def isValidUsername(username):
    query = """
    MATCH (c:User{name:$curUser})
    return c
    """

    formatter = {"curUser": username}
    results = neo.run(query, formatter)

    # User exists if result is not null
    for result in results:
        if result:
            return True

    return False

def getUserFollowingsDAO(username):
    query = """
    MATCH (c:User{name:$username})-[r:FOLLOWS]->(f:User)
    return f.name as name
    """

    formatter = {"username": username}
    results = neo.run(query, formatter)

    following_names = []
    for result in results:
        following_names.append(result["name"])

    return following_names

def getUserFollowersDAO(username):
    query = """
    MATCH (c:User{name:$username})<-[r:FOLLOWS]-(f:User)
    return f.name as name
    """

    formatter = {"username": username}
    results = neo.run(query, formatter)

    follower_names = []
    for result in results:
        follower_names.append(result["name"])

    return follower_names

def getNonFollowedUsersDAO(username):
    query = """
    MATCH (current_user:User{name:$username}), (other_users:User)
    WHERE NOT (current_user)-[:FOLLOWS]->(other_users) and current_user<>other_users
    RETURN other_users.name as name
    """

    formatter = {"username": username}
    results = neo.run(query, formatter)

    nonfollowed_names = []
    for result in results:
        nonfollowed_names.append(result["name"])

    return nonfollowed_names

def followUserDAO(username, toFollowUsername):
    query = """
    MATCH (c:User{name:$username}), (f:User{name:$toFollowUsername})
    CREATE (c)-[r:FOLLOWS]->(f)
    """

    formatter = {"username": username, "toFollowUsername": toFollowUsername}
    neo.run(query, formatter)

def unfollowUserDAO(username, toUnfollowUsername):
    query = """
    MATCH (c:User{name:$username})-[r:FOLLOWS]->(f:User{name:$toUnfollowUsername})
    DELETE r
    """

    formatter = {"username": username, "toUnfollowUsername": toUnfollowUsername}
    neo.run(query, formatter)


# -*- coding: utf-8 -*-

# Run this app with `python app.py` and
# visit http://127.0.0.1:8050/ in your web browser.

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
from dash.dependencies import Output, Input
import dash_bootstrap_components as dbc

import json
import pandas as pd
import plotly.express as px
import numpy as np
import plotly.graph_objects as go
import math

from constants import Graph, edges, distance

from grapher import ret_fig

df = pd.read_csv('distances.csv')[['Name','lat','long','Number']]

px.set_mapbox_access_token('pk.eyJ1IjoiYW50b3JudmF5IiwiYSI6ImNrbmsyb3M3NDA3NGUycHM1bzg0MXBmeGwifQ.XDoxAtNYH_JlmZz0e7ZsnQ')
fig = px.scatter_mapbox(df, lat="lat", lon="long",mapbox_style="satellite", zoom=14, color_discrete_sequence=['red']*len(df), labels=None, hover_name='Name', hover_data={'lat':False, 'long':False}, )
fig.update_layout(showlegend=False)
fig.update_layout(
    autosize=True,
    height=800,)

g = Graph(len(df))
dijktime = 0
for i in edges:
    x = i[0]
    y = i[1]
    d = distance(df.iloc[x-1].lat,df.iloc[x-1].long, df.iloc[y-1].lat,df.iloc[y-1].long)
    g.graph[x-1][y-1] = d
    g.graph[y-1][x-1] = d

from flask import Flask

server = Flask(__name__)
app = dash.Dash(server=server,external_stylesheets=[dbc.themes.BOOTSTRAP])
imap = [
        html.H1(children="Dijkstra's X Insti", style={'margin-top':'2.5%', 'text-align':'center'}),
        dbc.Row([
        dbc.Col(md= 2),
        dbc.Col([
            dcc.Dropdown(
                id='crossfilter-start',
                options=[{'label': i[1].Name, 'value': i[1].Number} for i in df.iterrows()],
                value=1,
                placeholder='Select a start'

            ),
        ],
            md=3),
        dbc.Col(md= 2),
        dbc.Col([
            dcc.Dropdown(
                id='crossfilter-dest',
                options=[{'label': i[1].Name, 'value': i[1].Number} for i in df.iterrows()],
                value=None,
                placeholder='Select a destination'

            ),
        ],
            md=3),
        ]),
        dbc.Row([
            dbc.Col([
                dbc.Button("Go to Graph Generator", color="dark",href='/network', style={'margin-left':'50%'}),
            ],
            md=2),
            dbc.Col(
            dcc.Graph(
                id='crossfilter-insti',
                figure=fig,
                # layout=fig.layout,
            ), md=8),
        ],
            ),
    ]

grap = [
    html.H3('Random Geometric Graphs', style={'margin-top':'2.5%', 'text-align':'center'}),
    dcc.Dropdown(
        id='crossfilter-n',
        options=[{'label': i, 'value': i} for i in [5,10,25,50,100,200,300,500,1000]],
        value=50,
        placeholder='Select a destination',
        style={'width':'40%', 'margin-left':'30%'},
        ),
    html.Div(className='row',
    children=[
        html.Div([
            dbc.Button("Go to InstiMap", color="dark",href='/', style={'margin-left':'30%'}),
            html.Table([
                html.Tr([
                    html.Th('Algorithm'),
                    html.Th('Time Taken (ms)'),
                    html.Th('Relative'),
                ])
            ],style={'width':'100%', 'margin-left':'5%','margin-top':'15%'}, id='time-table')
        ], className='col-md-3'),
        html.Div([
            dcc.Graph(id='main-graph', figure=fig)
        ], className='col-md-9')
    ])
]

url_bar_and_content_div = html.Div([
    dcc.Location(id='url', refresh=False),
    html.Div(id='page-content', style={ 'background-color':'white', 'height':'100%'})
])

app.validation_layout = html.Div([
    url_bar_and_content_div,
    imap,
    grap])

app.layout = url_bar_and_content_div

@app.callback(
    Output('page-content', 'children'),
    [Input('url', 'pathname')])
def display_page(pathname):
    if pathname in ['/network/','/network']:
        return grap
    elif pathname == '/':
        return imap
    else:
        return imap

@app.callback(
    Output('main-graph', 'figure'),
    Output('time-table', 'children'),
    [Input('crossfilter-n', 'value')])
def display_fig(n):
    if n is None:
        return [go.Figure(data=[]),[]]
    figu, timeit = ret_fig(n)
    timeit = timeit[0][0]
    if figu is None:
        figu = go.Figure(data=[], layout=go.Layout(
            annotations=[ dict(
                    text="Figure not loaded to prevent overload",
                    showarrow=False,
                    xref="paper", yref="paper",
                    font_size=30,
                    x=0.5, y=0.5 ) ],
        ))
        l = [('Dijkstra\'s',timeit[0]),('A*',timeit[2])]
        l.sort(key=lambda x:x[1])
        lay = [
                html.Tr([
                    html.Th('Algorithm'),
                    html.Th('Time Taken (ms)'),
                    html.Th('Relative'),
                ]),
                html.Tr([
                    html.Th('{}'.format(l[0][0])),
                    html.Th('{}'.format(int(l[0][1]*100000)/100)),
                    html.Th('1x'),
                ]),
                html.Tr([
                    html.Th('{}'.format(l[1][0])),
                    html.Th('{}'.format(int(l[1][1]*100000)/100)),
                    html.Th('~{}x'.format(int(l[1][1]/l[0][1]))),
                ]),
                ]

        return [figu,lay]
    else:
        l = [('Dijkstra\'s',timeit[0]),('Bellman-Ford',timeit[1]),('A*',timeit[2])]
        l.sort(key=lambda x:x[1])
        lay = [
                html.Tr([
                    html.Th('Algorithm'),
                    html.Th('Time Taken (ms)'),
                    html.Th('Relative'),
                ]),
                html.Tr([
                    html.Th('{}'.format(l[0][0])),
                    html.Th('{}'.format(int(l[0][1]*100000)/100)),
                    html.Th('1x'),
                ]),
                html.Tr([
                    html.Th('{}'.format(l[1][0])),
                    html.Th('{}'.format(int(l[1][1]*100000)/100)),
                    html.Th('~{}x'.format(int(l[1][1]/l[0][1]))),
                ]),
                html.Tr([
                    html.Th('{}'.format(l[2][0])),
                    html.Th('{}'.format(int(l[2][1]*100000)/100)),
                    html.Th('~{}x'.format(int(l[2][1]/l[0][1]))),
                ]),
                ]
        return [figu,lay]

@app.callback(
    Output('crossfilter-insti', 'figure'),
    [Input('crossfilter-start', 'value'),
    Input('crossfilter-dest', 'value')])
def update_graph(start,destination):
    fig.data = [fig.data[0]]

    if start is None or destination is None:
        return fig

    start-=1
    destination-=1
    dist, prev, t_taken = g.dijkstra(start)
    # print(t_taken.microseconds/1000)
    path = [destination]
    src = start
    while True:
        dest = prev[path[-1]]
        if dest is None:
            break
        else:
            path.append(dest)
    path = [i+1 for i in path[::-1]]
    visible_edges = []
    for i in range(len(path)-1):
        try:
            visible_edges.append(edges.index([path[i],path[i+1]]))
        except:
            visible_edges.append(edges.index([path[i+1],path[i]]))

    for j in visible_edges:
        i = edges[j]
        x = i[0]
        y = i[1]

        fig.add_trace(go.Scattermapbox(
        mode = "lines",
        lon = [df.iloc[x-1].long, df.iloc[y-1].long],
        lat = [df.iloc[x-1].lat,df.iloc[y-1].lat],
        hoverinfo='skip',
        line={'color':'orange'}
        ))
    return fig

if __name__ == '__main__':
    app.run_server(host='0.0.0.0', debug=False)


# Basics Requirements
import pathlib
import os
import dash
from dash.dependencies import Input, Output, State, ClientsideFunction
import dash_core_components as dcc
import dash_html_components as html

# Dash Bootstrap Components
import dash_bootstrap_components as dbc

# Data
import json
from datetime import datetime as dt
from lib import stats

# Recall app
from app import app

####################################################################################
# Add the DS4A_Img
####################################################################################

simte_Img = html.Div(
    children=[
        html.Img(
            src=app.get_asset_url("logo-simte.png"),
            id="simt-image",
            style={"width": "85%"},
        )
    ], style={'textAlign': 'center'}
)

DS4A_Img = html.Div(
    children=[
        html.Img(
            src=app.get_asset_url("ds4a-img.svg"),
            id="ds4a-image",
        )
    ],
)

ISA_Img = html.Div(
    children=[
        html.Img(
            src=app.get_asset_url("ISA_logoblanco.png"),
            id="logo-image",
            style={"width": "85%"},
        )
    ], style={'textAlign': 'center'}
)

MINTIC_Img = html.Div(
    children=[
        html.Img(
            src=app.get_asset_url("logo-mintic.png"),
            id="logo-mintic",
            style={"width": "100%"},
        )
    ],style={'textAlign': 'center'}
)

##############################################################################
# Date Picker
##############################################################################

date_picker = dcc.DatePickerRange(
    id="date_picker",
    min_date_allowed=dt(2014, 1, 2),
    max_date_allowed=dt(2017, 12, 31),
    start_date=dt(2016, 1, 1).date(),
    end_date=dt(2017, 1, 1).date(),
)

#############################################################################
# Sidebar Layout
#############################################################################
sidebar = html.Div([
    # [
    #     DS4A_Img,  # Add the DS4A_Img located in the assets folder
    #     html.H4("Team 4",style={'textAlign': 'center'}),
        # html.Hr(),  # Add an horizontal line
        ####################################################
        # Place the rest of Layout here
        ####################################################
        simte_Img,
        html.Hr(),
        # dcc.Link(html.Button('back'), href='www.google.com'),
        dbc.Nav(
            [
                dbc.NavLink(
                        html.Span(
                            [html.I(className="fas fa-cloud", style={"margin-right": "0.5rem"}),
                             "Exploratory Analysis",
                            ],
                    ),
                    href="/exploratory",
                    id="page-1-link",
                    className='text-dark',
                ),
                dbc.NavLink(
                    html.Span(
                            [html.I(className="fa fa-tasks", style={"margin-right": "0.5rem"}),
                             "Outage prediction",
                            ],
                    ),
                    href="/model",
                    id="page-2-link",
                    className="text-dark",
                ),
                dbc.NavLink(
                   html.Span(
                            [html.I(className="fa fa-users", style={"margin-right": "15px"}),
                             "About us",
                            ],),
                    href="/about-us",
                    id="page-3-link",
                    className="text-dark",
                ),
            ],
            vertical=True,
            pills=True
        ),
        html.Hr(),
        ISA_Img,
        html.Hr(),
        DS4A_Img,
        MINTIC_Img,
    ],
    className="ds4a-sidebar",
)