'''
Using the data of obstacle instead of using the camera detection now
Using the position data of the sensors instead of a computed number
'''
import glob
import sys
import icp
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from obstacle_detect.Run import *
from PIL import Image

try:
    sys.path.append(glob.glob('../carla/dist/carla-*%d.%d-%s.egg' % (
        sys.version_info.major,
        sys.version_info.minor,
        'win-amd64' if os.name == 'nt' else 'linux-x86_64'))[0])
except IndexError:
    pass

# ==============================================================================
# -- imports -------------------------------------------------------------------
# ==============================================================================

import carla
from carla import ColorConverter as cc
import cv2
import nvector as nv
import weakref
import random

try:
    import pygame
    from pygame.locals import K_ESCAPE
    from pygame.locals import K_SPACE
    from pygame.locals import K_a
    from pygame.locals import K_d
    from pygame.locals import K_s
    from pygame.locals import K_w
    from pygame.locals import K_TAB
except ImportError:
    raise RuntimeError('cannot import pygame, make sure pygame package is installed')

try:
    import numpy as np
    # np.set_printoptions(threshold=sys.maxsize)
except ImportError:
    raise RuntimeError('cannot import numpy, make sure numpy package is installed')

VIEW_WIDTH = 1920 // 2
VIEW_HEIGHT = 540

# FOV (field of view): the extent of the observable world seen at any given moment.
VIEW_FOV = 90

BB_COLOR = (248, 64, 24)
saved = False

class ClientSideBoundingBox(object):

    @staticmethod
    def get_bounding_boxes(obstacles, camera):
        bounding_boxes = [ClientSideBoundingBox.get_bounding_box(obstacle, camera) for obstacle in obstacles]
        bounding_boxes = [bounding_box for bounding_box in bounding_boxes if all(bounding_box[:,2] > 0)]
        return bounding_boxes

    @staticmethod
    def draw_bounding_boxes(display,bounding_boxes):
        bounding_box_surface = pygame.Surface((VIEW_WIDTH, VIEW_HEIGHT))
        bounding_box_surface.set_colorkey((0,0,0))
        for bounding_box in bounding_boxes:
            points = [(int(bounding_box[i,0]), int(bounding_box[i,1])) for i in range(8)]
            # draw lines
            # base
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[0], points[1])
            # pygame.draw.line(bb_surface, BB_COLOR, points[0], points[1])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[1], points[2])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[2], points[3])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[3], points[0])
            # top
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[4], points[5])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[5], points[6])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[6], points[7])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[7], points[4])
            # base-top
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[0], points[4])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[1], points[5])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[2], points[6])
            pygame.draw.line(bounding_box_surface, BB_COLOR, points[3], points[7])
        display.blit(bounding_box_surface, (0, 0))

    @staticmethod
    def create_bounding_area_masks(bounding_boxes, depth_img):

        masks = []
        for bounding_box in bounding_boxes:
            mask = np.ones((VIEW_HEIGHT, VIEW_WIDTH), np.uint8)*255
            points = [(int(bounding_box[i, 0]),int(bounding_box[i, 1])) for i in range(8)]

            cv2.line(mask, points[0], points[1], 0, thickness=2)
            cv2.line(mask, points[1], points[2], 0, thickness=2)
            cv2.line(mask, points[2], points[3], 0, thickness=2)
            cv2.line(mask, points[3], points[0], 0, thickness=2)
            cv2.line(mask, points[4], points[5], 0, thickness=2)
            cv2.line(mask, points[5], points[6], 0, thickness=2)
            cv2.line(mask, points[6], points[7], 0, thickness=2)
            cv2.line(mask, points[7], points[4], 0, thickness=2)
            cv2.line(mask, points[0], points[4], 0, thickness=2)
            cv2.line(mask, points[1], points[5], 0, thickness=2)
            cv2.line(mask, points[2], points[6], 0, thickness=2)
            cv2.line(mask, points[3], points[7], 0, thickness=2)

            retval, labels = cv2.connectedComponents(mask)
            bg_label = labels[0, 0]
            mask = np.ones((VIEW_HEIGHT, VIEW_WIDTH), np.uint8)
            # print(np.shape(mask))
            mask[labels == bg_label] = 0
            '''
            min_dist = np.min(depth_img[mask != 0])
            for i in range(5, VIEW_HEIGHT-5):
                for j in range(5, VIEW_WIDTH-8):
                    if depth_img[i, j] == 50 and mask[i, j] != 0:
                        times = 0
                        diff = 0.5
                        for ii in range(i-4, i+4):
                            for jj in range(j-3, j+3):
                                if 0 < abs(depth_img[ii, jj]-min_dist) < diff:
                                    times += 1
                        if times < 2:
                            mask[i, j] = 0
                    if (mask[i, j] != 0) and (depth_img[i, j] < min_dist-0.5 or depth_img[i, j] > min_dist+0.5):
                        if depth_img[i, j] != 50:
                            mask[i, j] = 0
            '''
            masks += [mask]
            # print(bg_label)

        return masks

    @staticmethod
    def get_bounding_box(obstacle,camera):
        bounding_box_cords = ClientSideBoundingBox.create_bounding_box_points(obstacle)
        # vehicle reference
        cords_x_y_z = ClientSideBoundingBox.vehicle_to_camera(bounding_box_cords, obstacle, camera)[:3, :]
        # print(cords_x_y_z)
        cords_y_minus_z_x = np.concatenate([cords_x_y_z[1, :], -cords_x_y_z[2, :], cords_x_y_z[0, :]])
        # print(cords_y_minus_z_x)
        bounding_box = np.transpose(np.dot(camera.calibration, cords_y_minus_z_x))
        # camera image reference (u,v,z)

        camera_bounding_box = np.concatenate([bounding_box[:, 0] / bounding_box[:, 2], bounding_box[:, 1] / bounding_box[:, 2],
                                              bounding_box[:, 2]], axis=1)
        # print(camera_bounding_box)
        return camera_bounding_box

    @staticmethod
    def create_bounding_box_points(obstacle):
        cords = np.zeros((8, 4))
        extent = obstacle.bounding_box.extent
        cords[0, :] = np.array([extent.x, extent.y, -extent.z, 1])
        cords[1, :] = np.array([-extent.x, extent.y, -extent.z, 1])
        cords[2, :] = np.array([-extent.x, -extent.y, -extent.z, 1])
        cords[3, :] = np.array([extent.x, -extent.y, -extent.z, 1])
        cords[4, :] = np.array([extent.x, extent.y, extent.z, 1])
        cords[5, :] = np.array([-extent.x, extent.y, extent.z, 1])
        cords[6, :] = np.array([-extent.x, -extent.y, extent.z, 1])
        cords[7, :] = np.array([extent.x, -extent.y, extent.z, 1])
        return cords

    @staticmethod
    def get_matrix(transform):
        #from carla transform to matrix, the matrix contains the location and the rotation matrix
        rotation = transform.rotation
        location = transform.location
        cos_yaw = np.cos(np.radians(rotation.yaw))
        sin_yaw = np.sin(np.radians(rotation.yaw))
        cos_roll = np.cos(np.radians(rotation.roll))
        sin_roll = np.sin(np.radians(rotation.roll))
        cos_pitch = np.cos(np.radians(rotation.pitch))
        sin_pitch = np.sin(np.radians(rotation.pitch))
        matrix = np.matrix(np.identity(4))
        matrix[0, 3] = location.x
        matrix[1, 3] = location.y
        matrix[2, 3] = location.z
        matrix[0, 0] = cos_pitch*cos_yaw
        matrix[0, 1] = cos_yaw*sin_pitch*sin_roll-sin_yaw*cos_roll
        matrix[0, 2] = -cos_yaw*sin_pitch*cos_roll-sin_yaw*sin_roll
        matrix[1, 0] = sin_yaw*cos_pitch
        matrix[1, 1] = sin_yaw*sin_pitch*sin_roll+cos_yaw*cos_roll
        matrix[1, 2] = -sin_yaw*sin_pitch*cos_roll+cos_yaw*sin_roll
        matrix[2, 0] = sin_pitch
        matrix[2, 1] = -cos_pitch*sin_roll
        matrix[2, 2] = cos_pitch*cos_roll
        return matrix

    @staticmethod
    def vehicle_to_world(cords, obstacle):
        # boundingbox's coordinate in the obstacle's reference
        bounding_box_transform = carla.Transform(obstacle.bounding_box.location)
        bounding_box_obstacle_matrix = ClientSideBoundingBox.get_matrix(bounding_box_transform)

        # obstacle's coordinate in the world reference
        obstacle_world_matrix = ClientSideBoundingBox.get_matrix(obstacle.get_transform())
        bounding_box_world_matrix = np.dot(obstacle_world_matrix, bounding_box_obstacle_matrix)
        bounding_box_world_cords = np.dot(bounding_box_world_matrix, np.transpose(cords))
        return bounding_box_world_cords

    @staticmethod
    def world_to_camera(cords, camera):
        camera_world_matrix = ClientSideBoundingBox.get_matrix(camera.get_transform())
        world_camera_matrix = np.linalg.inv(camera_world_matrix)
        camera_cords = np.dot(world_camera_matrix, cords)
        return camera_cords

    @staticmethod
    def vehicle_to_camera(cords, obstacle, camera):

        world_cord = ClientSideBoundingBox.vehicle_to_world(cords, obstacle)
        camera_cord = ClientSideBoundingBox.world_to_camera(world_cord, camera)
        return camera_cord

    @staticmethod
    def camera1_to_camera2(cords_camera1, camera1, camera2, icp_T):
        """
        Transforms pedestrian coordinates from sensor1 to sensor2.
        """
        camera1_world_matrix = ClientSideBoundingBox.get_matrix(camera1.get_transform())
        # print(camera1_world_matrix)

        camera2_world_matrix = ClientSideBoundingBox.get_matrix(camera2.get_transform())
        # camera2_world_matrix[3, 0] += icp_T[3, 0]
        # camera2_world_matrix[3, 1] += icp_T[3, 1]
        # camera2_world_matrix[3, 2] += icp_T[3, 2]
        # print(camera2_world_matrix)
        world_camera2_matrix = np.linalg.inv(camera2_world_matrix)
        # print(world_camera2_matrix)
        cords_camera2 = world_camera2_matrix.dot(camera1_world_matrix.dot(cords_camera1))
        # print(cords_camera2)
        return cords_camera2

    @staticmethod
    def image1_to_camera(depth_img, masks, camera, dist):

        # Transform the image of sensor1 to the 3D coordinates about sensor1

        if depth_img is None:
            print("depth image broken")
        else:
            width = VIEW_WIDTH
            height = VIEW_HEIGHT
            matrix_camera = np.linalg.inv(camera.calibration)
            cords_x = np.fromfunction(lambda i, j: j*matrix_camera[0, 0]+i*matrix_camera[0, 1], (height, width), dtype=float)
            cords_y = np.fromfunction(lambda i, j: j*matrix_camera[1, 0]+i*matrix_camera[1, 1], (height, width), dtype=float)
            cords_z = np.fromfunction(lambda i, j: j*matrix_camera[2, 0]+i*matrix_camera[2, 1], (height, width), dtype=float)
            cords_all = []
            '''
            TO be fixed here: with overlapping region, how to determine the distance information
            '''
            for mask in masks:
                argmin_dist = np.argmin(depth_img)
                min_dist = np.min(depth_img[mask != 0])
                print(min_dist)
                dist += [min_dist + 0.5]
                # dist += [avg_dist]
                depth_img[mask != 0] = sys.maxunicode

                v0 = argmin_dist//width
                u0 = argmin_dist-v0*width

                x_y_z0 = np.dot(matrix_camera, np.array([u0, v0, 1]).transpose())

                cords = np.stack((cords_x, cords_y, cords_z), axis = -1)-u0*matrix_camera[:, 0]- v0*matrix_camera[:, 1]+x_y_z0

                k = x_y_z0.dot(matrix_camera[:, :2])
                x_y_z0_square = x_y_z0.dot(x_y_z0)
                denominator = np.fromfunction(lambda i,j: k[0]*(j-u0)+k[1]*(i-v0), (height, width), dtype=float)
                denominator += x_y_z0_square
                cords = np.stack((cords[:, :, 0]/denominator, cords[:, :, 1]/denominator, cords[:, :, 2]/denominator), axis=-1)*min_dist*np.sqrt(x_y_z0_square)
                cords_all += [cords]

            return  cords_all

    @staticmethod
    def get_2d_cords_sensor2(rgb_image, depth_img, masks, distances, camera1, camera2, icp_T):
        print(icp_T)
        if (rgb_image is not None) and (depth_img is not None):
            cords_y_minus_z_x_camera1_all = ClientSideBoundingBox.image1_to_camera(depth_img, masks, camera1, distances)
            view_uv_camera2_all = []
            for cords_y_minus_z_x_camera1 in cords_y_minus_z_x_camera1_all:
                cords_y_minus_z_x_camera1 = cords_y_minus_z_x_camera1.reshape(VIEW_HEIGHT*VIEW_WIDTH, 3).transpose()
                cords_camera1 = np.array([cords_y_minus_z_x_camera1[2, :], cords_y_minus_z_x_camera1[0, :],
                                          -cords_y_minus_z_x_camera1[1, :], np.ones(VIEW_HEIGHT*VIEW_WIDTH)])

                cords_camera2 = ClientSideBoundingBox.camera1_to_camera2(cords_camera1, camera1, camera2, icp_T)
                cords_y_minus_z_x_camera2 = np.concatenate([cords_camera2[1, :], -cords_camera2[2, :],
                                                            cords_camera2[0, :]])
                view_uv_camera2 = np.transpose(np.dot(camera2.calibration, cords_y_minus_z_x_camera2))

                view_uv_camera2 = np.concatenate([view_uv_camera2[:, 0]/view_uv_camera2[:, 2],
                                                  view_uv_camera2[:, 1]/view_uv_camera2[:, 2],
                                                  view_uv_camera2[:, 2]], axis=1)

                view_uv_camera2 = np.rint(view_uv_camera2).astype(int)
                view_uv_camera2 = np.array(view_uv_camera2).reshape(VIEW_HEIGHT, VIEW_WIDTH, 3)
                view_uv_camera2_all += [view_uv_camera2]

            return view_uv_camera2_all
        else:
            print("image not prepared")

class BasicSynchronousClient(object):
    """
    Basic implementation of a synchronous client.
    """

    def __init__(self):
        self.client = None
        self.world = None
        self.camera = None
        self.pedestrian = None
        self.pedestrian2 = None
        self.car_0 = None
        self.car_A = None
        self.car = None
        self.car_controlled = None

        self.display = None
        self.image1 = None
        self.image2 = None
        self.cloud1 = None
        self.cloud2 = None
        self.converted_image = None
        self.depth_image = None
        self.obstacle = None
        self.obstacle_distances = []
        self.view_uv_all = None
        self.pointA = None
        self.point = None
        self.ax = None
        self.ay = None

        self.mask = None
        self.capture_rgb1 = True
        self.capture_rgb2 = True
        self.capture_depth = True
        self.capture_lidar1 = True
        self.capture_lidar2 = True
        self.capture_gnss1 = True
        self.capture_gnss2 = True
        self.saved_file = False
        self.detect_obstacle = True

    def camera_blueprint(self):
        """
        Returns camera blueprint.
        """

        camera_bp = self.world.get_blueprint_library().find('sensor.camera.rgb')
        camera_bp.set_attribute('image_size_x', str(VIEW_WIDTH))
        camera_bp.set_attribute('image_size_y', str(VIEW_HEIGHT))
        camera_bp.set_attribute('fov', str(VIEW_FOV))
        return camera_bp

    def set_synchronous_mode(self, synchronous_mode):
        """
        Sets synchronous mode.
        """

        settings = self.world.get_settings()
        settings.synchronous_mode = synchronous_mode
        # settings.fixed_delta_seconds = 0.03
        self.world.apply_settings(settings)

    def setup_car_0(self):
        """
        Spawns a car in front of the controlled vehicle.
        """
        car_bp = self.world.get_blueprint_library().filter('vehicle.audi.*')[1]
        # print(car_bp)
        location = self.world.get_map().get_spawn_points()[2]
        location.location.x += 15
        location.location.y -= 0.8
        self.car_0 = self.world.spawn_actor(car_bp, location)

    def setup_pedestrian(self):
        """
        Spawns pedestrians in front of the first vehicle.
        """
        pedestrian_bp = self.world.get_blueprint_library().filter('walker.pedestrian.*')[2]
        location = self.world.get_map().get_spawn_points()[2]
        location.location.x += 15
        location.location.y += 0.8
        self.pedestrian = self.world.spawn_actor(pedestrian_bp, location)

    def setup_pedestrian_2(self):
        """
        Spawns pedestrians in front of the first vehicle.
        """
        pedestrian_bp = self.world.get_blueprint_library().filter('walker.pedestrian.*')[2]
        location = self.world.get_map().get_spawn_points()[2]
        location.location.x += 17
        location.location.y += 0.9
        self.pedestrian2 = self.world.spawn_actor(pedestrian_bp, location)

    def setup_car_A(self):
        """
        Spawns a car in front of the controlled vehicle.
        """
        car_bp = self.world.get_blueprint_library().filter('vehicle.*')[0]
        location = self.world.get_map().get_spawn_points()[3]
        location.location.x += 8
        location.location.y += 0.8
        self.car_A = self.world.spawn_actor(car_bp, location)

    def setup_car(self):
        """
        Spawns actor-vehicle to be controled.
        """

        car_bp = self.world.get_blueprint_library().filter('vehicle.*')[0]
        # location = random.choice(self.world.get_map().get_spawn_points())
        location = self.world.get_map().get_spawn_points()[3]
        location.location.y += 2.8
        self.car = self.world.spawn_actor(car_bp, location)

    def setup_camera(self):
        """
        Spawns actor-camera to be used to render view.
        Sets calibration for client-side boxes rendering.
        """

        # camera_transform = carla.Transform(carla.Location(x=-5.5, z=2.8), carla.Rotation(pitch=-15))
        camera_transform_A = carla.Transform(carla.Location(x=1.2, y=0, z=1.3), carla.Rotation(pitch=0))
        camera_transform = carla.Transform(carla.Location(x=0.2, y=-0.25, z=1.3), carla.Rotation(pitch=0))
        lidar_transform_A = carla.Transform(carla.Location(x=1.2, y=0, z=2.0), carla.Rotation(pitch=0))
        lidar_transform = carla.Transform(carla.Location(x=0.2, y=-0.25, z=2.0), carla.Rotation(pitch=0))
        self.camera = self.world.spawn_actor(self.camera_blueprint(), camera_transform, attach_to=self.car)
        self.camera_A_rgb = self.world.spawn_actor(self.camera_blueprint(), camera_transform_A, attach_to=self.car_A)

        camera_depth_bp = self.world.get_blueprint_library().find('sensor.camera.depth')
        camera_depth_bp.set_attribute('image_size_x', str(VIEW_WIDTH))
        camera_depth_bp.set_attribute('image_size_y', str(VIEW_HEIGHT))
        camera_depth_bp.set_attribute('fov', str(VIEW_FOV))
        self.camera_A_depth = self.world.spawn_actor(camera_depth_bp, camera_transform_A, attach_to=self.car_A)
        '''
        camera_depth_bp2 = self.world.get_blueprint_library().find('sensor.camera.depth')
        camera_depth_bp2.set_attribute('image_size_x', str(VIEW_WIDTH))
        camera_depth_bp2.set_attribute('image_size_y', str(VIEW_HEIGHT))
        camera_depth_bp2.set_attribute('fov', str(VIEW_FOV))
        self.camera_A_depth2 = self.world.spawn_actor(camera_depth_bp2, camera_transform, attach_to=self.car)
        '''
        lidar_bp1 = self.world.get_blueprint_library().find('sensor.lidar.ray_cast')
        lidar_bp1.set_attribute('range', '5000')
        lidar_bp1.set_attribute('channels', '128')
        lidar_bp1.set_attribute('rotation_frequency', '50')
        lidar_bp1.set_attribute('points_per_second', '1000000')
        self.lidar1 = self.world.spawn_actor(lidar_bp1, lidar_transform_A, attach_to = self.car_A)
        lidar_bp2 = self.world.get_blueprint_library().find('sensor.lidar.ray_cast')
        lidar_bp2.set_attribute('range', '5000')
        lidar_bp2.set_attribute('channels', '128')
        lidar_bp2.set_attribute('rotation_frequency', '50')
        lidar_bp2.set_attribute('points_per_second', '5000')
        self.lidar2 = self.world.spawn_actor(lidar_bp2, lidar_transform, attach_to = self.car)

        gnss_bp1 = self.world.get_blueprint_library().find('sensor.other.gnss')
        self.gnss1 = self.world.spawn_actor(gnss_bp1, camera_transform_A, attach_to = self.car_A)
        gnss_bp2 = self.world.get_blueprint_library().find('sensor.other.gnss')
        self.gnss2 = self.world.spawn_actor(gnss_bp2, camera_transform, attach_to = self.car)

        weak_self = weakref.ref(self)
        self.camera_A_rgb.listen(lambda image: self.set_rgb_image1(weak_self, image))
        # self.camera_A_depth.listen(lambda image: self.set_depth_image(weak_self, image))
        # self.camera_A_depth2.listen(lambda image: self.set_depth_image2(weak_self, image))
        self.camera.listen(lambda image: self.set_rgb_image2(weak_self, image))
        self.lidar1.listen(lambda cloud: self.set_lidar1(weak_self, cloud))
        self.lidar2.listen(lambda cloud: self.set_lidar2(weak_self, cloud))
        self.gnss1.listen(lambda gnss: self.set_gnss1(weak_self, gnss))
        self.gnss2.listen(lambda gnss: self.set_gnss2(weak_self, gnss))

        calibration = np.identity(3)
        # calibration[0, 0] = 5
        calibration[0, 2] = VIEW_WIDTH / 2.0
        calibration[1, 2] = VIEW_HEIGHT / 2.0
        calibration[0, 0] = calibration[1, 1] = VIEW_WIDTH / (2.0 * np.tan(VIEW_FOV * np.pi / 360.0))
        print("calibration = ")
        print(calibration)
        self.camera.calibration = calibration
        self.camera_A_rgb.calibration = calibration

    def control(self):
        """
        Applies control to main car based on pygame pressed keys.
        Will return True If ESCAPE is hit, otherwise False to end main loop.
        """
        # car = self.car_controlled
        keys = pygame.key.get_pressed()
        if keys[K_ESCAPE]:
            return True
        if keys[K_TAB]:
            self.car_controlled = self.car_A if self.car_controlled == self.car else self.car

        control = self.car_controlled.get_control()
        control.throttle = 0

        if keys[K_w]:
            control.throttle = 1
            control.reverse = False
        elif keys[K_s]:
            control.throttle = 1
            control.reverse = True
        if keys[K_a]:
            control.steer = max(-1., min(control.steer - 0.05, 0))
        elif keys[K_d]:
            control.steer = min(1., max(control.steer + 0.05, 0))
        else:
            control.steer = 0
        control.hand_brake = keys[K_SPACE]

        self.car_controlled.apply_control(control)
        return False

    @staticmethod
    def set_rgb_image1(weak_self, img):
        """
        Sets image coming from camera sensor.
        The self.capture flag is a mean of synchronization - once the flag is
        set, next coming image will be stored.
        """

        self = weak_self()
        if self.capture_rgb1:
            self.image1 = img
            save_name = "./obstacle_detect/eval/image/000000.jpeg"
            cc = carla.ColorConverter.Raw
            # self.image1 = image.
            img.save_to_disk(save_name, cc)
            self.capture_rgb1 = False

    @staticmethod
    def set_rgb_image2(weak_self, img):
        """
        Sets image coming from camera sensor.
        The self.capture flag is a mean of synchronization - once the flag is
        set, next coming image will be stored.
        """

        self = weak_self()
        if self.capture_rgb2:
            self.image2 = img
            self.capture_rgb2 = False

    @staticmethod
    def set_depth_image(weak_self, depth_img):
        """
        Sets depth image coming from depth camera sensor.
        The self.capture_depth flag is a mean of synchronization - once the flag is
        set, next coming image will be stored.
        """

        self = weak_self()
        cc = carla.ColorConverter.Depth
        depth_img.save_to_disk('depth_img/00.png', cc)
        if self.capture_depth:
            distance = np.frombuffer(depth_img.raw_data, dtype=np.dtype("uint8"))
            distance = np.reshape(distance, (depth_img.height, depth_img.width, 4))
            distance = distance[:, :, :3]
            distance = distance.astype("uint32")
            distance = (distance[:, :, 2] + distance[:, :, 1] * 256 + distance[:, :, 0] * 256 * 256) / (
                        256 * 256 * 256 - 1) * 1000
            np.sum(self.mask, axis=0)
            distance[np.sum(self.mask, axis=0) == 0] = sys.maxunicode
            self.depth_image = distance
            # print('shape: ', np.shape(distance))
            self.capture_depth = False

        # plt.figure("depth")
        # plt.imshow(self.depth_image)

    @staticmethod
    def set_depth_image2(weak_self, depth_img):
        """
        Sets depth image coming from depth camera sensor of the back car.
        The self.capture_depth flag is a mean of synchronization - once the flag is
        set, next coming image will be stored.
        """

        self = weak_self()
        cc = carla.ColorConverter.Depth
        depth_img.save_to_disk('depth_img/01.png', cc)
        if self.capture_depth2:
            self.capture_depth2 = False

    @staticmethod
    def set_lidar1(weak_self, cloud):
        self = weak_self()
        cloud.save_to_disk('_out/1%06d' % cloud.frame)
        if self.capture_lidar1:
            self.capture_lidar1 = False
            num_point = 0
            for location in cloud:
                num_point += 1
            self.cloud1 = np.zeros((num_point, 3))
            i = 0
            for location in cloud:
                self.cloud1[i, 0] = location.x
                self.cloud1[i, 1] = -location.y
                self.cloud1[i, 2] = -location.z + 0.7
                i += 1
            cloud_y_minus_z_x = np.zeros((num_point, 3))
            cloud_y_minus_z_x[:, 2] = self.cloud1[:, 1]
            cloud_y_minus_z_x[:, 1] = -self.cloud1[:, 2]
            cloud_y_minus_z_x[:, 0] = self.cloud1[:, 0]
            # print('shape2: ', np.shape(cloud_y_minus_z_x))
            distance = np.ones((VIEW_HEIGHT, VIEW_WIDTH))
            distance = distance * 50
            calibration = self.camera_A_rgb.calibration
            for point in cloud_y_minus_z_x:
                position = np.dot(calibration, point)
                position[0] = position[0]/position[2]
                position[1] = position[1]/position[2]
                # print(position)
                u = int(position[0])
                v = int(position[1])
                if (2 < position[2] < 50) and (0 <= v < VIEW_HEIGHT) and (0 <= u < VIEW_WIDTH) and (position[2] < distance[v, u]):
                    # if distance[int(v), int(u)] == 50 or distance[int(v), int(u)] < position[2]:
                    distance[v, u] = position[2]
            self.depth_image = distance
            # distance = distance * 25
            # distance = np.shape(vector, (VIEW_HEIGHT, VIEW_WIDTH))
            new_im = Image.fromarray(np.uint8(distance))
            # plt.imsave('depth_img/1.jpeg', new_im, cmap='gray')

    @staticmethod
    def set_lidar2(weak_self, cloud):
        self = weak_self()
        cloud.save_to_disk('_out/2%06d' % cloud.frame)
        if self.capture_lidar2:
            self.capture_lidar2 = False
            num_point = 0
            for location in cloud:
                num_point += 1
            # print(num_point)
            self.cloud2 = np.zeros((num_point, 3))
            i = 0
            for location in cloud:
                self.cloud2[i, 0] = location.x
                self.cloud2[i, 1] = -location.y
                self.cloud2[i, 2] = -location.z+0.7
                i += 1

    @staticmethod
    def set_gnss1(weak_self, gnss):
        self = weak_self()
        if self.capture_gnss1:
            # print(gnss)
            wgs84 = nv.FrameE(name='WGS84')
            point = wgs84.GeoPoint(gnss.latitude, gnss.longitude, gnss.altitude, degrees=True)
            # print(point)
            self.pointA = point
            self.capture_gnss1 = False

    @staticmethod
    def set_gnss2(weak_self, gnss):
        self = weak_self()
        if self.capture_gnss2:
            # print(gnss)
            wgs84 = nv.FrameE(name='WGS84')
            point = wgs84.GeoPoint(gnss.latitude, gnss.longitude, gnss.altitude, degrees=True)
            # print(point)
            self.point = point
            self.capture_gnss2 = False

    def render(self, display):
        """
        Transforms image from camera sensor and blits it to main pygame display.
        """

        if self.image2 is not None and self.image1 is not None:
            array1 = np.frombuffer(self.image1.raw_data, dtype=np.dtype("uint8"))
            array1 = np.reshape(array1, (self.image1.height, self.image1.width, 4))
            array1 = array1[:, :, :3]
            array1 = array1[:, :, ::-1].copy()

            array2 = np.frombuffer(self.image2.raw_data, dtype=np.dtype("uint8"))
            array2 = np.reshape(array2, (self.image2.height, self.image2.width, 4))
            array2 = array2[:, :, :3]
            array2 = array2[:, :, ::-1].copy()

            # print(array2)
            if self.view_uv_all is not None and self.mask is not None:
                indices = np.argsort(self.obstacle_distances)[::-1]
                for i in indices:
                    mask = self.mask[i]
                    valide_indices = np.nonzero(mask)
                    uv_couples = self.view_uv_all[i][valide_indices]
                    # print(np.shape(valide_indices))
                    array2[uv_couples[:, 1], uv_couples[:, 0]] = array1[valide_indices]
                    # array1[valide_indices] = [0, 0, 0]
                    # array2[valide_indices] = array1[valide_indices]

            array = np.concatenate((array1, array2), axis=1)
            surface = pygame.surfarray.make_surface(array.swapaxes(0, 1))
            display.blit(surface, (0, 0))
        else:
            print("render not ok")

    def game_loop(self):
        """
        Main program loop.
        """

        saved = False
        # load weights

        weights_path = os.path.abspath(os.path.dirname(__file__)) + '/obstacle_detect/weights'
        model_lst = [x for x in sorted(os.listdir(weights_path)) if x.endswith('.pkl')]
        if len(model_lst) == 0:
            print('No previous model found, please train first!')
            exit()
        else:
            print('Using previous model %s' % model_lst[-1])
            # TODO: load bins from file or something
            dir_weights = weights_path + '/%s' % model_lst[-1]
            fp = open(dir_weights, "rb")
            weights = torch.load(fp)

        # load yolo
        yolo_path = os.path.abspath(os.path.dirname(__file__)) + '/obstacle_detect/weights'
        yolo = cv_Yolo(yolo_path)

        try:
            pygame.init()

            self.client = carla.Client('127.0.0.1', 2000)
            self.client.set_timeout(2.0)
            self.world = self.client.get_world()

            # self.setup_pedestrian()
            # self.setup_pedestrian_2()
            self.setup_car_0()
            self.setup_car_A()
            self.setup_car()
            self.setup_camera()

            self.car_controlled = self.car

            self.display = pygame.display.set_mode((VIEW_WIDTH * 2, VIEW_HEIGHT), pygame.HWSURFACE | pygame.DOUBLEBUF)
            pygame_clock = pygame.time.Clock()

            settings = self.world.get_settings()
            settings.fixed_delta_seconds = 0.1
            settings.synchronous_mode = True
            self.world.apply_settings(settings)
            self.car.set_autopilot(True)
            # vehicles = [vehicle for vehicle in self.world.get_actors().filter('vehicle.*')]
            # pedestrians = [pedestrian for pedestrian in self.world.get_actors().filter('walker.pedestrian.*')]

            # print(obstacles)

            while True:
                time = self.world.tick()

                '''
                figure1 = plt.figure()
                ax1 = Axes3D(figure1)
                ax1.scatter3D(self.cloud1[:, 0], self.cloud1[:, 1], self.cloud1[:, 2])
                plt.show()

                figure2 = plt.figure()
                ax2 = Axes3D(figure2)
                ax2.scatter3D(self.cloud2[:, 0], self.cloud2[:, 1], self.cloud2[:, 2])
                plt.show()
                time.sleep(5)
                print(np.shape(self.cloud1))
                print(np.shape(self.cloud2))

                plt.figure()
                plt.scatter(self.ay, self.ax)
                plt.show()
                time.sleep(5)
                '''
                self.obstacle_distances = []
                x1 = self.car_A.get_location().x
                x2 = self.car.get_location().x
                # print(x1, x2)
                bounding_boxes = detect(weights, yolo)
                # print(np.shape(bounding_boxes))
                if abs(x1 - x2) > 2:
                    T, R, i = icp.icp(self.cloud1, self.cloud2, max_iterations=1000, tolerance=0.001)

                    self.mask = ClientSideBoundingBox.create_bounding_area_masks(bounding_boxes, self.depth_image)

                    self.view_uv_all = ClientSideBoundingBox.get_2d_cords_sensor2(self.camera_A_rgb, self.depth_image,
                                                                                self.mask, self.obstacle_distances,
                                                                                self.camera_A_rgb, self.camera, T)

                self.render(self.display)

                ClientSideBoundingBox.draw_bounding_boxes(self.display, bounding_boxes)

                pygame.image.save(self.display, "screenshot/screenshot_" + str(time) + ".jpeg")
                pygame.display.flip()

                pygame.event.pump()
                self.capture_rgb1 = True
                self.capture_rgb2 = True
                self.capture_depth = True
                self.capture_depth2 = True
                self.detect_obstacle = True
                self.capture_lidar1 = True
                self.capture_lidar2 = True
                self.capture_gnss1 = True
                self.capture_gnss2 = True
                if self.control():
                    return

        finally:
            self.set_synchronous_mode(False)
            self.client.stop_recorder()
            self.camera.destroy()
            self.camera_A_depth.destroy()
            self.camera_A_rgb.destroy()
            self.car.destroy()
            self.car_A.destroy()
            self.pedestrian.destroy()
            # self.car_0.destroy()
            pygame.quit()

    def print_to_txt(self, data):
        if ~self.saved_file and (data is not None):
            np.savetxt('data.txt', data, fmt="%.3f")
            saved = True

def main():
    """
    Initializes the client-side bounding box demo.
    """

    try:
        client = BasicSynchronousClient()
        client.game_loop()
    finally:
        print('EXIT')

if __name__ == '__main__':
    main()


from datetime import datetime, timedelta
from random import randint, choice

import re

from pytz import timezone, utc

from twisted.python import log
from twisted.words.protocols import irc
from twisted.internet import protocol, reactor
from twisted.internet.task import LoopingCall

import configuration
from ladder import LadderParser
from leader import LeaderParser
from twitch import TwitchParser
from twitter import TwitterParser
from tourney import TourneyParser
from patch import PatchParser
from misc import MiscParser

class TownCrierScheduler(object):
    def __init__(self, event=datetime.utcnow()):
        """Initialize the announcement scheduler for an event."""
        if not isinstance(event, datetime):
            raise TypeError("event is not a datetime.datetime ojbect")

        self._event = event
        self._timer = None

    @property
    def event(self):
        return self._event

    @event.setter
    def event(self, new_event):
        if not isinstance(new_event, datetime):
            raise TypeError("new_event is not a datetime.datetime object")
        self._event = new_event

    @property
    def timer(self):
        return self._timer

    @timer.setter
    def timer(self, new_timer):
        self._timer = new_timer

    def __iter__(self):
        return self

    def next(self):
        """
        Return the seconds until next update is due for datetime specified.
        Delay is calculated in following increments:
            > 1d | 24h
            >12h |  4h
            > 6h |  2h
            > 3h |  1h
            > 1h | 30m
            > 0h | 15m
            else | raise StopIterator
        """

        now = datetime.utcnow()
        if now >= self._event:
            raise StopIteration

        countdown = self._event - now
        if countdown.days:
            next_update = self._event - timedelta(countdown.days)
        elif countdown.seconds > 43200:  # 12h
            # round to multiples of 4 hours
            next_update_seconds = (countdown.seconds // 14400) * 14400
            next_update = self._event - timedelta(0, next_update_seconds)
        elif countdown.seconds > 21600:  # 6h
            # round to multiples of 2 hours
            next_update_seconds = (countdown.seconds // 7200) * 7200
            next_update = self._event - timedelta(0, next_update_seconds)
        elif countdown.seconds > 10800:  # 3h
            # round to full hours
            next_update_seconds = (countdown.seconds // 3600) * 3600
            next_update = self._event - timedelta(0, next_update_seconds)
        elif countdown.seconds > 3600:  # 1h
            # round to full 30m
            next_update_seconds = (countdown.seconds // 1800) * 1800
            next_update = self._event - timedelta(0, next_update_seconds)
        else:
            # round to full 15m
            next_update_seconds = (countdown.seconds // 900) * 900
            next_update = self._event - timedelta(0, next_update_seconds)

        return (next_update - now).total_seconds()

class CommanderBot(irc.IRCClient):
    """
    The Commander IRC bot.

    It authenticates with NickServ, joins channels and listens for commands.
    """

    # timestamp for flood prevention
    lastcmd = datetime.utcnow()
    started = datetime.utcnow()
    twitch = TwitchParser()
    ladder = LadderParser()
    leader = LeaderParser()
    tweets = TwitterParser()
    tourney = TourneyParser()
    patch = PatchParser()
    misc = MiscParser()
    last_patches = None
    towncrier = TownCrierScheduler()

    def sendLine(self, line):
        """Encode all lines as utf-8. Is this a good idea?"""
        if isinstance(line, unicode):
            line = line.encode("utf-8")
        irc.IRCClient.sendLine(self, line)

    def connectionMade(self):
        """
        Upon successful connection establishment, we set up our nickname, real
        name and message rate.
        """
        self.nickname = self.factory.nickname
        self.realname = self.factory.realname
        self.lineRate = self.factory.linerate
        irc.IRCClient.connectionMade(self)

    def signedOn(self):
        """
        Authenticate with NickServ and join the configured channels as soon as
        the welcome message is received.
        """
        irc.IRCClient.signedOn(self)
        log.msg("Connection established successfully.")

        if self.factory.nickserv:
            log.msg("Authenticating with NickServ.")
            self.msg("NickServ", "IDENTIFY {0}".format(self.factory.nickserv))

        log.msg("Joining channels {0}.".format(self.factory.channels))
        for channel in self.factory.channels:
            self.join(channel)

        log.msg("Starting event checker.")
        LoopingCall(self.check_events).start(120, True)

    def privmsg(self, user, channel, msg):
        """Handle messages to either the bot itself or the channel it is in."""
        irc.IRCClient.privmsg(self, user, channel, msg)
        # ignore everything that's not a command
        if not msg.startswith(self.factory.prefix):
            return

        nick = user.split("!")[0]
        # is this a query? if so, send messages to nick instead
        if channel == self.nickname:
            channel = nick

        now = datetime.utcnow()
        if (now - self.lastcmd).seconds < self.factory.cmdlimit:
            self.notice(nick, "Sorry, I only answer requests every "
                              "\x02{0}\x02 seconds.".format(
                                  self.factory.cmdlimit))
            return
        self.lastcmd = now

        # this might be a bad idea but we assume all data to be utf-8
        msg = msg.decode("utf-8")
        log.msg(u"Received {0} from {1} on {2}.".format(
            msg.encode("ascii", "xmlcharrefreplace"), nick, channel))

        # command is always separated by a space
        parts = msg.split(" ", 1)
        cmd = parts[0]
        args = parts[1].strip() if len(parts) == 2 else None

        # check if we can handle that command
        cmd_name = "handle_command_{0}".format(cmd[1:])
        handle_command = getattr(self, cmd_name, None)
        if handle_command and callable(handle_command):
            handle_command(channel, nick, args)

    def handle_command_help(self, channel, nick, args):
        """
        Handle !help command.
        Print a list of supported commands.
        """
        commands = ("!ladder [activity]", "!stats <user>", "!rank <user>",
                    "!forecast <user1> <user2>", "!ratio <user1> <user2>",
                    "!suggest <user>",
                    "!top [uber|platinum|gold|silver|bronze]",
                    "!twitch", "!uptime",
                    "!twitter [3|5]",
                    "!tourney [next|last]",
                    "!patch", "!news",
                    "!exodus",
                    "!now", "!roll [[<n>]d<n>]")

        self.msg(channel, u"Available commands: "
                          u"{0}".format(", ".join(commands)))
        self.notice(nick, u"Want more? Ask \x02Pyrus\x02 to add it!")

    def handle_command_exodus(self, channel, nick, args):
        """
        Handle !exodus command.
        Print information on their website.
        """
        self.msg(channel, u"\x02eXodus eSports\x02. "
                          u"Visit http://exodusesports.com/")

    def handle_command_uptime(self, channel, nick, args):
        """
        Handle !uptime command.
        Print the time since bot was started.
        """
        self.msg(channel, u"I've been alive for {0}".format(
            datetime.utcnow() - self.started))

    def handle_command_ladder(self, channel, nick, args):
        """
        Handler !ladder command.
        It always shows the top N players. The optional argument can be used to
        filter by activity. It defaults to active players in the last 28 days.
        Trigger an update on self.ladder an print topN.
        """
        activity = int(args) if args and args.isdigit() else 28
        self.ladder.top(activity).addCallback(self.tell_ladder, channel)

    def handle_command_stats(self, channel, nick, args):
        """
        Handle !stats command.
        It expects (part of) a username in args.
        Trigger an update on self.adder and print stats for player.
        """
        if not args:
            self.notice(nick, "You need to include a player name.")
            return

        userstats = args
        self.ladder.stats(userstats).addCallback(self.tell_stats,
                                                 channel, userstats)

    def handle_command_rank(self, channel, nick, args):
        """
        Handle !rank command.
        It expects (part of) a username in args.
        Trigger an update on self.adder and print player's rank.
        """
        if not args:
            self.notice(nick, "You need to include a player name.")
            return

        userrank = args
        self.ladder.rank(userrank).addCallback(self.tell_rank,
                                               channel, userrank)

    def handle_command_forecast(self, channel, nick, args):
        """
        Handle !forecast command.
        It expects (parts of) two usernames in args.
        Trigger an update on self.ladder and print match quality.
        """
        if not args:
            self.notice(nick, "You need to specify exactly two players.")
            return

        users = args.split(" ", 1)
        if len(users) != 2:
            self.notice(nick, "You need to specify exactly two players.")
            return

        self.ladder.forecast(users[0], users[1]).addCallback(
            self.tell_forecast, channel, users[0], users[1])

    def handle_command_ratio(self, channel, nick, args):
        """
        Handle !ratio command.
        It expects (parts of) two usernames in args.
        Trigger an update on self.ladder and print match ratio.
        """
        if not args:
            self.notice(nick, "You need to specify exactly two players.")
            return

        users = args.split(" ", 1)
        if len(users) != 2:
            self.notice(nick, "You need to specify exactly two players.")
            return

        self.ladder.ratio(users[0], users[1]).addCallback(
            self.tell_ratio, channel, users[0], users[1])

    def handle_command_suggest(self, channel, nick, args):
        """
        Handle !suggest command.
        It expects (part of) a username in args.
        Trigger an update on self.ladder and print opponents for player.
        """
        if not args:
            self.notice(nick, "You need to include a player name.")
            return

        usersuggest = args

        self.ladder.suggest(usersuggest, 5).addCallback(
            self.tell_suggestion, channel, usersuggest)

    def handle_command_top(self, channel, nick, args):
        """
        Handle !top command.
        It expects a league in args. Valid values are "uber", "platinum",
        "gold", "silver", "bronze".
        Trigger an update on self.leader and print top 10.
        """
        league = "uber"
        initial_dict = {e[0]: e for e in
                        ("uber", "platinum", "gold", "silver", "bronze")}
        if args and args[0] in initial_dict:
            league = initial_dict[args[0]]

        self.leader.top(league).addCallback(self.tell_top, channel, league)

    def handle_command_twitch(self, channel, nick, args):
        """
        Handle !twitch command.
        Trigger an update on self.twitch and print current streams.
        """
        self.twitch.live().addCallback(self.tell_streams, channel)

    def handle_command_twitter(self, channel, nick, args):
        """
        Handler !twitter command.
        It expects the number of tweets to print in args (defaults to 1).
        Trigger an update on self.twitter and print up to N tweets.
        """
        n = int(args) if args and args in ("3", "5", "10") else 1
        self.tweets.latest(n).addCallback(self.tell_tweets, channel)

    def handle_command_tourney(self, channel, nick, args):
        """
        Handle !tourney command.
        It expects either "next" or "last" in args (defaults to "next").
        Trigger an update on self.tourney and print next/last tournament.
        """
        if (not args or args == "next" or args not in ("next", "last")):
            self.tourney.next().addCallback(self.tell_tourney,
                                            "next", channel)
        else:
            self.tourney.last().addCallback(self.tell_tourney,
                                            "last", channel)

    def handle_command_patch(self, channel, nick, args):
        """
        Handle !patch command.
        It doesn't take any arguments.
        Trigger an update on self.patch and print stable/PTE build ID.
        """
        self.patch.patches().addCallback(self.tell_patch, channel)

    def handle_command_news(self, channel, nick, args):
        """
        Handle !news command.
        It doesn't take any arguments.
        Trigger an update on self.misc and print most recent news item.
        """
        self.misc.news(1).addCallback(self.tell_news, channel)

    def handle_command_now(self, channel, nick, args):
        """
        Handle !now command.
        Print current UTC (and US/Pacific) time and date.
        """
        if 0 == randint(0, 999):
            self.msg(channel, u"It is time to dance!")
            self.describe(channel, "dances.")
            return

        now = datetime.utcnow().replace(microsecond=0, tzinfo=utc)
        ubernow = now.astimezone(timezone("US/Pacific"))

        self.msg(channel, u"It is now \x02{0}\x02 (UTC) / "
                          u"\x02{1}\x02 (Ubertime)".format(
                              now.isoformat(" "), ubernow.isoformat(" ")))

    def handle_command_roll(self, channel, nick, args):
        """
        Handle !roll command.
        Print the result of dice rolls.
        """
        dice_pattern = r"(?P<count>\d+)?d(?P<sides>\d+)"
        dice_result = re.match(dice_pattern, args) if args else None
        dice_dict = dice_result.groupdict() if dice_result else dict()

        # by default we toss a coin
        count = int(dice_dict["count"]) if dice_dict.get("count") else 1
        sides = int(dice_dict["sides"]) if dice_dict.get("sides") else 2

        # nothing to do
        if count < 1:
            return

        if count > 10:
            self.describe(channel, "only has 10.")
            count = 1

        if sides is 0:
            self.describe(channel, "slowly backs away from the singularity.")
        elif sides is 1:
            self.msg(channel, u"Rolling {0}... got \x02{1}\x02. Duh.".format(
                "a marble" if count == 1 else "some marbles", count))
        elif sides is 2:
            coins = (choice(("Heads", "Tails")) for _ in range(count))
            coins_bold = map(lambda coin: "\x02{0}\x02".format(coin), coins)
            numerus = "a coin" if count == 1 else "{0} coins".format(count)
            self.msg(channel, u"Tossing {0}... got {1}.".format(
                numerus, ", ".join(coins_bold)))
        elif sides > 100:
            self.describe(channel, "doesn't have one of those.")
        else:
            rolls = [randint(1, sides) for _ in range(count)]
            total = sum(rolls)
            rolls_bold = map(lambda roll: "\x02{0}\x02".format(roll), rolls)
            numerus = ("a d{0}".format(sides) if count == 1 else
                       "{0} d{1}s".format(count, sides))
            self.msg(channel, u"Rolling {0}... got {1}{2}.".format(
                numerus, ", ".join(rolls_bold),
                " => {0}".format(total) if count > 1 else ""))

    def tell_ladder(self, top, channel):
        """Write top n uberskill players to channel."""
        top_n_str = (u"\x02{0}\x02. {1}".format(x + 1, top[x])
                     for x in range(0, len(top)))

        self.msg(channel, u"1on1 Ladder Top \x02{0}\x02: {1}".format(
                          len(top), ", ".join(top_n_str)))

    def tell_stats(self, stats, channel, user):
        """Write win/loss statistic for a specific user to channel."""
        if not stats:
            self.msg(channel, u"1on1 Ladder Stats: "
                              u"Cannot acquire stats for "
                              u"\x02{0}\x02.".format(user))
            return

        name, won, drawn, lost, url = stats
        self.msg(channel, u"1on1 Ladder Stats: "
                          u"\x02{0}\x02 has "
                          u"\x02{1}\x02 wins, "
                          u"\x02{2}\x02 losses and "
                          u"\x02{3}\x02 draws. "
                          u"PA Stats: {4}".format(name,
                                                  won,
                                                  lost,
                                                  drawn,
                                                  url))

    def tell_rank(self, result, channel, user):
        """Write total number of players and the rank of a user to channel."""
        if not result:
            self.msg(channel, u"1on1 Ladder Ranking: "
                              u"\x02{0}\x02 is not ranked.".format(user))
            return

        name, rank, total = result
        if not rank:
            self.msg(channel, u"1on1 Ladder Ranking: "
                              u"\x02{0}\x02 currently is not ranked due to "
                              u"lack of activity.".format(name))
        else:
            self.msg(channel, u"1on1 Ladder Ranking: "
                              u"\x02{0}\x02 is ranked "
                              u"\x02{1}.\x02 out of \x02{2}\x02.".format(
                                  name, rank, total))

    def tell_forecast(self, forecast, channel, user1, user2):
        """Write likely match outcome between to players to channel."""
        if not forecast:
            self.msg(channel, u"1on1 Ladder Forecast: "
                              u"Cannot estimate outcome "
                              u"of \x02{0}\x02 vs \x02{1}\x02.".format(user1,
                                                                       user2))
            return

        name1, name2, draw, score1, score2 = forecast
        # highlight the player most likely to win
        if score1 > score2:
            name1 = "\x02" + name1 + "\x02"
        elif score2 > score1:
            name2 = "\x02" + name2 + "\x02"

        fuzzy = ("Evenly Matched" if draw >= 0.8 else
                 "Skewed Odds" if draw >= 0.5 else
                 "Utter Annihilation")

        self.msg(channel, u"1on1 Ladder Forecast: "
                          u"Match quality for {0} vs {1} is "
                          u"\x02{2:.2%}\x02: \x02{3}\x02.".format(name1,
                                                                  name2,
                                                                  draw,
                                                                  fuzzy))

    def tell_ratio(self, ratio, channel, user1, user2):
        """Write likely match outcome between to players to channel."""
        if not ratio:
            self.msg(channel, u"1on1 Ladder Match Ratio: "
                              u"Cannot determine match ratio between "
                              u"\x02{0}\x02 and \x02{1}\x02.".format(user1,
                                                                     user2))
            return

        name1, name2, nof_games, wins1, wins2 = ratio

        if not nof_games:
            self.msg(channel, u"1on1 Ladder Match Ratio: "
                              u"\x02{0}\x02 and \x02{1}\x02 have not yet "
                              u"played against each other.".format(name1,
                                                                   name2))
            return

        self.msg(channel, u"1on1 Ladder Match Ratio: "
                          u"\x02{0}\x02 and \x02{1}\x02 "
                          u"have played {2} games. "
                          u"Ratio is {3}:{4}.".format(name1, name2,
                                                      nof_games, wins1, wins2))

    def tell_suggestion(self, result, channel, user):
        """Write a user's most interesting opponents to channel."""
        if not result:
            self.msg(channel, u"1on1 Ladder: Cannot suggest opponents for "
                              u"\x02{0}\x02.".format(user))
            return

        name, best = result
        self.msg(channel, u"1on1 Ladder: Most interesting opponents for "
                          u"\x02{0}\x02: {1}.".format(name,
                                                      ", ".join(best)))

    def tell_top(self, top, channel, league):
        """Write top10 for the specified league to channel."""
        top_n_str = (u"\x02{0}\x02. {1}".format(x + 1, top[x])
                     for x in range(0, len(top)))

        self.msg(channel, u"1on1 \x02{0}\x02 Leaderboard: {1}".format(
                          league.capitalize(), ", ".join(top_n_str)))

    def tell_streams(self, streams, channel):
        """Write streams to channel."""
        if not len(streams):
            self.msg(channel, u"There are no Planetary Annihilation streams "
                              u"on \x02twitch\x02 at the moment.")
            return

        number = len(streams)
        if number > 5:
            self.msg(channel, u"There are \x02{0}\x02 PA streams on Twitch. "
                              u"For a full list visit http://www.twitch.tv/"
                              u"directory/game/Planetary%20Annihilation/. "
                              u"Five most viewed streams: ".format(number))
            number = 5
        elif number > 1:
            self.msg(channel, u"There are \x02{0}\x02 PA streams "
                              u"on Twitch:".format(number))
        else:
            self.msg(channel, u"There is \x02{0}\x02 PA stream "
                              u"on Twitch:".format(number))

        for x in range(number):
            desc = streams[x]["desc"] or "No Description"
            self.msg(channel, u"Stream #{0}: {1} "
                              u"by \x02{2}\x02 ({3})".format(
                                  x + 1,
                                  desc.replace("\n", ""),
                                  streams[x]["name"],
                                  streams[x]["url"]))

    def tell_tweets(self, tweets, channel):
        """Write tweets to channel."""
        if not len(tweets):
            self.msg(channel, "Could not acquire any Tweets for #UberRTS.")
            return

        self.msg(channel, u"\x02{0}\x02 latest Tweets "
                          u"for #UberRTS:".format(len(tweets)))

        for tweet in tweets:
            self.msg(channel, u"\x02{0}\x02: » {1} « [{2}]".format(
                tweet["name"], tweet["text"],
                tweet["date"].isoformat(" ")))

    def tell_tourney(self, tourney, state, channel):
        """Write tourney to channel."""
        if not tourney:
            if state == "last":
                self.msg(channel, u"No finished tournaments found.")
            else:
                self.msg(channel, u"No upcoming tournaments found.")
            return

        if state == "next":
            now = datetime.utcnow().replace(microsecond=0)
            if now < tourney["date"]:
                countdown = (u"\u23f3"
                             u"\x033 {0}\x0F".format(tourney["date"] - now))

                self.msg(channel, u"Upcoming tournament: "
                                  u"\x02{0}\x02, \u23f0 {1} (UTC) [{2}]: "
                                  u"{3} ({4})".format(
                                      tourney["name"],
                                      tourney["date"].isoformat(" "),
                                      countdown,
                                      tourney["mode"], tourney["url"]))
            else:
                self.msg(channel, u"Tournament in progress: "
                                  u"\x02{0}\x02, \u23f0 {1} (UTC): "
                                  u"{2} ({3})".format(
                                      tourney["name"],
                                      tourney["date"].isoformat(" "),
                                      tourney["mode"], tourney["url"]))
        else:
            self.msg(channel, u"Latest tournament: "
                              u"\x02{0}\x02, \u23f0 {1} (UTC): "
                              u"Winner(s) \x02{2}\x02 ({3})".format(
                                  tourney["name"],
                                  tourney["date"].isoformat(" "),
                                  tourney["winner"], tourney["url"]))

    def tell_patch(self, patches, channel, **kwargs):
        """Write current build IDs to channel."""
        if not patches:
            self.msg(channel, u"Could not query current patch versions.")
            return

        if (kwargs.get("only_new", False) and self.last_patches == patches):
            return

        # remember patches so we don't announce those we've seen already
        self.last_patches = patches

        info = ("{2}: \x02{0}\x02 ({1})".format(
                patch["build"], patch["date"].isoformat(" "), patch["desc"])
                for patch in patches)

        full_info = u"Latest patch versions: {0}".format(", ".join(info))
        if isinstance(channel, list):
            for c in channel:
                self.msg(c, full_info)
        else:
            self.msg(channel, full_info)

    def tell_news(self, news, channel):
        """Write news item to channel."""
        if not news:
            self.msg(channel, u"Could not retrieve news items.")
            return

        # only use latest news
        news = news[0]

        self.msg(channel, u"Latest News: \x02{1}\x02 [{0}]".format(
            news["date"].isoformat(" "), news["title"]))

    def tell_tourney_countdown(self):
        """Write tourney countdown to all channels and schedule next update."""
        now = datetime.utcnow().replace(microsecond=0)

        if now < self.towncrier.event:
            for channel in self.factory.channels:
                self.msg(channel, u"Next tourney will begin in\x033 {0}\x0F. "
                                  u"Use !tourney for details.".format(
                                      self.towncrier.event - now))

        # schedule next update
        try:
            countdown = next(self.towncrier)
            log.msg(u"Scheduling next tournament announcement in {0}s".format(
                countdown))
            self.towncrier.timer = reactor.callLater(
                countdown, self.tell_tourney_countdown)
        except StopIteration:
            self.towncrier.timer = None

    def handle_tourney_countdown(self, tournament):
        """
        Check if we already have a countdown going for this tournament (or we
        no longer need one).
        """
        # are we already waiting for this one?
        if self.towncrier.event == tournament["date"]:
            return

        # remember this event
        self.towncrier.event = tournament["date"]

        # stop old timer if we have one
        if self.towncrier.timer:
            self.towncrier.timer.cancel()
            self.towncrier.timer = None

        # announce event right away for the first time
        self.tell_tourney_countdown()

    def check_events(self):
        """
        Check for events we need to react on.
        Currently these include new patches and new tournaments.
        """
        # we tell everyone about new patches
        self.patch.patches().addCallback(self.tell_patch,
                                         self.factory.channels,
                                         only_new=True)

        # tournaments are not announced, instead we handle countdowns
        self.tourney.next().addCallback(self.handle_tourney_countdown)

class CommanderFactory(protocol.ClientFactory):
    """
    Factory for Commander IRC connections.

    Reads the configuration, stores relevant settings and passes them to the
    protocol object in buildProtocol.
    """

    instance = None

    def __init__(self):
        """Read configuration from a file or store defaults."""
        irc_cfg = configuration.get_config("irc")

        self.channels = irc_cfg["channels"]
        self.linerate = irc_cfg["linerate"]
        self.nickname = irc_cfg["nickname"]
        self.nickserv = irc_cfg["nickserv"]
        self.realname = irc_cfg["realname"]
        self.username = irc_cfg["username"]

        cmd_cfg = configuration.get_config("cmd")
        self.prefix = cmd_cfg["prefix"]
        self.cmdlimit = cmd_cfg["cmdlimit"]

    def buildProtocol(self, address):
        """Build a new CommanderBot instance and remember it."""
        newBot = CommanderBot()
        newBot.factory = self
        self.instance = newBot
        return newBot

    def getInstance(self):
        """Return a list of created CommanderBots."""
        return self.instance

    def clientConnectionLost(self, connector, reason):
        """Reconnect to the server if we got disconnected."""
        log.msg("Disconnected from server: {0}".format(
            reason.getErrorMessage()))
        connector.connect()

    def clientConnectionFailed(self, connector, reason):
        """Stop the reactor if the connection fails."""
        log.msg("Connection to server failed: {0}".format(
            reason.getErrorMessage()))
        reactor.stop()


import datetime
import os

import numpy as np
import torch
# import yaml
from pathlib import Path

from utils import check_mkdir
from utils.data import LAND_CLASSES, COLOR_PALETTE
from utils.data.dataset import AgricultureDataset
from utils.data.preprocess import split_train_val_test_sets

# change DATASET ROOT to your dataset path
# DATASET_ROOT = Path("/home/hanz/github/agriculture-vision-datasets/2021/supervised/Agriculture-Vision-2021")

# TRAIN_ROOT = os.path.join(DATASET_ROOT, "train")
# VAL_ROOT = os.path.join(DATASET_ROOT, "val")
# TEST_ROOT = os.path.join(DATASET_ROOT, "test/images")

class AgricultureConfiguration(object):
    root_path = Path("/home/hanz/github/P3-SemanticSegmentation")
    model_name = "none"
    optimizer = "adam"
    # data set parameters
    dataset = "Agriculture"
    bands = ["NIR", "RGB"]
    loader = AgricultureDataset
    labels = LAND_CLASSES
    nb_classes = len(LAND_CLASSES)
    palette = COLOR_PALETTE  # palette_vsl
    weights = []

    k_folder = 0
    k = 0
    input_size = [512, 512]
    scale_rate = 1.0 / 1.0
    val_size = [512, 512]  # [1224, 1224]#[2248, 2248]
    train_samples = 12901
    val_samples = 1200
    train_batch = 7
    val_batch = 7
    # train_batch = 1
    # val_batch = 1

    # flag of mean_std normalization to [-1, 1]
    pre_norm = False
    seeds = 69278  # random seed

    # training hyper parameters
    lr = 1.5e-4 / np.sqrt(3.0)
    lr_decay = 0.9
    max_iter = 1e8

    # l2 regularization factor, increasing or decreasing to fight over-fitting
    weight_decay = 2e-5
    momentum = 0.9

    # check point parameters
    checkpoint_path = root_path / "checkpoints" / optimizer
    snapshot = ""
    print_freq = 100
    # print_freq = 5
    save_pred = False
    save_rate = 0.1
    best_record = {}

    def __init__(
            self,
            net_name=model_name,
            data=dataset,
            bands_list=bands,
            kf=1,
            k_folder=5,
            note="",
            optimizer="adam",
    ):
        """Class handling training configuration and tensorboard operations

        Refactoring of the following:
            Source: https://github.com/samleoqh/MSCG-Net/blob/master/config/configs_kf.py

        :param net_name:
        :param data:
        :param bands_list:
        :param kf:
        :param k_folder:
        :param note:
        """
        self.model_name = net_name
        self.dataset = data
        self.bands = bands_list
        self.k = kf
        self.k_folder = k_folder
        self.suffix_note = note

        check_mkdir(self.checkpoint_path)
        check_mkdir(os.path.join(self.checkpoint_path, self.model_name))

        band_str = "-".join(self.bands)
        if self.k_folder is not None:
            sub_dir = (
                    self.dataset
                    + "_"
                    + band_str
                    + "_kf-"
                    + str(self.k_folder)
                    + "-"
                    + str(self.k)
            )
        else:
            sub_dir = self.dataset + "_" + band_str
        if note != "":
            sub_dir += "-"
            sub_dir += note

        check_mkdir(os.path.join(self.checkpoint_path, self.model_name, sub_dir))
        self.save_path = os.path.join(self.checkpoint_path, self.model_name, sub_dir)

    def get_file_list(self):
        return split_train_val_test_sets(
            name=self.dataset,
            bands=self.bands,
            KF=self.k_folder,
            k=self.k,
            seeds=self.seeds,
        )

    def get_dataset(self):
        train_dict, val_dict, test_dict = self.get_file_list()
        # split_train_val_test_sets(name=self.dataset,KF=None, k=self.k,seeds=self.seeds)
        train_set = self.loader(
            mode="train",
            file_lists=train_dict,
            pre_norm=self.pre_norm,
            num_samples=self.train_samples,
            win_size=self.input_size,
            scale=self.scale_rate,
        )
        val_set = self.loader(
            mode="val",
            file_lists=val_dict,
            pre_norm=self.pre_norm,
            num_samples=self.val_samples,
            win_size=self.val_size,
            scale=self.scale_rate,
        )
        return train_set, val_set

    def resume_train(self, net, checkpoint_path: str = None, use_gpu: bool = True):
        """Function for loading in a metrics for resuming training
z
        :param net:
        :param checkpoint_path:
        :return:
        """
        # check if path exists
        if checkpoint_path:
            print("Loading metrics from checkpoint:", checkpoint_path)
            if use_gpu:
                net.load_state_dict(
                    torch.load(checkpoint_path, map_location=torch.device(0)),
                    strict=False,
                )
            else:
                net.load_state_dict(
                    torch.load(checkpoint_path, map_location=torch.device("cpu")),
                    strict=False,
                )

        if len(self.snapshot) == 0:
            curr_epoch = 1
            self.best_record = {
                "epoch": 0,
                "val_loss": 0,
                "acc": 0,
                "acc_cls": 0,
                "mean_iu": 0,
                "fwavacc": 0,
                "f1": 0,
            }
        else:
            print("training resumes from " + self.snapshot)
            # core.load_state_dict(torch.load(self.snapshot))
            net.load_state_dict(torch.load(os.path.join(self.save_path, self.snapshot)))
            split_snapshot = self.snapshot.split("_")
            curr_epoch = int(split_snapshot[1]) + 1
            self.best_record = {
                "epoch": int(split_snapshot[1]),
                "val_loss": float(split_snapshot[3]),
                "acc": float(split_snapshot[5]),
                "acc_cls": float(split_snapshot[7]),
                "mean_iu": float(split_snapshot[9]),
                "fwavacc": float(split_snapshot[11]),
                "f1": float(split_snapshot[13]),
            }
        return net, curr_epoch

    def print_best_record(self):
        print(
            "[best_ %d]: [val loss %.5f], [acc %.5f], [acc_cls %.5f], [mean_iu %.5f], [fwavacc %.5f], [f1 %.5f]"
            % (
                self.best_record["epoch"],
                self.best_record["val_loss"],
                self.best_record["acc"],
                self.best_record["acc_cls"],
                self.best_record["mean_iu"],
                self.best_record["fwavacc"],
                self.best_record["f1"],
            )
        )

    def update_best_record(self, epoch, val_loss, acc, acc_cls, mean_iu, fwavacc, f1):
        print(
            "----------------------------------------------------------------------------------------"
        )
        print(
            "[epoch %d]: [val loss %.5f], [acc %.5f], [acc_cls %.5f], [mean_iu %.5f], [fwavacc %.5f], [f1 %.5f]"
            % (epoch, val_loss, acc, acc_cls, mean_iu, fwavacc, f1)
        )
        self.print_best_record()

        print(
            "----------------------------------------------------------------------------------------"
        )
        if mean_iu > self.best_record["mean_iu"] or f1 > self.best_record["f1"]:
            self.best_record["epoch"] = epoch
            self.best_record["val_loss"] = val_loss
            self.best_record["acc"] = acc
            self.best_record["acc_cls"] = acc_cls
            self.best_record["mean_iu"] = mean_iu
            self.best_record["fwavacc"] = fwavacc
            self.best_record["f1"] = f1
            return True
        else:
            return False

    def display(self):
        """printout all configuration values."""
        print("\nConfigurations:")
        for a in dir(self):
            if not a.startswith("__") and not callable(getattr(self, a)):
                print("{:30} {}".format(a, getattr(self, a)))
        print("\n")

    def write2txt(self):
        file = open(
            os.path.join(self.save_path, str(datetime.datetime.now()) + ".txt"), "w"
        )
        for a in dir(self):
            if not a.startswith("__") and not callable(getattr(self, a)):
                line = "{:30} {}".format(a, getattr(self, a))
                file.write(line + "\n")

# def check_mkdir(dir_name):
#     if not os.path.exists(dir_name):
#         os.mkdir(dir_name)
# import re
#     import json

# loader = yaml.SafeLoader
# loader.add_implicit_resolver(
#     u"tag:yaml.org,2002:float",
#     re.compile(
#         u"""^(?:
#  [-+]?(?:[0-9][0-9_]*)\\.[0-9_]*(?:[eE][-+]?[0-9]+)?
# |[-+]?(?:[0-9][0-9_]*)(?:[eE][-+]?[0-9]+)
# |\\.[0-9_]+(?:[eE][-+][0-9]+)?
# |[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*
# |[-+]?\\.(?:inf|Inf|INF)
# |\\.(?:nan|NaN|NAN))$""",
#         re.X,
#     ),
#     list(u"-+0123456789."),
# )
#
# with open("../data/config.yml", "r") as fh:
#     config = yaml.load(fh, Loader=loader)
#     print(config)
# with open("../data/config.json", "w") as fh:
#     json.dump(config, fh, indent=4)
# pass

if __name__ == "__main__":
    pass


# IMPORTS
import os
import json
from urllib.parse import urlencode
from urllib.request import Request, urlopen
from flask import Flask, request
import requests
import re

app = Flask(__name__)

@app.route('/', methods=['POST'])
def webhook():
    token = os.environ.get('token')
    print(type(token))
    data = request.get_json()
    text = str(data['text'])
    tickers = re.findall(r'\$([^a-z\d][^\ &]+)(?=&(peers|chart|pt|news))*', text)

    if len(tickers) >= 1:
        for ticker in tickers:
            if ticker[1] == "":
                replyString = stockQuote(ticker[0], token)
                reply(replyString)
            elif ticker[1] == 'chart':
                reply_with_image(ticker[0])
            elif ticker[1] == 'peers':
                replyString = peers(ticker[0], token)
                reply(replyString)
            elif ticker[1] == 'pt':
                replyString = price_target(ticker[0], token)
                reply(replyString)
            elif ticker[1] == 'news':
                replyString = news(ticker[0], token)
                reply(replyString)

    return "ok", 200

def stockQuote(ticker,token):
    url = 'https://cloud.iexapis.com/v1/stock/{}/quote?token={}'.format(ticker, token)
    print(ticker)
    print(url)
    r = requests.get(url)
    if r.status_code == 200:
        response = requests.get(url).json()
        if response['companyName']:
            companyName = response['companyName']
        else:
            companyName = 'N/A'
        if response['latestPrice']:
            latestPrice = response['latestPrice']
        else:
            latestPrice = 0
        if response['changePercent']:
            changePercent = response['changePercent']
        else:
            changePercent = 0
        if response['peRatio']:
            peRatio = response['peRatio']
        else:
            peRatio = 0
        replyString = "Name: {},  Last price: {:.2f},  Pct chg: {:.2%},  P/E: {:.2f}x".format(companyName, latestPrice, changePercent, peRatio)
    elif r.status_code == 404:
        replyString = "Stonk not found :-("
    else:
        replyString = "Bad Request! response={}".format(r.status_code)
    return replyString

def peers(ticker,token):
    url = 'https://cloud.iexapis.com/v1/stock/{}/peers?token={}'.format(ticker, token)
    r = requests.get(url)
    if r.status_code == 200:
        response = requests.get(url).json()
        reply = str(response)
        return reply

def price_target(ticker,token):
    url = 'https://cloud.iexapis.com/v1/stock/{}/price-target?token={}'.format(ticker, token)
    r = requests.get(url)
    if r.status_code == 200:
        response = requests.get(url).json()
        reply = str(response)
        return reply

def news(ticker,token):
    url = 'https://cloud.iexapis.com/v1/stock/{}/news/last/5?token={}'.format(ticker, token)
    r = requests.get(url)
    if r.status_code == 200:
        response = requests.get(url).json()
        x=[(x['headline'], x['url']) for x in response]
        reply = str(x)
        return reply

# Send a message in the groupchat
def reply(msg):
    bot = os.environ.get('botid')
    url = 'https://api.groupme.com/v3/bots/post'
    data = {'bot_id':bot, 'text':msg}
    request = Request(url, urlencode(data).encode())
    json = urlopen(request).read().decode()

def upload_image(imgURL):
    session = requests.Session()
    access = os.environ.get('access')
    imgRequest = session.get(imgURL, stream=True, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
    filename = 'temp.png'
    postImage = None
    if imgRequest.status_code == 200:
        # Save Image
        with open(filename, 'wb') as image:
            for chunk in imgRequest:
                image.write(chunk)
        # Send Image
        headers = {'content-type': 'application/json'}
        url = 'https://image.groupme.com/pictures'
        files = {'file': open(filename, 'rb')}
        payload = {'access_token': access}
        r = requests.post(url, files=files, params=payload, timeout=10)
        imageurl = r.json()['payload']['url']
        os.remove(filename)
        return imageurl

def reply_with_image(ticker):
    bot = os.environ.get('botid')
    token = os.environ.get('token')
    url = 'https://api.groupme.com/v3/bots/post'
    imgURL = 'https://c.stockcharts.com/c-sc/sc?s={}&p=D&b=5&g=0&i=0&r=1564148102465'.format(ticker)
    msg = stockQuote(ticker,token)
    urlOnGroupMeService = upload_image(imgURL)
    print(urlOnGroupMeService)
    print('!!!!!!!!!!{}!!!!!!!!'.format(urlOnGroupMeService))
    data = {
        'text' : msg,
        'bot_id'        : bot,
        'picture_url'       : urlOnGroupMeService
    }
    request = Request(url, urlencode(data).encode())
    json = urlopen(request, timeout=10).read().decode()


from pathlib import Path
from typing_extensions import Final
from srim import Layer, Target
from .dcf import create_ion_list, pool_srim, pickle_srim, elem_u_dict, elem_o_dict, elem_si_dict

if __name__ == "__main__":

    # set path to save data
    data_path: Final[Path] = Path(r".\data\uo2pure")

    # poin to srim exec
    srim_executable_directory: Final[Path] = Path(r"C:\srim")

    # create list of ions from list of energies in keV
    energy_kev_list = [
        50,
        100,
        200,
        300,
        400,
        500,
        600,
        700,
        800,
        900,
        1000,
        1250,
        1500,
        1750,
        2000,
        2500,
        3000,
        4000,
        5000,
    ]

    ions_He_list = create_ion_list("He", energy_kev_list, units="kev")

    # create target from list of layers
    layer_UO2_10um = Layer(
        {
            "U": {"stoich": 1.0, **elem_u_dict},
            "O": {"stoich": 2.0, **elem_o_dict.as_dict()},
        },
        density=10.97,
        width=100_000.0,
        name="urania",
    )

    layer_SiO2_10um = Layer(
        {
            "Si": {"stoich": 1.0, **elem_si_dict},
            "O": {"stoich": 2.0, **elem_o_dict.as_dict()},
        },
        density=2.65,
        width=100_000.0,
        name="silica",
    )

    target = Target([layer_UO2_10um])

    data_list = pool_srim(
        ions_He_list,
        target,
        data_path,
        num_ions=1_000_000,
        srim_dir=srim_executable_directory,
    )

    pickle_srim(data_list)


import numpy as np
import pprint
from typing import List
from collections import deque

arr = []
G = {}
starts = []
starts_res = []
with open("./day12/input.txt") as input:
    lines = [line.replace("\n", "") for line in input.readlines()]

    for i, line in enumerate(lines):
        arr.append([])
        for j, letter in enumerate(line):
            if letter == "S":
                print("start at", i, j)
                letter = "a"
            if letter == "E":
                print("end at", i, j)
                letter = "z"
            arr[i].append(letter)

            if letter == "a":
                starts.append((i,j))
    # pprint.pprint(arr)

    for i in range(len(arr)):
        for j in range(len(arr[i])):
            G[(i, j)] = []
            curr = arr[i][j]

            if i > 0:
                if ord(curr) - ord(arr[i - 1][j]) >= -1:
                    G[(i, j)].append((i - 1, j))
            if i < (len(arr) - 1):
                if ord(curr) - ord(arr[i + 1][j]) >= -1:
                    G[(i, j)].append((i + 1, j))
            if j > 0:
                if ord(curr) - ord(arr[i][j - 1]) >= -1:
                    G[(i, j)].append((i, j - 1))
            if j < (len(arr[i]) - 1):
                if ord(curr) - ord(arr[i][j + 1]) >= -1:
                    G[(i, j)].append((i, j + 1))

    # pprint.pprint(G)

def shortest_path(graph, node1, node2):
    path_list = [[node1]]
    path_index = 0
    # To keep track of previously visited nodes
    previous_nodes = {node1}
    if node1 == node2:
        return path_list[0]

    while path_index < len(path_list):
        current_path = path_list[path_index]
        last_node = current_path[-1]
        next_nodes = graph[last_node]
        # Search goal node
        if node2 in next_nodes:
            current_path.append(node2)
            return current_path
        # Add new paths
        for next_node in next_nodes:
            if not next_node in previous_nodes:
                new_path = current_path[:]
                new_path.append(next_node)
                path_list.append(new_path)
                # To avoid backtracking
                previous_nodes.add(next_node)
        # Continue to next path in list
        path_index += 1
    # No path is found
    return []

for s in starts:
    # shortest = shortest_path(G, s, (2,5))
    shortest = shortest_path(G, s, (20,91))
    print(len(shortest))
    if len(shortest) > 0:
        starts_res.append(len(shortest) - 1)

starts_res.sort()
print(starts_res)

"""

Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

v..v<<<<
>v.vv<<^
.>vv>E^^
..v>>>^^
..>>>>>^
"""


import json
import os

share_name = '[inosatiot-report]'
config_file = '/etc/samba/smb.conf'

with open(os.getenv('inosatiot_cfg')) as f:
    cfg = json.loads(f.read())

# read file
with open(config_file, 'r') as reader:
    lines = reader.readlines()

# maybe config exist - find lines
begin = -1
end = -1
for i in range(len(lines)):
    if lines[i].find('#' + share_name) >= 0:
        end = i
    elif lines[i].find(share_name) >= 0:
        begin = i

# write file if config found
if begin >= 0 and end >= 0:
    del lines[begin:end + 1]
    with open(config_file, 'w') as reader:
        for line in lines:
            reader.write(line)

# append new configuration
config = f"""{share_name}
    comment = Report folder for InosatIoT
    path = {cfg['report']['output_path']}
    read only = no
    browsable = yes
#{share_name}"""

with open(config_file, 'a') as reader:
    reader.write(config)

print(f'Added configuration to file {config_file}: \n{config}')


import pyttsx3
import torch
from transformers import GPT2LMHeadModel, GPT2Tokenizer

class Companion:

    def announce(self, stringvar):
        print(stringvar)
        self.voice_engine.say(stringvar)
        self.voice_engine.runAndWait()
        return
    def chat(self):

        print("Beginning chat protocol, enter text to chat with AI...")
        self.chat_flag = True
        while self.go_flag == True:

            self.sequence = input()
            if self.sequence == "":
                self.go_flag == False
            else:
                self.inputs = self.tokenizer.encode(self.sequence, return_tensors='pt')
                self.outputs = self.model.generate(self.inputs, max_length=200, do_sample=True)
                self.text = self.tokenizer.decode(self.outputs[0], skip_special_tokens=True)
                print(self.text)

    def voice_chat(self):
        print("Beginning chat protocol, enter text to chat with AI...")
        self.chat_flag = True
        while self.go_flag == True:

            self.sequence = input()
            if self.sequence == "":
                self.go_flag == False
            else:
                self.inputs = self.tokenizer.encode(self.sequence, return_tensors='pt')
                self.outputs = self.model.generate(self.inputs, max_length=200, do_sample=True)
                self.text = self.tokenizer.decode(self.outputs[0], skip_special_tokens=True)
                self.announce(self.text)

    def __init__(self):
        self.tokenizer = GPT2Tokenizer.from_pretrained('gpt2')
        self.model = GPT2LMHeadModel.from_pretrained('gpt2')
        self.go_flag = True
        self.sequence = ""
        self.chat_flag = False
        self.inputs = None
        self.outputs = None
        self.text = None

        # TTS Engine Initialization
        self.voice_engine = pyttsx3.init()
        self.voices = self.voice_engine.getProperty("voices")
        self.voice_engine.setProperty('rate', 175)
        self.voice_engine.setProperty('voice', self.voices[1].id)

        # Voice Recognition Initialization
        self.recog_model = vosk.Model("vosk-model-small-en-us-0.15")
        self.voice_recog = vosk.KaldiRecognizer(self.recog_model, 16000)
        self.mic = pyaudio.PyAudio()
        self.stream = self.mic.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=81)
        self.stream.start_stream()

        # Tests/ Strings
        self.voice_engine.runAndWait()

def main():
    artemis = Companion()
    artemis.chat()

if __name__ == "__main__":
    main()


import streamlit
import pandas
import requests
import snowflake.connector
from urllib.error import URLError

streamlit.title('My Parents\' New Healthy Diner')

streamlit.header('\N{bowl with spoon} Breakfast Favorites')
streamlit.text('Omega 3 & Blueberry Oatmeal')
streamlit.text('🥗 Kale, Spinach & Rocket Smoothie')
streamlit.text('🐔 Hard-Boiled Free-Range Egg')
streamlit.text('🍓 Avocado Toast')

streamlit.header('🍉 Build ur Own Fruit Smoothie 🍎')

fruit_list=pandas.read_csv("https://uni-lab-files.s3.us-west-2.amazonaws.com/dabw/fruit_macros.txt")
fruit_list=fruit_list.set_index('Fruit')

#multi select for the user to pick their fruits
fruits_selected=streamlit.multiselect("Pick ur Fruits",list(fruit_list.index),['Apple','Banana'])
fruits_show=fruit_list.loc[fruits_selected]
#streamlit.multiselect("Pick ur Fruits",list(fruit_list.Fruit))
streamlit.dataframe(fruits_show)

#function
def get_fruityvice_data(this_fruit_choice):
  fruityvice_response = requests.get("https://fruityvice.com/api/fruit/" +fruit_choice)
  #normalizing json text
  fruityvice_normalize=pandas.json_normalize(fruityvice_response.json())
  #print as a table
  return fruityvice_normalize

#new section for Fruity Vice
streamlit.header('Fruityvice Fruit Advice')
try:
  fruit_choice=streamlit.text_input('What fruit would you like to know about?')
  if not fruit_choice:
    streamlit.error("Please select a fruit to get information")
  else:
    value_from_function=get_fruityvice_data(fruit_choice)
    #print as a table
    streamlit.dataframe(value_from_function)

except URLError as e:
  streamlit.error()

streamlit.header("View our fruit list & Add ur favorites!!")
#snowflake functions:
def get_fruit_load_list():
  with my_cnx.cursor() as my_crsr:
    my_crsr.execute("select * from fruit_load_list")
    return my_crsr.fetchall()

#add a button and def for fruit load list:
if streamlit.button('Get fruit load list'):
  my_cnx= snowflake.connector.connect(**streamlit.secrets["snowflake"])
  my_data=get_fruit_load_list()
  my_cnx.close()
  streamlit.dataframe(my_data)

#allow user to add a fruit:
def insert_fruit_snowflake(new_fruit):
  with my_cnx.cursor() as my_crsr:
    my_crsr.execute("insert into fruit_load_list values ('"+new_fruit+"')")
    return "Thanks for adding: "+new_fruit

usr_fruit=streamlit.text_input('What fruit would you like to add in this list?')
if streamlit.button('Add a fruit to the list?'):
  my_cnx= snowflake.connector.connect(**streamlit.secrets["snowflake"])
  my_data=insert_fruit_snowflake(usr_fruit)
  my_cnx.close()
  streamlit.text(my_data)


import subprocess
import threading
import time

class Executable:
    def __init__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        self.is_running = threading.Event()
        self.p = None

    def run(self):
        self.is_running.set()
        while self.is_running.is_set():
            self.p = subprocess.Popen(*self.args, **self.kwargs)
            self.p.wait()
            time.sleep(1)

    def stop(self):
        assert self.p
        self.is_running.clear()
        self.p.kill()


n = int(input())
ar = list(map(int, input().split()))
print(ar)

d = [0]*101

d[0] = ar[0]
d[1] = ar[1]
for i in range(2, len(ar)):
    d[i] = max(d[i-2]+ar[i], d[i-1])

print(d[len(ar)-1])


from redbot.core import commands
import random
import os

path_cog = "C:/Users/nonadmin-main/Documents/MyCogs/play_by_category/"
path_cats = path_cog + "tracks/"
path_hist = path_cog + "history/"

def add_to_history(cat, track):
    path_file = path_hist + cat + ".txt"

    # append track fo history
    with open(path_file, "a") as file:
        file.write(track + "\n")

    # get num of file lines
    with open(path_file, "r+") as file:
        len_file = len(file.readlines())

    # get num of tracks in category
    len_cat = len([t.name for t in os.scandir(path_cats + cat)])

    # if all available tracks recorded, reset history
    if len_cat <= len_file:
        with open(path_file, 'w'):
            pass

def track_in_history(cat, track):
    path_file = path_hist + cat + ".txt"

    # create file if it doesn't exist
    if not os.path.isfile(path_file):
        with open(path_file, 'w'):
            pass

    with open(path_file, "r") as file:
        return track + "\n" in file.readlines()

def get_track(cat):
    cat_tracks = [t.name for t in os.scandir(path_cats + cat)]
    while True:
        random.shuffle(cat_tracks)
        track = cat_tracks.pop()

        if not track_in_history(cat, track):
            break

    add_to_history(cat, track)

    return track

class PlayByCategory(commands.Cog):
    """cat as in category"""

    # TODO: get prefix from redbot code

    def __init__(self, bot):
        self.bot = bot

    @commands.command()
    async def test(self, ctx):
        await ctx.send("h")

    @commands.command()
    async def playcat(self, ctx, cat):
        """play any track fromm user selected category"""

        # if folder doesn't exist
        if not os.path.isdir(path_cats + cat):
            await ctx.send("Category not found")
            return

        # if folder doesn't have files
        if not any(os.scandir(path_cats + cat)):
            await ctx.send("Category has no tracks")
            return

        # get (recently unplayed) random track in category
        track = get_track(cat)

        # otherwise, track will wait in queue,
        # and previous track shouldn't be in queue anymore
        await ctx.invoke(self.bot.get_command("stop"))

        # play track
        await ctx.invoke(self.bot.get_command("play"),
                         query=os.path.join(path_cats, cat, track))

    @commands.command()
    async def helpcat(self, ctx):
        """lets user know what they can do"""
        await ctx.send("?playcat <category>\n"
                       "?printcat - print available categories")

    @commands.command()
    async def printcat(self, ctx):
        """Get and print all category names in cog working directory.
        Folder names are category names."""

        # get folder names (excluding empty folders)
        cats = [c.name for c in os.scandir(path_cats)
                if any(os.scandir(path_cats + c.name))]

        # if list, join items to str
        if not isinstance(cats, str):
            cats = ", ".join(cats)

        await ctx.send("Available categories:  " + cats)


__author__      = "Stian Soiland-Reyes <https://orcid.org/0000-0001-9842-9718>"
__copyright__   = "Copyright 2018-2020 The University of Manchester"
__license__     = "Apache License, version 2.0 (https://www.apache.org/licenses/LICENSE-2.0)"

from setuptools import setup, find_packages
from codecs import open
from os import path

here = path.abspath(path.dirname(__file__))

with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
  long_description = f.read()

setup(
  name = 'arcp',
  packages = find_packages(exclude=['contrib', 'docs', 'tests']), # Required
  version = '0.2.2.dev0',
  description = 'arcp (Archive and Package) URI parser and generator',
  long_description=long_description,
  author = 'Stian Soiland-Reyes',
  author_email = 'stain@apache.org',

  # https://www.apache.org/licenses/LICENSE-2.0
  license = "Apache License, Version 2.0",
  url = 'https://arcp.readthedocs.io/',
  download_url = 'https://github.com/stain/arcp-py/archive/0.1.0.tar.gz',
  keywords = "arcp uri url iri archive package",

  install_requires=[],
  classifiers=[
    # https://pypi.python.org/pypi?%3Aaction=list_classifiers
    'Development Status :: 3 - Alpha',

    'Intended Audience :: Developers',
    'Topic :: Software Development :: Build Tools',
    'Topic :: Software Development :: Libraries :: Python Modules',
     # 'License :: OSI Approved :: Apache Software License',
     # https://github.com/pypa/pypi-legacy/issues/564
    #'License :: OSI Approved',
    # 'License :: OSI Approved :: Apache License, Version 2.0 (Apache-2.0)',
    'Programming Language :: Python :: 2.7',
    'Programming Language :: Python :: 3',
    'Programming Language :: Python :: 3.5',
    'Programming Language :: Python :: 3.6',
    'Programming Language :: Python :: 3.7',
    'Programming Language :: Python :: 3.8',
    'Topic :: Internet',
    'Topic :: Internet :: WWW/HTTP',
    'Topic :: System :: Archiving',
    'Topic :: System :: Archiving :: Packaging',
],

)


x = input() #Input #1
a = set(map(int, input().split())) #Input #2
y = input() #Input #3
b = set(map(int, input().split())) #Input #4

# Convert the lists back to set
c = set(a.difference(b))
d = set(b.difference(a))

# union of both the above sets in sorted order
e = sorted(c.union(d))
for i in e:
    print(i)


"""
script that takes as input the .dout file from hmmscan and the fasta of the
full pdb as inputted by the user
the script searches the .dout file for the highest aligning chains
and finds the coordinates of the variable region
{Ab} = the name of .dout file
coordinates are outputted to {Ab}/variable_coords.txt
also finds if antibody is kappa or lambda and writes to {Ab}/korl.txt
Note: often cuts off variable region one residue on either side of
each chain
"""

from Bio import SeqIO, SearchIO, Seq
from Bio.SeqRecord import SeqRecord
from Bio.Alphabet import generic_protein
import sys

dout = sys.argv[1]
fasta = sys.argv[2]

name = dout.split("/")[-1].split(".")[0]
dtbl = SearchIO.read(dout,'hmmscan3-domtab')
light_max_score = 0
heavy_max_score = 0
kappa = ""
for hmm in dtbl:
    dom = hmm.id.split("_")[0]
    for hit in hmm:
        score = hit.bitscore
        h = (dom == 'heavy') and (score > 80)
        l = dom in ['kappa' , 'lambda'] and (score > 80)
        if h and score > heavy_max_score:
            heavy_max_score = score
            heavy_coords = (hit.query_start,
                                    hit.query_end)
        if l and score > light_max_score:
            kappa = dom
            light_max_score = score
            light_coords = (hit.query_start,
                                    hit.query_end)

heavy_range = range(heavy_coords[0], heavy_coords[1])
light_range = range(light_coords[0], light_coords[1])

assert light_coords[0] not in heavy_range
assert light_coords[1] not in heavy_range

with open(f".kappa_or_lambda.txt", "w") as f:
    f.write(kappa)

for record in SeqIO.parse(fasta, "fasta"):
    Ab_seq = str(record.seq)

heavy_start = heavy_coords[0]
heavy_end = heavy_coords[1]

light_start = light_coords[0]
light_end = light_coords[1]

with open(f"./variable_coords.txt", "w") as f:
    f.write(f"{light_coords[0]} {light_coords[1]}\n")
    f.write(f"{heavy_coords[0]} {heavy_coords[1]}\n")


"""
Given a square matrix mat, return the sum of the matrix diagonals.

Only include the sum of all the elements on the primary diagonal and all the elements on the
secondary diagonal that are not part of the primary diagonal.

Ex 1:
Input: mat = [[1,2,3],
              [4,5,6],
              [7,8,9]]
Output: 25
Explanation: Diagonals sum: 1 + 5 + 9 + 3 + 7 = 25
Notice that element mat[1][1] = 5 is counted only once.

Input: mat = [[1,1,1,1],
              [1,1,1,1],
              [1,1,1,1],
              [1,1,1,1]]
Output: 8

Input: mat = [[5]]
Output: 5

"""

from typing import List

def matrixDiagonalSum(mat: List[List[int]]) -> int:

    primary_diagonal = 0
    secondary_diagonal = 0

    # first approach, time complexity O(n^2)
    # for index in range(len(mat)):
    #     for element_position in range(len(mat[index])):
    #         if index == element_position:
    #             primary_diagonal += mat[index][element_position]
    #
    #         if index + element_position == len(mat) - 1:
    #             if index != element_position:
    #                 secondary_diagonal += mat[index][element_position]
    # return primary_diagonal+secondary_diagonal

    # second approach, time complexity O(n^2)
    n = len(mat)

    for index in range(len(mat)):
        primary_diagonal += mat[index][index]

        if index + index != n - 1:
            secondary_diagonal += mat[index][n - index - 1]

    return primary_diagonal + secondary_diagonal

if __name__ == '__main__':
    mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    fc = matrixDiagonalSum(mat)
    expected_result = 25
    assert expected_result == fc, fc
    print(fc)

    mat = [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]]
    fc = matrixDiagonalSum(mat)
    expected_result = 8
    assert expected_result == fc, fc
    print(fc)

    mat = [[5]]
    fc = matrixDiagonalSum(mat)
    expected_result = 5
    assert expected_result == fc, fc
    print(fc)


import multiprocessing

bind = '0.0.0.0:5000'
# 开启进程
workers = 3
# workers = multiprocessing.cpu_count()

# # 每个进程的开启线程
# threads = 5

# 工作模式为gthread
# worker_class = "gthread"

# debug=True
# 如果不使用supervisord之类的进程管理工具需要设置为守护进程，否则会出问题
daemon = True

# 进程名称
proc_name = 'gunicorn.pid'
# 进程pid记录文件
pidfile = '/var/log/gunicorn/app_pid.log'
loglevel = 'debug'
logfile = '/var/log/gunicorn/debug.log'
accesslog = '/var/log/gunicorn/access.log'
access_log_format = '%(h)s %(t)s %(U)s %(q)s'