import unittest2

class TestIterator(unittest2.TestCase):

    def _getTargetClass(self):
        from gcloud.iterator import Iterator
        return Iterator

    def _makeOne(self, *args, **kw):
        return self._getTargetClass()(*args, **kw)

    def test_ctor(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        iterator = self._makeOne(client, PATH)
        self.assertTrue(iterator.client is client)
        self.assertEqual(iterator.path, PATH)
        self.assertEqual(iterator.page_number, 0)
        self.assertEqual(iterator.next_page_token, None)

    def test___iter__(self):
        PATH = '/foo'
        KEY1 = 'key1'
        KEY2 = 'key2'
        ITEM1, ITEM2 = object(), object()
        ITEMS = {KEY1: ITEM1, KEY2: ITEM2}

        def _get_items(response):
            for item in response.get('items', []):
                yield ITEMS[item['name']]
        connection = _Connection({'items': [{'name': KEY1}, {'name': KEY2}]})
        client = _Client(connection)
        iterator = self._makeOne(client, PATH)
        iterator.get_items_from_response = _get_items
        self.assertEqual(list(iterator), [ITEM1, ITEM2])
        kw, = connection._requested
        self.assertEqual(kw['method'], 'GET')
        self.assertEqual(kw['path'], PATH)
        self.assertEqual(kw['query_params'], {})

    def test_has_next_page_new(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        iterator = self._makeOne(client, PATH)
        self.assertTrue(iterator.has_next_page())

    def test_has_next_page_w_number_no_token(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        iterator = self._makeOne(client, PATH)
        iterator.page_number = 1
        self.assertFalse(iterator.has_next_page())

    def test_has_next_page_w_number_w_token(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        TOKEN = 'token'
        iterator = self._makeOne(client, PATH)
        iterator.page_number = 1
        iterator.next_page_token = TOKEN
        self.assertTrue(iterator.has_next_page())

    def test_get_query_params_no_token(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        iterator = self._makeOne(client, PATH)
        self.assertEqual(iterator.get_query_params(), {})

    def test_get_query_params_w_token(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        TOKEN = 'token'
        iterator = self._makeOne(client, PATH)
        iterator.next_page_token = TOKEN
        self.assertEqual(iterator.get_query_params(),
                         {'pageToken': TOKEN})

    def test_get_query_params_extra_params(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        extra_params = {'key': 'val'}
        iterator = self._makeOne(client, PATH, extra_params=extra_params)
        self.assertEqual(iterator.get_query_params(), extra_params)

    def test_get_query_params_w_token_and_extra_params(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        TOKEN = 'token'
        extra_params = {'key': 'val'}
        iterator = self._makeOne(client, PATH, extra_params=extra_params)
        iterator.next_page_token = TOKEN

        expected_query = extra_params.copy()
        expected_query.update({'pageToken': TOKEN})
        self.assertEqual(iterator.get_query_params(), expected_query)

    def test_get_query_params_w_token_collision(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        extra_params = {'pageToken': 'val'}
        self.assertRaises(ValueError, self._makeOne, client, PATH,
                          extra_params=extra_params)

    def test_get_next_page_response_new_no_token_in_response(self):
        PATH = '/foo'
        TOKEN = 'token'
        KEY1 = 'key1'
        KEY2 = 'key2'
        connection = _Connection({'items': [{'name': KEY1}, {'name': KEY2}],
                                  'nextPageToken': TOKEN})
        client = _Client(connection)
        iterator = self._makeOne(client, PATH)
        response = iterator.get_next_page_response()
        self.assertEqual(response['items'], [{'name': KEY1}, {'name': KEY2}])
        self.assertEqual(iterator.page_number, 1)
        self.assertEqual(iterator.next_page_token, TOKEN)
        kw, = connection._requested
        self.assertEqual(kw['method'], 'GET')
        self.assertEqual(kw['path'], PATH)
        self.assertEqual(kw['query_params'], {})

    def test_get_next_page_response_no_token(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        iterator = self._makeOne(client, PATH)
        iterator.page_number = 1
        self.assertRaises(RuntimeError, iterator.get_next_page_response)

    def test_reset(self):
        connection = _Connection()
        client = _Client(connection)
        PATH = '/foo'
        TOKEN = 'token'
        iterator = self._makeOne(client, PATH)
        iterator.page_number = 1
        iterator.next_page_token = TOKEN
        iterator.reset()
        self.assertEqual(iterator.page_number, 0)
        self.assertEqual(iterator.next_page_token, None)

    def test_get_items_from_response_raises_NotImplementedError(self):
        PATH = '/foo'
        connection = _Connection()
        client = _Client(connection)
        iterator = self._makeOne(client, PATH)
        self.assertRaises(NotImplementedError,
                          iterator.get_items_from_response, object())

class TestMethodIterator(unittest2.TestCase):

    def _getTargetClass(self):
        from gcloud.iterator import MethodIterator
        return MethodIterator

    def _makeOne(self, *args, **kw):
        return self._getTargetClass()(*args, **kw)

    def test_ctor_defaults(self):
        wlm = _WithListMethod()
        iterator = self._makeOne(wlm.list_foo)
        self.assertEqual(iterator._method, wlm.list_foo)
        self.assertEqual(iterator._token, None)
        self.assertEqual(iterator._page_size, None)
        self.assertEqual(iterator._kw, {})
        self.assertEqual(iterator._max_calls, None)
        self.assertEqual(iterator._page_num, 0)

    def test_ctor_explicit(self):
        wlm = _WithListMethod()
        TOKEN = wlm._letters
        SIZE = 4
        CALLS = 2
        iterator = self._makeOne(wlm.list_foo, TOKEN, SIZE, CALLS,
                                 foo_type='Bar')
        self.assertEqual(iterator._method, wlm.list_foo)
        self.assertEqual(iterator._token, TOKEN)
        self.assertEqual(iterator._page_size, SIZE)
        self.assertEqual(iterator._kw, {'foo_type': 'Bar'})
        self.assertEqual(iterator._max_calls, CALLS)
        self.assertEqual(iterator._page_num, 0)

    def test___iter___defaults(self):
        import string
        wlm = _WithListMethod()
        iterator = self._makeOne(wlm.list_foo)
        found = []
        for char in iterator:
            found.append(char)
        self.assertEqual(found, list(string.printable))
        self.assertEqual(len(wlm._called_with), len(found) // 10)
        for i, (token, size, kw) in enumerate(wlm._called_with):
            if i == 0:
                self.assertEqual(token, None)
            else:
                self.assertEqual(token, string.printable[i * 10:])
            self.assertEqual(size, None)
            self.assertEqual(kw, {})

    def test___iter___explicit_size_and_maxcalls_and_kw(self):
        import string
        wlm = _WithListMethod()
        iterator = self._makeOne(wlm.list_foo, page_size=2, max_calls=3,
                                 foo_type='Bar')
        found = []
        for char in iterator:
            found.append(char)
        self.assertEqual(found, list(string.printable[:2 * 3]))
        self.assertEqual(len(wlm._called_with), len(found) // 2)
        for i, (token, size, kw) in enumerate(wlm._called_with):
            if i == 0:
                self.assertEqual(token, None)
            else:
                self.assertEqual(token, string.printable[i * 2:])
            self.assertEqual(size, 2)
            self.assertEqual(kw, {'foo_type': 'Bar'})

class _WithListMethod(object):

    def __init__(self):
        import string
        self._called_with = []
        self._letters = string.printable

    def list_foo(self, page_token, page_size, **kw):
        if page_token is not None:
            assert page_token == self._letters
        self._called_with.append((page_token, page_size, kw))
        if page_size is None:
            page_size = 10
        page, self._letters = (
            self._letters[:page_size], self._letters[page_size:])
        token = self._letters or None
        return page, token

class _Connection(object):

    def __init__(self, *responses):
        self._responses = responses
        self._requested = []

    def api_request(self, **kw):
        self._requested.append(kw)
        response, self._responses = self._responses[0], self._responses[1:]
        return response

class _Client(object):

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


################################################################################
# fetch cmd funcs
#
# The "fetch" command fetches all repos on which the currently checked out
# revision of the current repo depend. i.e. 'git fetch <remote>' is called for
# all dependent repos.
################################################################################

import sys

from repo_tool import rept_utils

def print_fetch_usage():
    rept_utils.printerr('usage: rept fetch')

def cmd_fetch(dependencies, local_config, args):
    parsed_args = rept_utils.parse_args(
        args, '', usage_fn=print_fetch_usage)

    if len(parsed_args[1]):
        rept_utils.print_unknown_arg(parsed_args[1][0])
        print_fetch_usage()
        sys.exit(1)

    errs = []

    print('fetching {0} for this repo...'.format(local_config.remote))
    ret = rept_utils.exec_proc(['git', 'fetch', local_config.remote], False)
    if (ret):
        errs.append(
            "error: cannot fetch '{0}' for this repo".format(local_config.remote))

    for dep in dependencies:
        print('fetching {0}...'.format(dep.name))
        with rept_utils.DoInExistingDir(dep.path) as ctx:
            if ctx:
                ret = rept_utils.exec_proc(['git', 'fetch', dep.remote], False)
                if (ret):
                    errs.append(
                        "error: cannot fetch repo '{0}'".format(dep.name))
            else:
                errs.append('Missing repo: {0}'.format(dep.path))

    if errs:
        rept_utils.print_std_err_list(errs)
        sys.exit(1)


'''
Problem Statement - https://www.hackerrank.com/challenges/s10-geometric-distribution-2/problem
'''

def cal_geometri_distribution(probability,no_of_occurences):
    gd = 0
    for i in range(1, no_of_occurences + 1):
        print(i)
        gd += ((1-probability)**(no_of_occurences-i))*probability
    return gd
def decimal_print(value):
    formatted_float = "{:.3f}".format(value)
    print(formatted_float)

if __name__ == "__main__":
    no1,no2 = map(int, input().split(' '))
    no_of_occurences = int(input())
    P = no1/no2
    decimal_print(cal_geometri_distribution(P,no_of_occurences))

10 Days of Statistics/Day4: Geometric Distribution II/Day4_3.py


from collections import defaultdict, deque

from aoc.common.day_solver import DaySolver

class Day12Solver(DaySolver):
    year = 2021
    day = 12

    def _load_input(self, filename=None):
        lines = self.load_all_input_lines(filename)

        connections = defaultdict(lambda: [])
        can_revisit = set()
        for line in lines:
            node_1, node_2 = line.split('-')
            if node_1.isupper():
                can_revisit.add(node_1)
            if node_2.isupper():
                can_revisit.add(node_2)
            connections[node_1].append(node_2)
            connections[node_2].append(node_1)

        return connections, can_revisit

    def solve_puzzle_one(self):
        connections, can_revisit = self._load_input()

        all_paths = self._find_all_paths(connections, can_revisit, 'start', 'end')

        return len(all_paths)

    def solve_puzzle_two(self):
        connections, can_revisit = self._load_input()

        all_paths = self._find_all_paths_with_repeat(connections, can_revisit, 'start', 'end')

        return len(all_paths)

    def _find_all_paths(self, connections, can_revisit, start, end, visited=None):
        if visited is None:
            visited = set()

        visited.add(start)
        all_paths = []
        for adj in connections[start]:
            if adj == end:
                all_paths.append([start, end])
            elif adj in can_revisit or adj not in visited:
                adj_paths = self._find_all_paths(connections, can_revisit, adj, end, visited.copy())
                for path in adj_paths:
                    new_path = [start]
                    new_path.extend(path)
                    all_paths.append(new_path)

        return all_paths

    def _find_all_paths_with_repeat(self, connections, can_revisit, start, end, visited=None, has_repeat=False):
        if visited is None:
            visited = set()

        if start not in can_revisit:
            visited.add(start)
        all_paths = []
        for adj in connections[start]:
            if adj == end:
                all_paths.append([start, end])
                continue

            else:
                if adj not in visited:
                    adj_paths = self._find_all_paths_with_repeat(
                        connections,
                        can_revisit,
                        adj,
                        end,
                        visited.copy(),
                        has_repeat,
                    )
                elif not has_repeat and adj not in ('start', 'end'):
                    adj_paths = self._find_all_paths_with_repeat(
                        connections,
                        can_revisit,
                        adj,
                        end,
                        visited.copy(),
                        has_repeat=True,
                    )
                else:
                    adj_paths = []

                for path in adj_paths:
                    new_path = [start]
                    new_path.extend(path)
                    all_paths.append(new_path)

        return all_paths


from spack import *

class RMmwrweek(RPackage):
    """The first day of any MMWR week is Sunday. MMWR week numbering is
    sequential beginning with 1 and incrementing with each week to a maximum
    of 52 or 53. MMWR week #1 of an MMWR year is the first week of the year
    that has at least four days in the calendar year. This package provides
    functionality to convert Dates to MMWR day, week, and year and the
    reverse."""

    homepage = "https://cran.r-project.org/package=MMWRweek"
    url      = "https://cran.r-project.org/src/contrib/MMWRweek_0.1.1.tar.gz"
    list_url = "https://cran.r-project.org/src/contrib/Archive/MMWRweek"

    version('0.1.1', 'a1245025126f8a96c72be8f7b06b0499')


import asyncio
import os
import re
import sys

from telethon import TelegramClient

from ..core.logger import logging
from ..sql_helper.global_collection import (
    add_to_collectionlist,
    del_keyword_collectionlist,
    get_collectionlist_items,
)

package_patern = re.compile(r"([\w-]+)(?:=|<|>|!)")
github_patern = re.compile(r"(?:https?)?(?:www.)?(?:github.com/)?([\w\-.]+/[\w\-.]+)/?")
github_raw_pattern = re.compile(
    r"(?:https?)?(?:raw.)?(?:githubusercontent.com/)?([\w\-.]+/[\w\-.]+)/?"
)
trees_pattern = "https://api.github.com/repos/{}/git/trees/master"
raw_pattern = "https://raw.githubusercontent.com/{}/master/{}"

LOGS = logging.getLogger(__name__)

async def get_pip_packages(requirements):
    """Get a list of all the pacakage's names."""
    if requirements:
        packages = requirements
    else:
        cmd = await asyncio.create_subprocess_exec(
            sys.executable.replace(" ", "\\ "),
            "-m",
            "pip",
            "freeze",
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, _ = await cmd.communicate()
        packages = stdout.decode("utf-8")
    tmp = package_patern.findall(packages)
    return [package.lower() for package in tmp]

async def install_pip_packages(packages):
    """Install pip packages."""
    args = ["-m", "pip", "install", "--upgrade", "--user"]
    cmd = await asyncio.create_subprocess_exec(
        sys.executable.replace(" ", "\\ "),
        *args,
        *packages,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    await cmd.communicate()
    return cmd.returncode == 0

def run_async(func: callable):
    """Run async functions with the right event loop."""
    asyncio.get_event_loop()
    return loop.run_until_complete(func)

async def restart_script(client: TelegramClient, sandy):
    """Restart the current script."""
    try:
        ulist = get_collectionlist_items()
        for i in ulist:
            if i == "restart_update":
                del_keyword_collectionlist("restart_update")
    except Exception as e:
        LOGS.error(e)
    try:
        add_to_collectionlist("restart_update", [sandy.chat_id, sandy.id])
    except Exception as e:
        LOGS.error(e)
    executable = sys.executable.replace(" ", "\\ ")
    args = [executable, "-m", "userbot"]
    os.execle(executable, *args, os.environ)
    os._exit(143)

async def get_message_link(client, event):
    chat = await event.get_chat()
    if event.is_private:
        return f"tg://openmessage?user_id={chat.id}&message_id={event.id}"
    return f"https://t.me/c/{chat.id}/{event.id}"


import logging
import random
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponseRedirect

from django.db.models import Q
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from rest_framework.response import Response
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.authentication import TokenAuthentication, SessionAuthentication, BasicAuthentication
from rest_framework.decorators import action

from users.models import User
from .models import Album, Picture, Game, Player
from .utils import check_players
from control.models import Control
from . import serializers

logger = logging.getLogger(__file__)

@api_view(['GET','POST',],)
@permission_classes((IsAuthenticated,))
def pictures(request):
    data = {}

    if request.method == 'POST':
        album = request.data['album_id']
    elif request.method == 'GET':
        album = request.GET.get('album_id')
    else:
        return Response(status.HTTP_400_BAD_REQUEST)

    pictures = Picture.objects.filter(album=album).values()
    pictures_list = []
    for picture in pictures:
        print(f'PICTURE: {picture}')
        serializer = serializers.PicturesSerializer(picture, data=request.data)
        if serializer.is_valid():
            pictures_list.append(picture)
        else:
            print(f'Failed picture serializing. ERROR: {serializer.errors}')
    data['pictures'] = pictures_list
    data['response'] = f'Picture for album: {album}'

    if len(pictures_list) == 0:
        return Response(data='No Pictures', status=status.HTTP_200_OK)
    else:
        return Response(data)

@api_view(['GET',],)
def public_albums(request):
    """Access to public albums
    """
    data = {}
    if request.method == 'GET':
        _public_albums = Album.objects.filter(is_public=True)
        albums_list = []
        for album in _public_albums:
            serializer = serializers.AlbumSerializer(album, data=request.data)
            if serializer.is_valid():
                albums_list.append(serializer.data)
            else:
                print(f'Failed picture serializing. ERROR: {serializer.errors}')
                logger.error(f'Failed picture serializing. ERROR: {serializer.errors}')

        data['response'] = 'Public albums'
        data['albums'] = albums_list
        return Response(data)

@api_view(['POST', 'GET', 'PUT'],)
@permission_classes((IsAuthenticated,))
def albums(request):
    '''
    Retreive albums: either public ones or per user
    API endpoints:
    /api/game/albums/album_id=<ALBUM ID> for particular user album (the one that is logged in)
    /api/game/albums/ for all user albums
    '''
    data = {}
    if request.method == 'GET':
        query = request.GET.get('album_id')

        if query is not None:
            user_album = Album.objects.get(pk=query)
            serializer = serializers.AlbumSerializer(user_album, data=request.data)
            if serializer.is_valid():
                data['response'] = f'User album id {query}'
                data['album'] = serializer.data
                return Response(data)
            else:
                print(f'Failed picture serializing. ERROR: {serializer.errors}')
                data['response'] = f'No album found for id {query}'
                return Response(data)
        else:
            print('>> Getting all user albums')
            user_albums = Album.objects.filter(Q(user=request.user))
            albums_list = []
            for album in user_albums:
                serializer = serializers.AlbumSerializer(album, data=request.data)
                if serializer.is_valid():
                    albums_list.append(serializer.data)
            data['response'] = f'All albums for user: {request.user}'

            # print(f'ERROR GETTNIG ALL ALBUMS')
            # data = serializer.errors
            data['albums'] = albums_list
            return Response(data)

    # Update album
    elif request.method == 'PUT':

        try:
            album = Album.objects.get(album_id=request.GET.get('album_id'))
        except Album.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)

        serializer = serializers.AlbumSerializer(album, data=request.data)
        data = {}
        if serializer.is_valid():
            updated_album = serializer.save()
            data = serializer.data
            data['response'] = 'Update successful'
        else:
            data['response'] = "Update failed."

        return Response(data)

    # Create new album
    elif request.method == 'POST':
        data = {}
        print(f'New Album request: {request.data}')
        album_name = request.data['name']
        user = request.user
        pictures = request.data['pictures']
        board = request.data['board']

        album = Album()
        album.name = album_name
        album.user = user
        album.pictures = pictures
        album.board = board
        album.number_of_pictures = len(pictures[0])
        album.save()

        for pic in pictures[0]:
            image = Picture()
            image.name = pic
            image.album = album
            image.url = pictures[0][f'{pic}']['url']
            image.remove_id = pictures[0][f'{pic}']['remote_id']
            image.save()

        serializer = serializers.AlbumSerializer(album, data=request.data)
        if serializer.is_valid():
            data = serializer.data
        else:
            return Response('ERROR SERIALIZING NEW ALBUM')

        return Response(data)

    return Response(status.HTTP_400_BAD_REQUEST)

    # return Response(data='Images loaded', status=status.HTTP_200_OK)

################ NOT USED ###################
class UserAlbumsView(viewsets.ModelViewSet):
    serializer_class = serializers.AlbumSerializer
    authentication_classes = [TokenAuthentication,]
    permission_classes = (IsAuthenticated,)

    # queryset = Order.objects.all()
    @action(methods=['POST', ], detail=False)
    def get_queryset(self, *args, **kwargs):
        # queryset_list = Album.objects.all()
        user = self.request.user
        queryset_list = queryset_list.filter(Q(user=user))
        print(f'USER {user}  Albums: {queryset_list}')

        return queryset_list

@api_view(['POST',])
@permission_classes((IsAuthenticated,))
def game_create(request):
    data = {}
    # info = {}
    if request.method == 'POST':
        user = request.user
        # album_id = Album.objects.get(user=request.user, name=request.data['album_name'])

        # info['winning_conditions'] = request.data['winning_conditions']
        # info['is_public'] = request.data['is_public']
        # info['prizes'] = request.data['prizes']

        album_id = request.data['album_id']
        album = Album.objects.get(pk=album_id)
        # print(f'ALBUM_SER: {album_ser}')

        serializer = serializers.GameSerializer(data=request.data)

        if serializer.is_valid():
            game = serializer.save()

            game.album = album
            game.pictures_pool = album.pictures
            game.user = user
            game.save()

            data['response'] = "Game is ready"
            data['game_id'] = game.game_id
            data['album_id'] = game.album.pk
            data['winning_conditions'] = game.winning_conditions
            data['is_public'] = game.is_public
            data['prizes'] = game.prizes
            data['user_id'] = user.pk

            return Response(data)
        else:
            data['response'] = "Failed preping the game."
            data['errors'] = serializer.errors
            return Response(data)
    else:
        return Response(status.HTTP_400_BAD_REQUEST)

@api_view(['POST',])
@permission_classes((IsAuthenticated,))
def game_request(request):
    '''
    Calculating the price for the game according to the number of players joined.
    '''
    data = {}
    if request.method == 'POST':

        game = Game.objects.get(user=request.user, game_id=request.data['game_id'])
        game.game_requested = True

        # Collecting the Players
        try:
            players = Player.objects.filter(player_game_id=request.data["game_id"])
            players_list = []
            for player in players:
                player_data = {}
                player_data['nickname'] = player.nickname
                player_data['player_id'] = str(player.player_id)
                players_list.append(player_data)

            game.players_list = players_list

            game.number_of_players = len(players)

            #Setting up the price for the game
            # TODO: Define pricing accurately

            try:
                base_price = Control.objects.get(name='base_price').value_float
            except:
                base_price = 0.1

            if players:
                if len(players) < 21:
                    game_cost = round(len(players) * base_price,2)
                elif len(players) < 41:
                    game_cost = round(len(players) * base_price*0.80,2)
                else:
                    game_cost = round(len(players) * base_price*0.66,2)
            else:
                game_cost = 0

            data['game_cost'] = game_cost
            data['num_of_players'] = len(players)
            game.game_cost = game_cost
            game.save()
            return Response(data)
        except Exception as e:
            print(f'GAME: There are no players. ERROR: {e}')
            logger.error(f'GAME: No players found for this game. ERROR: {e}')
            return Response(status.HTTP_503_SERVICE_UNAVAILABLE)
    else:
        return Response('Bad request', status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET',])
@permission_classes((IsAuthenticated,))
def game_info(request):
    data = {}
    if request.method == 'GET':
        game_id = request.GET.get('game_id')
        user = request.user
        game = Game.objects.get(user=user, game_id=game_id)
        serializer = serializers.GameSerializer(game)
        data = serializer.data
        return Response(data)
    else:
        return Response(status.HTTP_400_BAD_REQUEST)

@api_view(['POST',])
@permission_classes((IsAuthenticated,))
def game_confirm(request):
    '''
    - Host to confirm the game
    - Checking that the user's balanace can cover the cost of the game
    '''
    data = {}
    if request.method == 'POST':
        user = User.objects.get(pk=request.user.pk)
        game = Game.objects.get(user=request.user.pk, game_id=request.data['game_id'])

        # Check user's balance and deduct the amount
        current_balance = user.balance
        game_cost = game.game_cost
        new_balance = current_balance - game_cost
        if new_balance > 0:
            # Updating user new balance
            user.balance = new_balance
            user.save()

            # Start the game
            game.started = True
            game.save()
            data['response'] = 'Game Started'
            return Response(data, status=status.HTTP_200_OK)
        else:
            data['response'] = 'Not enough balance'
            return Response(data)
    else:
        return Response(status.HTTP_400_BAD_REQUEST)

@api_view(['GET',])
@permission_classes((IsAuthenticated,))
def game_play(request):
    '''
    Handles the process for every click on the NEXT button
    1) Get the pictures from the pictures_pool
    2) Get a random picture from the pool
    3) Pop that picture from the pool and write it back to the DB
    4) Check which players met the winning condition
    5) Continue until "BINGO" or untill all pictures were drawn

    Request:
    - game id (error if there is no such game for the user)

    Return:
    - Picture ID for display
    - number of pictures pooled
    - number of pictures left
    - player IDs those who have winning conditions

    '''
    data = {}
    if request.method == 'GET':
        try:
            game_id = request.GET.get('game_id')
            game = Game.objects.get(user=request.user.pk, game_id=game_id)
        except Exception as e:
            print('No such game for this player')
            logger.error(f'No such game for this player. ERROR: {e}')
            return Response('Error game request', status=status.HTTP_400_BAD_REQUEST)

        pictures_pool_dict = game.pictures_pool[0]
        pictures_pool_list = []
        items_list = []

        # Creating a list of all keys in the dict
        if len(pictures_pool_dict) > 0:
            for pic in pictures_pool_dict:
                items_list.append(pic)

            # Drawing a random key from the dict
            picture_draw_index = random.randint(0,len(items_list)-1)
            rand_item = items_list[picture_draw_index]
            picture_draw = pictures_pool_dict.pop(rand_item)

            # Updating the DB with the reduced list of pictures
            pictures_pool_list.append(pictures_pool_dict)
            game.pictures_pool = pictures_pool_list

            current_shown_pictures = game.shown_pictures
            current_shown_pictures.append({rand_item:picture_draw})
            game.shown_pictures = current_shown_pictures

            game.save()

            data['remaining_pictures'] = len(pictures_pool_dict)
            data['picture'] = picture_draw
            data['pic_index'] = rand_item

            # Check the players' boards:
            active_boards = check_players(picture_id=picture_draw['remote_id'], game_id=game_id)
            print(f'ACTIVE BOARDS: {active_boards}')

            picture_draw_id = picture_draw["remote_id"]

            for board in active_boards:
                print(f'>> Pic: {picture_draw_id}')
                print(f'>> B: {board.pictures}')
                x_count_full = 0
                for i in range(board.size):
                    x_count_row = 0

                    # 1) Replace the hits with an X
                    board.pictures[i] = [pic if pic != picture_draw_id else 'X' for pic in board.pictures[i]]

                    # Count the 'X's are on the row
                    x_count_row += board.pictures[i].count('X')
                    if x_count_row == board.size:
                        player = Player.objects.get(board_id=board.pk)
                        player.winnings.append(f'row_{i}')
                        player.save()
                        print(f'BINGO: Player {player.nickname} Row {i} board {board}!!!')

                    # Count the 'X's are on the board
                    x_count_full += board.pictures[i].count('X')

                    # Update the board with the hits
                    board.save()

                    # Reset the row count for the next row
                    x_count_row = 0

                # Columns and diagnals winning condition check
                x_count_diag_left_to_right = 0
                x_count_diag_right_to_left = 0

                for column in range(board.size):
                    player = Player.objects.get(board_id=board.pk)
                    x_count_column = 0

                    for row in range(board.size):
                        if board.pictures[row][column] == 'X':
                            x_count_column += 1
                            player.winnings.append(f'row_{row}_col_{column}')

                    if x_count_column == board.size:
                        player.winnings.append(f'col_{column}')
                        print(f'BINGO: Player {player.nickname} Column {i} board {board}!!!')

                    if board.pictures[column][column] == 'X':
                        x_count_diag_left_to_right += 1

                    if x_count_diag_left_to_right == board.size:
                        player.winnings.append('diag_l2r')
                        print(f'BINGO: Player {player.nickname} Diagonal L2R board {board}!!!')

                    if board.pictures[-column-1][-column-1] == 'X':
                        x_count_diag_right_to_left += 1

                    if x_count_diag_right_to_left == board.size:
                        player.winnings.append('diag_r2l')
                        print(f'BINGO: Player {player.nickname} Diagonal R2L board {board}!!!')

                    player.save()

                # print(f'>> UPDATED B: {board.pictures}')
                # print(f'>> X-FULL Count: {x_count_full}')
                if x_count_full == board.size ** 2:
                    player = Player.objects.get(board_id=board.pk)
                    player.winnings.append('FULL')
                    player.save()
                    print(f'BINGO FULLLLL!!! Player {player.nickname} Board: {board}')

            return Response(data)
        else:
            game.ended = True
            game.is_finished = True
            game.save()

            return Response('Game Finished. No more pictures')
    else:
        print('Bad request at game play')
        logger.error('Bad request at game play')
        return Response(status.HTTP_400_BAD_REQUEST)

@api_view(['GET',])
@permission_classes((IsAuthenticated,))
def game_winnings(request):
    """Checks the winnings for particular player

    Args:
        player_id (str):

    Returns:
        list: List of all the winnings that the player currently has
    """
    if request.method == 'GET':
        winnings_set = set()
        board_id = request.GET.get('board_id')
        game_id = request.GET.get('game_id')
        try:
            player = Player.objects.get(board_id=board_id)
            for win in player.winnings:
                winnings_set.add(win)

            if len(winnings_set) == 0:
                return Response('No winnings')
            else:
                return Response(winnings_set)
        except Exception as e:
            print(f'There is no such player for that game. ERROR: {e}')
            logger.error(f'There is no such player for that game. ERROR: {e}')
            return Response('Player not found.', status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET',])
@permission_classes((IsAuthenticated,))
def get_players(request):
    ''' Getting the current players listed for a game
    '''
    data = {}
    if request.method == 'GET':
        game_id = request.GET.get('game_id')
        print(f'>> API: Accessing players list on game {game_id}')
        game_players = []
        _players = Player.objects.filter(player_game_id=game_id)
        for player in _players:
            player_obj = {}
            player_obj['id'] = player.pk
            player_obj['nickname'] = player.nickname
            player_obj['approved'] = player.approved
            game_players.append(player_obj)
        data['players'] = game_players
        return Response(data)
    else:
        print(f'>> API: Failed Accessing players list')
        return Response(status.HTTP_400_BAD_REQUEST)

@api_view(['GET','PUT',])
@permission_classes((IsAuthenticated,))
def player(request):
    """Get information about a particular player, and update his approved status

    Args:
        player_id (str):
        game_id (str):

    Returns:
        approved: bool
        board_id: str
    """
    if request.method == 'GET':
        player_id = request.GET.get('player_id')
        game_id = request.GET.get('game_id')
        print(f"Getting Player: {player_id}")

        data = {}
        player = Player.objects.get(player_game_id=game_id, pk=player_id)
        data['approved'] = player.approved
        data['board_id'] = player.board_id
        return Response(data)
    elif request.method == 'PUT':
        print(f'PU: {request.data}')
        player_id = request.data['player_id']
        game_id = request.data['game_id']
        player = Player.objects.get(player_game_id=game_id, pk=player_id)
        if request.data['approved'] == 'True':
            player.approved = True
        elif request.data['approved'] == 'False':
            player.approved = False
        else:
            return Response('Bad data formating', status.HTTP_400_BAD_REQUEST)
        player.save()

        return Response(f'Player approved status: {player.approved}', status=status.HTTP_200_OK)
    else:
        return Response(status.HTTP_400_BAD_REQUEST)

#################
# DEMO ONLY
#################

@login_required
def game_control(request):
    context = {}
    if request.method == 'POST':
        if 'gamePrep' in request.POST:
            album = Album.objects.filter(user=request.user).first()
            new_game = Game.objects.create(
                album_id=album,
                user = request.user,
                winning_conditions='ALL',
                is_public=True
            )

            try:
                context['game'] = new_game
                context['album'] = album.name
                context['winning_cond'] = 'ALL'
                context['is_public'] = 'Public Game'
            except Exception as e:
                context['game'] = new_game
                context['album'] = 'There are no albums for this user'
                context['winning_cond'] = 'ALL'
                context['is_public'] = 'Public Game'

            # return redirect('game:game-room', new_game.game_id)

        elif 'startGame' in request.POST:
            # TODO: open a WS on start of game listening to the joining of players
            game = Game.objects.filter(user=request.user).last
            context['game'] = game

        else:
            context['next'] = "NEXT IMAGE"

    #TODO: What happend on game complete?, e.g. is_finished is set to true

    return render(request, 'game/game-control.html', context)

def home(request):
    context = {}
    return render(request, 'game/home.html', context)

def game_room(request, game_id):
    ''' For testing purposes. Room game demo
    '''
    context = {}
    game = Game.objects.get(game_id=game_id)

    if request.method == 'POST':
        if 'requestGame' in request.POST:
            # TODO: Delete game data to oavoid future collisions

            # Setting game to started
            game = Game.objects.get(user=request.user.pk, game_id=game_id)
            game.game_requested = True

            # Collecting the Players
            _players = Player.objects.filter(player_game_id=game_id)
            game.player_list = _players

            game.number_of_players = len(_players)

            #Setting up the price for the game
            # TODO: Define pricing accurately
            if _players:
                if len(_players) < 21:
                    game.game_cost = round(len(_players) * 1/20,2)
                elif len(_players < 41):
                    game.game_cost = round(len(_players) * 1/25,2)
                else:
                    game.game_cost = round(len(_players) * 1/30,2)

            print(f'COST: {game.game_cost}')
            game.save()
        elif 'conirmed' in request.POST:
            user = User.objects.get(pk=request.user.pk)
            game = Game.objects.get(user=request.user.pk, game_id=game_id)
            game.game_requested = False

            # Check user's balance and deduct the amount
            current_balance = user.balance
            game_cost = game.game_cost
            new_balance = current_balance - game_cost
            if new_balance > 0:
                # Updating user new balance
                user.balance = new_balance
                user.save()

                # Start the game
                game.started = True
                game.save()
                print(f'GAME STARTED')

    context['game'] = game

    return render(request, 'game/game_room.html',context)

def players(request, user_id, game_id):
    ''' For generating the dynamic players table created with websocket
    '''
    context = {}
    _players = Player.objects.filter(player_game_id=game_id)
    context['players'] = _players
    return render(request, 'game/players.html', context)


from django import template
from django.template import loader
from django.utils.safestring import mark_safe
from martor.utils import markdownify
import re
register = template.Library()

re_img_tag = re.compile(r'(?P<img_tag>)')
re_attr = re.compile(r'([a-z]+)? *([a-z-]+)="([^"]+)')

img_template = template.loader.get_template('wbcore/content_image.html')

def img_match(match):
    gd = match.groupdict()
    img_tag = gd['img_tag'] if 'img_tag' in gd else ""
    img = {}

    for result in re_attr.findall(img_tag):
        img[result[1]] = result[2]

    src = img['src'] if 'src' in img else None
    if not src:
        return ""

    context = {
        'size': 'medium',
        'side': 'left',
        'src': src,
        'title': img['title'] if 'title' in img else None,
        'alt': img['alt'] if 'alt' in img else None,
    }
    return img_template.render(context)

def insert_ui_elems(field_name):
    #html = re_img_tag.sub(img_match, field_name)
    #html += '

'
    #html += '

'
    return field_name
    #return html

@register.filter
def safe_markdown(field_name):
    """
    Safe the markdown text as html ouput.

    Usage:
        {% load martortags %}
        {{ field_name|safe_markdown }}

    Example:
        {{ post.description|safe_markdown }}
    """
    return mark_safe(insert_ui_elems(markdownify(field_name)))


'''Scorrer for the decision list'''

#Date: 22nd April 2021.
#Amit Raj

import re
import pandas as pd
import sys
import os
import bs4

def extract_line(file):
    with open(file, "r", encoding ='utf-8') as tags:
        dd = tags.read()
        dcode = str(dd).strip()
        dcode = dcode.replace('\n','')
    return dcode

def extract_data(data):
    instances, senses =[],[]
    for vv in bs4.BeautifulSoup(data,'html.parser'):
        instances.append(vv.attrs['instance'])
    for ss in bs4.BeautifulSoup(data, 'html.parser'):
        senses.append(ss.attrs['senseid'])
    return instances, senses

def accuracy(pred_file, gd_file):
	pod,ww = {}, {}

	for vv in bs4.BeautifulSoup(pred_file, "html.parser"):
	    vv.find_all("answer")
	    pod.update({vv.get("instance"):vv.get("senseid")})

	for sppd in bs4.BeautifulSoup(gd_file, "html.parser"):
	    ww.update({sppd.get("instance"):sppd.get("senseid")})

	mnv =0
	for keys1,keys2 in zip(pod.items(), ww.items()):
	    if (keys1 == keys2):
	        mnv+=1

	# print(mnv)
	# print(len(ww))

	accuracy = ((mnv/len(ww)) * 100)
	print("The accuracy of the decision list is :{0}".format(accuracy))
	return pod, ww

#     print 'Not', x_values, y_values
    #     if(list(pod.keys)[i] == list(ww.keys)[i]):
#         if(list(pod.value)[i] == list(ww.value)[i])
#             print("vv")

def confusion_matrix(pod, ww):
	prd_senses = (list(pod.items()))
	gld_senses = (list(ww.items()))

	prd_sens_list,gld_sense_list = [],[]

	for i in range(0, len(pod.keys())):
	    prd_sens_list.append((prd_senses[i][1]))

	for j in range(0, len(pod.keys())):
	    gld_sense_list.append((gld_senses[j][1]))

	# print(pd.Series(prd_sens_list))

	# print(pd.Series(gld_sense_list))

	mMatrix = pd.crosstab(pd.Series(prd_sens_list), pd.Series(gld_sense_list))
	print(mMatrix)

def main():
	predicted = sys.argv[1]
	gold_std_file = sys.argv[2]

	pred_file = extract_line(predicted)

	gd_file = extract_line(gold_std_file)

	dict1, dict2 = accuracy(pred_file,gd_file)

	confusion_matrix(dict1, dict2)

if __name__ == '__main__':
	main()


import numpy as np
from matplotlib import pyplot as plt
from scipy import signal as signal
import math

filename = '/Users/shivani/Downloads/test2.img'
output = '/Users/shivani/Downloads/outputCV.img'

with open(filename , 'rb') as in_file:
    with open(output, 'wb') as out_file:
        out_file.write(in_file.read()[512:])

fo = open(output, 'rb')

#below file will have 512 X 512 image data
Output512 = np.fromfile(output, dtype='uint8', sep="")
Output512 = Output512.reshape([512, 512])

plt.imshow(Output512, cmap='gray')
plt.show()

tempArr = np.copy(Output512)

####### 1. PEAKINESS DETECTION #########
# assign measure of goodness to determine whether to select a combination of peak valleys or not

#generate histogram for the respective image
#a = np.histogram(Output512,bins=1,range=None, normed=None, weights=None, density=None)
#plt.hist(Output512,bins=40)
#plt.show()

histdata = [0] * 256

for x in range(0,512,1):
    for y in range(0,512,1):
        histdata[Output512[x][y]] = histdata[Output512[x][y]] + 1

#selection criteria for peaks
peaks = []
for item in histdata:
    if item >= 2500 : peaks.append(item)

#selection criteria for valleys
valleys = []
for item in histdata:
    if item <= 300 : valleys.append(item)

peakIDX =[]
valleyIDX = []
for item in peaks:
    peakIDX.append(histdata.index(item))

for item in valleys:
    valleyIDX.append(histdata.index(item))

#Measure of goodness criteria
# 1. peaks should be well seperated. distance >= 70
# 2. peaks are dominant as per our criteria
# 3. valleys selected are low enough
# 4. valley should be close to the center between the peaks. +- 5
# 5. calculate measure of goodness =

peaks2 = peaks

finalT = 0
finalp1 = 0
finalp2 = 0
MOG = 0
MOGold = 0
for peak1 in peaks:
    for peak2 in peaks2:
        if peak1 == peak2 :
            pass
        else :
            if abs(histdata.index(peak1) - histdata.index(peak2)) >= 70:
                for valley in valleys:
                    if histdata.index(peak1) <= histdata.index(valley) and histdata.index(peak2) >= histdata.index(valley):
                        centre = math.ceil((histdata.index(peak1) + histdata.index(peak2)) / 2)
                        if histdata.index(valley) <= (centre + 20) and histdata.index(valley) >= (centre - 20):
                            MOG = (abs(histdata.index(peak1) - histdata.index(peak2)) * (peak1 + peak2)/2) / ( histdata.index(valley) )

                            if MOG >= 4000 and MOGold < MOG:
                                finalT = histdata.index(valley)
                                finalp1 = histdata.index(peak1)
                                finalp2 = histdata.index(peak2)
                            MOGold = MOG

if finalT != 0:
    for x in range(0,512,1):
        for y in range(0,512,1):
            if Output512[x][y] >= finalT:
                Output512[x][y] = 255
            else:
                Output512[x][y] = 0

peakinessFinalImage = np.copy(Output512)

####### 2. ITERATIVE #########

Output512 = np.copy(tempArr)

mean = math.ceil(np.mean(Output512))

# define intensity 2D list
masterlist = []
list1 = []
list2 = []
newTempArr = np.copy(Output512)

#plt.imshow(newTempArr, cmap='gray')
#plt.show()

for x in range(0,512,1):
    for y in range(0,512,1):
        if newTempArr[x][y] < mean:
            list1.append(newTempArr[x][y])
        elif newTempArr[x][y] >= mean:
            list2.append(newTempArr[x][y])
masterlist.append(list1)
masterlist.append(list2)

newMean = math.ceil(np.mean(list1))
newMean1 = math.ceil(np.mean(list2))

Tnext = ( newMean + newMean1 ) / 2

oldMean = newMean
oldMean1 = newMean1
Tprev = Tnext
count = 0
while True:
    list1 = []
    list2 = []
    for x in range(0,512,1):
        for y in range(0,512,1):
            if newTempArr[x][y] < Tnext:
                list1.append(newTempArr[x][y])
            else:
                if newTempArr[x][y] >= Tnext:
                    list2.append(newTempArr[x][y])
    newMean = math.ceil(np.mean(list1))
    newMean1 = math.ceil(np.mean(list2))
    Tprev = Tnext
    Tnext = ( newMean + newMean1 ) / 2

    count = count + 1

    if Tnext == Tprev:
        break

for x in range(0,512,1):
    for y in range(0,512,1):
        if newTempArr[x][y] < math.ceil(Tnext):
            newTempArr[x][y] = 0
        elif newTempArr[x][y] >= math.ceil(Tnext):
            newTempArr[x][y] = 255

iterativeOutputArr = np.copy(newTempArr)

####### 3. ADAPTIVE THRESHOLDING #########

Output512 = np.copy(tempArr)

# built dataset for histogram data

histdata = [0] * 256

for x in range(0,512,1):
    for y in range(0,512,1):
        histdata[Output512[x][y]] = histdata[Output512[x][y]] + 1

#divide the image into 256 X 256 blocks i.e into 4 sub-images

subImage1 = np.zeros((256,256),dtype='uint8')
subImage2 = np.zeros((256,256),dtype='uint8')
subImage3 = np.zeros((256,256),dtype='uint8')
subImage4 = np.zeros((256,256),dtype='uint8')

i = 0
j = 0
for x in range(0,256,1):
    for y in range(0,256,1):
        subImage1[i][j] = Output512[x][y]
        j = j + 1
    j = 0
    i = i + 1

i = 0
j = 0
for x in range(256,512,1):
    for y in range(0,256,1):
        subImage2[i][j] = Output512[x][y]
        j = j + 1
    j = 0
    i = i + 1

i = 0
j = 0
for x in range(0,256,1):
    for y in range(256,512,1):
        subImage3[i][j] = Output512[x][y]
        j = j + 1
    j = 0
    i = i + 1

i = 0
j = 0
for x in range(256,512,1):
    for y in range(256,512,1):
        subImage4[i][j] = Output512[x][y]
        j = j + 1
    j = 0
    i = i + 1

# Iterative for subImage1

#built hist-data for subimg1
histdataIMG1 = [0] * 256

for x in range(0,256,1):
    for y in range(0,256,1):
        histdataIMG1[subImage1[x][y]] = histdataIMG1[subImage1[x][y]] + 1

mean = math.ceil(np.mean(subImage1))
list1 = []
list2 = []
newTempArr = np.copy(subImage1)

Tnext = mean

for x in range(0,256,1):
    for y in range(0,256,1):
        if newTempArr[x][y] < Tnext:
            list1.append(newTempArr[x][y])
        else:
            if newTempArr[x][y] >= Tnext:
                list2.append(newTempArr[x][y])

newMean = math.ceil(np.mean(list1))
newMean1 = math.ceil(np.mean(list2))

Tnext = ( newMean + newMean1 ) / 2

oldMean = newMean
oldMean1 = newMean1
Tprev = Tnext
count = 0
while True:
    list1 = []
    list2 = []
    for x in range(0,256,1):
        for y in range(0,256,1):
            if newTempArr[x][y] < Tnext:
                list1.append(newTempArr[x][y])
            else:
                if newTempArr[x][y] >= Tnext:
                    list2.append(newTempArr[x][y])
    newMean = math.ceil(np.mean(list1))
    newMean1 = math.ceil(np.mean(list2))
    Tprev = Tnext
    Tnext = ( newMean + newMean1 ) / 2

    count = count + 1

    if Tnext == Tprev:
        break

for x in range(0,256,1):
    for y in range(0,256,1):
        if newTempArr[x][y] < math.ceil(Tnext):
            newTempArr[x][y] = 0
        elif newTempArr[x][y] >= math.ceil(Tnext):
            newTempArr[x][y] = 255

#plt.imshow(newTempArr, cmap='gray')
#plt.show()

opsubImage1 = np.copy(newTempArr)

# Iterative for subImage2

# built hist-data for subimg2
histdataIMG2 = [0] * 256

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        histdataIMG2[subImage2[x][y]] = histdataIMG2[subImage2[x][y]] + 1

mean = math.ceil(np.mean(subImage2))
list1 = []
list2 = []
newTempArr = np.copy(subImage2)

Tnext = mean

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        if newTempArr[x][y] < Tnext:
            list1.append(newTempArr[x][y])
        else:
            if newTempArr[x][y] >= Tnext:
                list2.append(newTempArr[x][y])

newMean = math.ceil(np.mean(list1))
newMean1 = math.ceil(np.mean(list2))

Tnext = (newMean + newMean1) / 2

oldMean = newMean
oldMean1 = newMean1
Tprev = Tnext
count = 0
while True:
    list1 = []
    list2 = []
    for x in range(0, 256, 1):
        for y in range(0, 256, 1):
            if newTempArr[x][y] < Tnext:
                list1.append(newTempArr[x][y])
            else:
                if newTempArr[x][y] >= Tnext:
                    list2.append(newTempArr[x][y])
    newMean = math.ceil(np.mean(list1))
    newMean1 = math.ceil(np.mean(list2))
    Tprev = Tnext
    Tnext = (newMean + newMean1) / 2

    count = count + 1

    if Tnext == Tprev:
        break

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        if newTempArr[x][y] < math.ceil(Tnext):
            newTempArr[x][y] = 0
        elif newTempArr[x][y] >= math.ceil(Tnext):
            newTempArr[x][y] = 255

#plt.imshow(newTempArr, cmap='gray')
#plt.show()

opsubImage2 = np.copy(newTempArr)

# Iterative for subImage3

# built hist-data for subimg3
histdataIMG3 = [0] * 256

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        histdataIMG3[subImage3[x][y]] = histdataIMG3[subImage3[x][y]] + 1

mean = math.ceil(np.mean(subImage3))
list1 = []
list2 = []
newTempArr = np.copy(subImage3)

Tnext = mean

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        if newTempArr[x][y] < Tnext:
            list1.append(newTempArr[x][y])
        else:
            if newTempArr[x][y] >= Tnext:
                list2.append(newTempArr[x][y])

newMean = math.ceil(np.mean(list1))
newMean1 = math.ceil(np.mean(list2))

Tnext = (newMean + newMean1) / 2

oldMean = newMean
oldMean1 = newMean1
Tprev = Tnext
count = 0
while True:
    list1 = []
    list2 = []
    for x in range(0, 256, 1):
        for y in range(0, 256, 1):
            if newTempArr[x][y] < Tnext:
                list1.append(newTempArr[x][y])
            else:
                if newTempArr[x][y] >= Tnext:
                    list2.append(newTempArr[x][y])
    newMean = math.ceil(np.mean(list1))
    newMean1 = math.ceil(np.mean(list2))
    Tprev = Tnext
    Tnext = (newMean + newMean1) / 2

    count = count + 1

    if Tnext == Tprev:
        break

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        if newTempArr[x][y] < math.ceil(Tnext):
            newTempArr[x][y] = 0
        elif newTempArr[x][y] >= math.ceil(Tnext):
            newTempArr[x][y] = 255

#plt.imshow(newTempArr, cmap='gray')
#plt.show()

opsubImage3 = np.copy(newTempArr)

# Iterative for subImage4

# built hist-data for subimg4
histdataIMG4 = [0] * 256

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        histdataIMG4[subImage4[x][y]] = histdataIMG4[subImage4[x][y]] + 1

mean = math.ceil(np.mean(subImage4))
list1 = []
list2 = []
newTempArr = np.copy(subImage4)

Tnext = mean

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        if newTempArr[x][y] < Tnext:
            list1.append(newTempArr[x][y])
        else:
            if newTempArr[x][y] >= Tnext:
                list2.append(newTempArr[x][y])

newMean = math.ceil(np.mean(list1))
newMean1 = math.ceil(np.mean(list2))

Tnext = (newMean + newMean1) / 2

oldMean = newMean
oldMean1 = newMean1
Tprev = Tnext
count = 0
while True:
    list1 = []
    list2 = []
    for x in range(0, 256, 1):
        for y in range(0, 256, 1):
            if newTempArr[x][y] < Tnext:
                list1.append(newTempArr[x][y])
            else:
                if newTempArr[x][y] >= Tnext:
                    list2.append(newTempArr[x][y])
    newMean = math.ceil(np.mean(list1))
    newMean1 = math.ceil(np.mean(list2))
    Tprev = Tnext
    Tnext = (newMean + newMean1) / 2

    count = count + 1

    if Tnext == Tprev:
        break

for x in range(0, 256, 1):
    for y in range(0, 256, 1):
        if newTempArr[x][y] < math.ceil(Tnext):
            newTempArr[x][y] = 0
        elif newTempArr[x][y] >= math.ceil(Tnext):
            newTempArr[x][y] = 255

#plt.imshow(newTempArr, cmap='gray')
#plt.show()

opsubImage4 = np.copy(newTempArr)

# consolidate the sub-images

outputImage = np.zeros((512,512),dtype='uint8')

#copy subimage 1
for x in range(0,256,1):
    for y in range(0,256,1):
        outputImage[x][y] = opsubImage1[x][y]

#copy subimage 2
x = 0
y = 0

for i in range(256,512,1):
    for j in range(0,256,1):
        outputImage[i][j] = opsubImage2[x][y]
        y = y + 1
    x = x + 1
    y = 0

#copy subimage 3
x = 0
y = 0

for i in range(0,256,1):
    for j in range(256,512,1):
        outputImage[i][j] = opsubImage3[x][y]
        y = y + 1
    x = x + 1
    y = 0

#copy subimage 4
x = 0
y = 0

for i in range(256,512,1):
    for j in range(256,512,1):
        outputImage[i][j] = opsubImage4[x][y]
        y = y + 1
    x = x + 1
    y = 0

adaptiveOutputArr = np.copy(outputImage)

####### 4. DUAL THRESHOLDING #########

Output512 = np.copy(tempArr)

#generate histogram for the respective image

histdata = [0] * 256

for x in range(0,512,1):
    for y in range(0,512,1):
        histdata[Output512[x][y]] = histdata[Output512[x][y]] + 1

firstHALF = [0] * 256
secondHALF = [0] * 256
for x in range(0,256,1):
    if x >= 0 and x <= 127:
        firstHALF[x] = histdata[x]
    else:
        secondHALF[x] = histdata[x]

max2half = np.max(secondHALF)

T1 = math.ceil(np.mean(Output512))
T2 = histdata.index(max2half)

#patition the image into three regions
#   R1  -   < T1
#   R2  -   T1<= x <= T2
#   R3  -   > T2

region1 = np.zeros((512,512),dtype='uint8')
region2 = np.zeros((512,512),dtype='uint8')
region3 = np.zeros((512,512),dtype='uint8')

for x in range(0,512,1):
    for y in range(0,512,1):
        if Output512[x][y] < T1:
            region1[x][y] = Output512[x][y]
            if Output512[x][y] == 0 : region1[x][y] = 1
        else:
            if Output512[x][y] >= T1 and Output512[x][y] <= T2:
                region2[x][y] = Output512[x][y]
            else:
                if Output512[x][y] > T2:
                    region3[x][y] = Output512[x][y]

# visit each pixel in R2 and if pixel has 4- nieghborhood belonging to R1 then assign pixel to R1

for x in range(0,512,1):
    for y in range(0,512,1):
        if region2[x][y] != 0 :
            if (x-1)>= 0 and (y-1) >=0 and (x+1) <= 511 and (y+1) <=511:
                if (region1[x - 1][y] != 0) and (region1[x][y + 1] != 0) and (region1[x][y - 1] != 0) and (
                    region1[x][y + 1] != 0) :
                    region2[x][y] = 0

# all the pixels from R2 which are not in R1 should be assigned to R3
for x in range(0,512,1):
    for y in range(0,512,1):
        if region2[x][y] != 0 :
            region3[x][y] = region2[x][y]
            region2[x][y] = 0

for x in range(0,512,1):
    for y in range(0,512,1):
        if region1[x][y] !=0 :
            region1[x][y] = 255
        else:
            region1[x][y] = 0

dualTOutputArr = np.copy(region1)

#display all four togehther

w=10
h=10
fig=plt.figure(figsize=(8, 8))
columns = 2
rows = 2

fig.add_subplot(rows, columns, 1)
plt.title('Peakiness Detection')
plt.imshow(peakinessFinalImage, cmap='gray')

fig.add_subplot(rows, columns, 2)
plt.title('Iterative Thresholding')
plt.imshow(iterativeOutputArr, cmap='gray')

fig.add_subplot(rows, columns, 3)
plt.title('Adaptive Thresholding')
plt.imshow(adaptiveOutputArr, cmap='gray')

fig.add_subplot(rows, columns, 4)
plt.title('Dual Thresholding')
plt.imshow(dualTOutputArr, cmap='gray')

plt.show()


#!/user/bin/env python

import click
import datetime
import logging
import os
import sys
import re
from collections import defaultdict
import csv
import glob
from tools.emailer import email_general
import csv
from sample_sheet import SampleSheet
from benedict import benedict
import subprocess
import pandas as pd
import itertools

@click.command()
@click.option('--logdir',
              default='/medstore/logs/pipeline_logfiles/sars-cov-2-typing/weekly_report',
              help='Path/to/logfile/directory, uses default if path not specified')
@click.option('--articdir',
              default='/medstore/results/clinical/SARS-CoV-2-typing/artic_results',
              help='Path/to/artic/results/directory, uses default if path not specified')
@click.option('--nextseqdir',
              default='/medstore/results/clinical/SARS-CoV-2-typing/nextseq_data',
              help='Path/to/nextseq_data/directory, uses default if path not specified')
@click.option('--eurofinsdir',
              default='/medstore/results/clinical/SARS-CoV-2-typing/eurofins_data/goteborg',
              help='Path/to/eurofind_data/directory, uses default if path not specified')
@click.option('-o', '--outfile', required=True,
              help='Path/to/output/file')
@click.option('-c', '--config', default='weekly_report_config.yaml',
              help='Path/to/config/file')
@click.option('--converter', default='/apps/bio/scripts/csv2xls',
              help='Path/to/csv2xls/script')
@click.option('--send-email', is_flag=True,
              help='Send results as e-mail')
@click.option('--debug', is_flag=True,
              help='Print debug information.')
@click.option('--uploadedsamples', default='/medstore/results/clinical/SARS-CoV-2-typing/nextseq_data/gensam_upload/reports/Samples_to_gensam.csv',
              help='Path/to/gensam/uploaded/samples/report')

def main (logdir, articdir, nextseqdir, eurofinsdir, outfile, send_email, config, debug, converter,uploadedsamples):
    #Set up the logfile and start loggin
    now = datetime.datetime.now()
    logfile = os.path.join(logdir, "weekly_" + now.strftime("%y%m%d_%H%M%S") + ".log")
    logger = setup_logger('weekly', logfile)
    logger.info('Starting the weekly report workflow.')

    #Load in the config file
    conf_dict = load_config(logger, config)
    if debug: logger.debug(f"CONFIG: {conf_dict.items()}")

    #Find all artic results (in-house sequencing)
    artic_results = find_inhouseruns(articdir)

    logger.info(f'The following in-house runs were found: {" ".join(artic_results)}')

    #Find number of samples for in-house run
    inhouse_dict = defaultdict(lambda: defaultdict(dict))
    for run_name in artic_results:
        #Find which week the run belongs to
        rundate = run_name.split("_")[0]
        runyear = rundate[:2]
        runweek_str = str(datetime.datetime.strptime(rundate, '%y%m%d').isocalendar()[1])
        runweek = f"20{runyear}_{runweek_str}"

        #Find number of samples for in-house run
        logger.info(f'Processing run {run_name}')

        #Open the QC CSV file and parse
        qc_csv = os.path.join(articdir, run_name, run_name + ".qc.csv")
        with open(qc_csv, 'r') as read_obj:
            csv_handler = csv.reader(read_obj)
            #Skip header
            next(csv_handler)
            for row in csv_handler:
                samplename = row[0].split("_")[0]
                sample_status = row[-1]
                #Skip controls etc
                if samplename.lower().startswith(("neg","pos")):
                    inhouse_dict[runweek][run_name][samplename] = "CONTROL"
                #Save non control samples in dict
                else:
                    inhouse_dict[runweek][run_name][samplename] = sample_status

        #Get the metadata about type of samples from samplesheet
        sheetpath = os.path.join(nextseqdir, run_name, "metadata", "SampleSheet.csv")
        if os.path.exists(sheetpath):
            crit_dict = sample_sheet_criteria(sheetpath, inhouse_dict, runweek, run_name)
            inhouse_dict[runweek][run_name]['criteria'] = [str(crit_dict['general']), str(crit_dict['selection']), str(crit_dict['unknown'])]
        else:
            logger.error(f"Can not find SampleSheet for {run_name}")

        #Calc number of samples which passed QC and also total numer
        num_passed_qc = sum(x == "TRUE" for x in inhouse_dict[runweek][run_name].values())
        tot_samples = sum(x == "TRUE" or x == "FALSE" for x in inhouse_dict[runweek][run_name].values())

        tot_criteria = sum(crit_dict.values())
        if tot_samples != tot_criteria:
            logger.warning(f"Sum of selection criteria ({tot_criteria}) not equal to total number of samples ({tot_samples})")

        #Get all the fasta files
        fastadir = os.path.join(nextseqdir, run_name, 'fasta')
        #Check if there is a fastadir, if not ignore.
        #This could be due to the pipeline having started
        #for this sample, but haven't finished
        if os.path.exists(fastadir):
            run_num_fastas = get_num_fasta(fastadir, '.fa')
            inhouse_dict[runweek][run_name]['fastas'] = run_num_fastas

            if run_num_fastas == 0:
                logger.warning(f'Could not find any fasta files for {run_name}')
            elif run_num_fastas != num_passed_qc:
                logger.warning(f'Number of passed samples and number of fasta files does not match')
        else:
            logger.warning(f'No fasta directory found for run: {run_name}. Pipeline still not finished?')
            continue

        #Get all the fastq files
        fastqdir = os.path.join(nextseqdir, run_name, 'fastq')
        #Check if there is a fastqdir, if not ignore.
        #This could be due to the pipeline having started
        #for this sample, but haven't finished
        if os.path.exists(fastqdir):
            run_num_fastqs = get_num_fasta(fastqdir, '.fastq.gz')
            inhouse_dict[runweek][run_name]['fastqs'] = run_num_fastqs
            if run_num_fastqs == 0:
                logger.warning(f'Could not find any fastq files for {run_name}')
            elif run_num_fastqs != tot_samples*2:
                logger.warning(f'Total number of samples is not equal to number of fastq/2')
        else:
            logger.warning(f'No fastq directory found for run: {run_name}. Pipeline still not finished?')
            continue

        #Find all pangolin types for nextseq runs
        #First check that the pangolin dir exists
        lineagepath = os.path.join(nextseqdir, run_name, 'lineage',run_name + "_lineage_report.txt")
        if os.path.exists(lineagepath):
            inhouse_dict[runweek][run_name]['lineages'] = get_pangolin_types(lineagepath, ',')
            run_num_pangos = sum(inhouse_dict[runweek][run_name]['lineages'].values())
            if run_num_pangos != num_passed_qc:
                logger.warning(f'Number of pangolin classifications does not match number of QC passed samples')
        else:
            logger.warning(f'No lineage dir found for run: {run_name}. Pipeline still not finished?')

    #Per week results if debug
    if debug:
        for week in inhouse_dict:
            num_runs = len(inhouse_dict[week])
            runs = ",".join(inhouse_dict[week].keys())
            logger.debug(f"Week {week}: runs({num_runs}, {runs} )")

    #Find all eurofins samples which have been sequenced
    eurofins_batches = find_eurofinsruns(eurofinsdir)
    logger.info(f'Processing Eurofins data. Found {len(eurofins_batches)} batches')

    #Number of samples
    eurofins_dict = defaultdict(lambda: defaultdict(dict))
    for batch in eurofins_batches:
        batchdate = "-".join(batch.split("-")[0:3])
        batch_year = batchdate.split("-")[0]
        batchweek_str = str(datetime.datetime.strptime(batchdate, '%Y-%m-%d').isocalendar()[1])
        batchweek = f"{batch_year}_{batchweek_str}"
        batchpath = os.path.join(eurofinsdir, batch)

        #Count all the fasta samples
        run_num_samples = len(glob.glob1(batchpath, "*consensus.fasta"))
        if run_num_samples == 0:
            logger.warning(f'Could not find any fasta files for {batch}')
            continue
        else:
            eurofins_dict[batchweek][batch]['fastas'] = run_num_samples

        #Number of all different pangolin types
        lineagefiles = glob.glob1(batchpath, "*lineage_classification.txt")

        #Trim the list of lineages files if there are multiples
        if len(lineagefiles) == 0:
            logger.warning(f'Could not find any pangolin types for {batch}')
            continue
        elif len(lineagefiles) > 1:
            lineagefiles = trimlineages(lineagefiles)

        #Get all strains
        lineagepath = os.path.join(eurofinsdir, batch, lineagefiles[0])
        eurofins_dict[batchweek][batch]['lineages'] = get_pangolin_types(lineagepath, '\t')

        #Check if same number of fastas as strains
        sum_fastas = eurofins_dict[batchweek][batch]['fastas']
        sum_lineages = sum(eurofins_dict[batchweek][batch]['lineages'].values())
        if sum_fastas != sum_lineages:
            logger.warning(f'Sum of fasta files and strains do not match in {batch}')

    #Make an output file (csv + excel)
    #Probably keep appending to the same old file
    logger.info(f'Writing data to {outfile}')

    #Open the output file
    try:
        outf = open(outfile, "w")
    except:
        logger.error(f'Could not open {outfile} for writing output.')

    #Write the data from nextseq
    write_nextseq(inhouse_dict, outf, logger, conf_dict)

    # Write the data from eurofins
    write_eurofins(eurofins_dict, outf, logger, conf_dict)

    #Write any notes that exists to the output
    write_notes(outf, logger, conf_dict)
    #Close the output file in case it should be sent as e-mail

    #Write data  based on uploaded samples to FHM
    write_uploaded_samples(uploadedsamples, outf)

    outf.close()

    #Convert output file to excel format
    logger.info(f"Converting {outfile} to xlsx format.")
    out_excel = os.path.splitext(outfile)[0]+'.xlsx'
    call_list = [converter, outfile, "-o", out_excel, "--tsv"]
    subprocess.run(call_list)
    #Send an e-mail if flagged to do
    if send_email:
        recipients = []
        if "emails" in conf_dict or len(conf_dict.keys()) < 1:
            recipients = conf_dict['emails'].values()

            logger.info(f'Sending e-mail to {", ".join(recipients)}')

            # Set up an e-mail
            msg_to = recipients
            msg_from = "clinicalgenomics@gu.se"
            message_subject = 'COVIDSeq in-house sequencing results'
            message_body = 'The latest pangolin types from the COVIDseq can be found in the attached file.'
            attachment = out_excel
            email_general(msg_to, msg_from, message_subject, message_body, attachment)

        else:
            logger.warning(f"E-mails requested but {config} does not contain en e-mail section, or it is empty. Skipping sedning e-mail.")

def load_config (logger, config):
    #Check that the config exists
    logger.info(f"Loading config file {config}")
    if os.path.exists(config):
        config_dict = benedict.from_yaml(config, keypath_separator=None)
    else:
        logger.error(f"Config file {config} does not exist. Exiting.")
        sys.exit(1)

    return config_dict

def write_notes(outf, logger, conf_dict):
    #Check if there are notes, if so write them
    if 'notes' in conf_dict and len(conf_dict['notes']) > 0:
        for week in conf_dict['notes']:
            week_notes = (conf_dict['notes'][week])
            outf.write(f"Week {week}: {week_notes}\n")
    else:
        pass

def write_eurofins(eurofins_dict, outf, logger, conf_dict):
    #Print header
    outf.write('Eurofins sequencing\n')
    headers = ['Year', 'Week', 'Batches', 'Sequenced Genomes']
    outf.write('\t'.join(headers) + "\t")

    #Find all strains sequenced so far
    all_strains = sorted(liststrains(eurofins_dict))

    #Add annotation to variants of concern
    #Load in the variants from config file
    if 'variants' not in conf_dict:
        logger.warning("No variants detected in config file. Skipping annotation for eurofins samples.")
        outf.write("\t".join(all_strains) + "\n")
    else:
        annot_strains = []
        for strain in all_strains:
            if strain in conf_dict['variants']:
                new_strain = strain + "(" + conf_dict['variants'][strain] + ")"
                annot_strains.append(new_strain)
            else:
                annot_strains.append(strain)

        outf.write("\t".join(annot_strains) + "\n")

    #Print eurofins for all weeks
    for week in eurofins_dict:
        num_runs = len(eurofins_dict[week])
        num_fastas = 0
        for batch in eurofins_dict[week]:
            num_fastas += eurofins_dict[week][batch]['fastas']

        num_strains = strain_nums(all_strains, eurofins_dict, week)

        run_year = str(week).split("_")[0]
        run_week = str(week).split("_")[1]

        outf.write(f'{run_year}\t{run_week}\t{num_runs}\t{num_fastas}')
        for strain in sorted(num_strains):
            outf.write(f'\t{num_strains[strain]}')
        outf.write("\n")

def write_nextseq(inhouse_dict, outf, logger, conf_dict):
    #Print header
    outf.write('In-House sequencing\n')
    headers = ['Year', 'Week', 'Runs', 'Sequenced Genomes', 'Passed QC', 'Allmän,Riktad,Unknown']
    outf.write("\t".join(headers) + "\t")
    #Find all strains sequenced so far
    all_strains = sorted(liststrains(inhouse_dict))

    #Load in the variants from config file
    if 'variants' not in conf_dict:
        logger.warning("No variants detected in config file. Skipping annotation for in-house samples.")
        outf.write("\t".join(all_strains) + "\n")
    else:
        annot_strains = []
        for strain in all_strains:
            if strain in conf_dict['variants']:
                new_strain = strain + "(" + conf_dict['variants'][strain] + ")"
                annot_strains.append(new_strain)
            else:
                annot_strains.append(strain)

        outf.write("\t".join(annot_strains) + "\n")

    #Print nextdata for all weeks
    for week in inhouse_dict:
        num_runs = len(inhouse_dict[week])
        tot_samples = 0
        num_passed_qc = 0
        criteria_general = 0
        criteria_selection = 0
        criteria_unknown = 0

        for run_name in inhouse_dict[week]:
            tot_samples += sum(x == "TRUE" or x == "FALSE" for x in inhouse_dict[week][run_name].values())
            num_passed_qc += sum(x == "TRUE" for x in inhouse_dict[week][run_name].values())

            num_strains = strain_nums(all_strains, inhouse_dict, week)
            criteria_general += int(inhouse_dict[week][run_name]['criteria'][0])
            criteria_selection += int(inhouse_dict[week][run_name]['criteria'][1])
            criteria_unknown += int(inhouse_dict[week][run_name]['criteria'][2])

        criteria = ",".join([str(criteria_general), str(criteria_selection), str(criteria_unknown)])

        run_year = str(week).split("_")[0]
        run_week = str(week).split("_")[1]

        outf.write(f'{run_year}\t{run_week}\t{num_runs}\t{tot_samples}\t{num_passed_qc}\t{criteria}')
        #If a note exists about the week, print an asterisk
        if week in conf_dict['notes']:
            outf.write('*')

        for strain in sorted(num_strains):
            outf.write(f'\t{num_strains[strain]}')

        outf.write("\n")

def trimlineages(lineage_list):
    for element in lineage_list:
        if element.startswith('20'):
            lineage_list.remove(element)

    return lineage_list

def strain_nums(strainlist, nextseq_dict, week):
    #Build a dict with all seen strains
    straindict = {}
    for strain in strainlist:
        straindict[strain] = 0

    #for week in nextseq_dict:
    for run_name in nextseq_dict[week]:
        if 'lineages' in nextseq_dict[week][run_name].keys():
            for strain in nextseq_dict[week][run_name]['lineages']:
                straindict[strain] += nextseq_dict[week][run_name]['lineages'][strain]

    return straindict

def liststrains(nextseq_dict):
    strains = []
    for week in nextseq_dict:
        for run_name in nextseq_dict[week]:
            if 'lineages' in nextseq_dict[week][run_name].keys():
                for strain in nextseq_dict[week][run_name]['lineages']:
                    if not strain in strains:
                        strains.append(strain)
    return strains

def get_pangolin_types (lineagepath, delim):
    pango_dict = {}
    #Collect number of each found strain
    with open(lineagepath) as csv_file:
        next(csv_file) #Skip header
        csv_handler = csv.reader(csv_file, delimiter=delim)
        for row in csv_handler:
            taxon = row[0]
            strain = row[1]
            #Skip negative controls
            if taxon.lower().startswith('consensus_neg'):
                continue
            #Skip positive controls
            elif taxon.lower().startswith('consensus_pos'):
                continue
            elif strain.lower().startswith('none'):
                continue
            else:
                if strain in pango_dict:
                    pango_dict[strain] += 1
                else:
                    pango_dict[strain] = 1

    return pango_dict

def get_num_fasta (fastadir, suffix):
    num_fasta = 0
    for fasta in os.listdir(fastadir):
        if not fasta.lower().startswith(('neg', 'pos')) \
                and fasta.lower().endswith(suffix):
            num_fasta += 1
    return num_fasta

def find_inhouseruns (datadir):
    dir_list = []
    #Find all runs in folder
    for dirname in next(os.walk(datadir))[1]:
        if re.match('^2[1-4]', dirname) and len(dirname.split("_")) == 4:
            dirdate = dirname.split("_")[0]
            dir_list.append(dirname)

    return dir_list

def find_eurofinsruns (nextseqdir):
    dir_list = []
    #Find all runs in folder
    for dirname in next(os.walk(nextseqdir))[1]:
        # Exclude this file as it is duplicate data
        if dirname[0].isdigit():
            dir_list.append(dirname)

    return dir_list

def sample_sheet_criteria(path, inhouse_dict, week, run_name):
    Sheet = SampleSheet(path)
    data = {}
    data['general'] = 0
    data['selection'] = 0
    data['unknown'] = 0
    for sample in Sheet.samples:
        sample_name = sample['Sample_ID']
        description = sample['Description']

        # Skip controls or if not in dict
        if sample_name.lower().startswith(('neg', 'pos')):
            continue
        elif sample_name not in inhouse_dict[week][run_name].keys():
            continue
        else:
            #Check if the description field is correct lenght, and sanity for criterion
            criterion = description.split("_")[-1]
            if len(description.split('_')) == 15 and criterion.isdigit() and int(criterion) <= 10:
                if int(criterion) == 1 or int(criterion) == 8 or int(criterion) == 9:
                    data['general'] += 1
                elif int(criterion) == 7:
                    data['unknown'] += 1
                else:
                    data['selection'] += 1
            else:
                data['unknown'] += 1

    return data

def setup_logger(name, log_path=None):
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)

    stream_handle = logging.StreamHandler()
    stream_handle.setLevel(logging.DEBUG)
    stream_handle.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
    logger.addHandler(stream_handle)

    if log_path:
        file_handle = logging.FileHandler(log_path, 'a')
        file_handle.setLevel(logging.DEBUG)
        file_handle.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
        logger.addHandler(file_handle)

    return logger

def write_uploaded_samples(uplodedSamplesFile, outf):
    outf.write('\nUploaded fasta-files to Gensam \n')
    Samples= pd.read_csv(uplodedSamplesFile, sep=',')
    Samples[['year', 'month', 'day']] = Samples.upload_date.str.split("-",expand=True)
    Samples['year_week'] = Samples[['year', 'upload_week']].astype(str).agg('_'.join, axis=1)
    df = Samples.groupby(['year_week','selection_criteria','upload_week','sequencing_week', 'fasta']).size().reset_index(name='counts')

    data = {}
    weeks= df['year_week'].unique().tolist()
    for week in weeks:
        run_week = str(week).split("_")[1]
        run_year = str(week).split("_")[0]
        data[week] ={'Year': run_year, 'Week': run_week, 'general':0, 'unknown':0, 'selection':0, 'Non-negative' :0, '#':'#', 'total_general':0, 'total_unknown':0, 'total_selection':0, 'total' :0}
    for index,row in df.iterrows():
        if str(row['selection_criteria']).isdigit() and row['fasta'] == 'uploaded':
            if row['selection_criteria'] == 1 or  row['selection_criteria'] == 8 or row['selection_criteria'] == 9:
                data[row['year_week']]['general'] += row['counts']
            elif row['selection_criteria'] == 7:
                data[row['year_week']]['unknown'] += row['counts']
            else:
                data[row['year_week']]['selection'] += row['counts']
        elif row['fasta'] == 'uploaded':
            data[row['year_week']]['unknown'] += row['counts']

    for index, row in df.iterrows():
        if str(row['selection_criteria']).isdigit():
            if row['selection_criteria'] == 1 or  row['selection_criteria'] == 8 or row['selection_criteria'] == 9:
                data[row['year_week']]['total_general'] += row['counts']
            elif row['selection_criteria'] == 7:
                data[row['year_week']]['total_unknown'] += row['counts']
            else:
                data[row['year_week']]['total_selection'] += row['counts']
        else:
            data[row['year_week']]['total_unknown'] += row['counts']

        # add a total value of all of uploaded samples
        data[row['year_week']]['Non-negative'] = data[row['year_week']]['unknown'] + data[row['year_week']]['selection'] + data[row['year_week']]['general']
        data[row['year_week']]['total'] = data[row['year_week']]['total_unknown'] + data[row['year_week']]['total_selection'] + data[row['year_week']]['total_general']
    # Read data into a dataframe, group by upload week, and sum the values
    df = pd.DataFrame.from_dict(data).T
    # Write dataframe to outputfile
    df.to_csv(outf, sep='\t', index=False)

if __name__ == '__main__':
    main()


import logging
from datetime import timedelta
from functools import lru_cache
from typing import Any, Dict, List

import aiofiles
from asgi_correlation_id import CorrelationIdMiddleware
from asgi_correlation_id.context import correlation_id
from fastapi import Depends, FastAPI, HTTPException, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exception_handlers import http_exception_handler
from fastapi.responses import HTMLResponse, JSONResponse, ORJSONResponse
from fastapi.security import OAuth2PasswordRequestForm
from fastapi.staticfiles import StaticFiles
from timing_asgi import TimingClient, TimingMiddleware
from timing_asgi.integrations import StarletteScopeToName

from ucsschool.lib.models.attributes import ValidationError as SchooLibValidationError
from ucsschool.lib.models.base import NoObject
from ucsschool.lib.models.utils import env_or_ucr, get_file_handler
from ucsschool.lib.models.validator import VALIDATION_LOGGER
from udm_rest_client import UdmError

from .config import UDM_MAPPING_CONFIG, load_configurations
from .constants import (
    APP_VERSION,
    DEFAULT_LOG_LEVELS,
    LOG_FILE_PATH,
    STATIC_FILE_CHANGELOG,
    STATIC_FILE_README,
    STATIC_FILES_PATH,
    URL_API_PREFIX,
    URL_TOKEN_BASE,
)
from .import_config import get_import_config
from .ldap import check_auth_and_get_user
from .opa import OPAClient
from .routers import role, school, school_class, user, workgroup
from .token_auth import Token, create_access_token, get_token_ttl

@lru_cache(maxsize=1)
def get_logger() -> logging.Logger:
    return logging.getLogger(__name__)

app = FastAPI(
    title="Kelvin API",
    description="UCS@school Kelvin REST API",
    version=str(APP_VERSION),
    docs_url=f"{URL_API_PREFIX}/docs",
    redoc_url=f"{URL_API_PREFIX}/redoc",
    openapi_url=f"{URL_API_PREFIX}/openapi.json",
    default_response_class=ORJSONResponse,
)
app.add_middleware(CorrelationIdMiddleware)
logger = get_logger()

class PrintTimings(TimingClient):
    def timing(self, metric_name, timing, tags):
        logger.warning(f"{metric_name} - {timing:.3f} s - {tags}")

app.add_middleware(
    TimingMiddleware,
    client=PrintTimings(),
    metric_namer=StarletteScopeToName(prefix="kelvin_app", starlette_app=app),
)

class ValidationDataFilter(logging.Filter):
    def filter(self, record):
        return record.name != VALIDATION_LOGGER

@app.on_event("shutdown")
async def shutdown_opa_client() -> None:
    await OPAClient.shutdown_instance()

@app.on_event("startup")
def setup_logging() -> None:
    min_level = env_or_ucr("ucsschool/kelvin/log_level")
    if min_level not in ("DEBUG", "INFO", "WARNING", "ERROR"):
        min_level = logging.ERROR
    min_level = logging._checkLevel(min_level)
    abs_min_level = min_level
    for name, default_level in DEFAULT_LOG_LEVELS.items():
        logger = logging.getLogger(name)
        logger.setLevel(min(default_level, min_level))
        abs_min_level = min(min_level, logger.level)

    file_handler = get_file_handler(abs_min_level, str(LOG_FILE_PATH))
    file_handler.addFilter(ValidationDataFilter())
    logger = logging.getLogger("uvicorn.access")
    logger.addHandler(file_handler)
    logger = logging.getLogger()
    logger.setLevel(abs_min_level)
    logger.addHandler(file_handler)

@app.exception_handler(UdmError)
async def udm_exception_handler(request: Request, exc: UdmError) -> ORJSONResponse:
    """Format unhandled udm exceptions and return in a standard JSON format"""

    error_type = f"UdmError:{exc.__class__.__name__}"
    errors: List[Dict[str, Any]]
    if exc.error is not None:
        errors = [
            {"loc": (location,), "msg": message, "type": error_type}
            for (location, message) in exc.error.items()
        ]
    elif exc.reason is not None:
        errors = [{"loc": (), "msg": exc.reason, "type": error_type}]
    else:
        errors = [{"loc": (), "msg": str(exc), "type": error_type}]

    status_code = exc.status or 500

    logger.error(f"Encountered exception {exc} responding with {errors}")

    return ORJSONResponse(
        content=jsonable_encoder({"detail": errors}),
        status_code=status_code,
        headers={
            CorrelationIdMiddleware.header_name: correlation_id.get() or "",
            "Access-Control-Expose-Headers": CorrelationIdMiddleware.header_name,
        },
    )

@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
    """Add Correlation-ID to HTTP 500."""
    logger.exception(f"While responding to {request.method!s} {request.url!s}: {exc!s}")
    return await http_exception_handler(
        request,
        HTTPException(
            status.HTTP_500_INTERNAL_SERVER_ERROR,
            "Internal server error",
            headers={
                CorrelationIdMiddleware.header_name: correlation_id.get() or "",
                "Access-Control-Expose-Headers": CorrelationIdMiddleware.header_name,
            },
        ),
    )

@app.on_event("startup")
def load_configs():
    load_configurations()
    logger: logging.Logger = get_logger()
    logger.info("UDM mapping configuration: %s", UDM_MAPPING_CONFIG)

@app.on_event("startup")
def configure_import():
    get_import_config()

@app.exception_handler(NoObject)
async def no_object_exception_handler(request: Request, exc: NoObject):
    return ORJSONResponse(status_code=status.HTTP_404_NOT_FOUND, content={"message": str(exc)})

@app.exception_handler(SchooLibValidationError)
async def school_lib_validation_exception_handler(request: Request, exc: SchooLibValidationError):
    return ORJSONResponse(status_code=status.HTTP_400_BAD_REQUEST, content={"message": str(exc)})

@app.post(URL_TOKEN_BASE, response_model=Token)
async def login_for_access_token(
    form_data: OAuth2PasswordRequestForm = Depends(),
    logger: logging.Logger = Depends(get_logger),
):
    user = check_auth_and_get_user(form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
        )
    access_token_expires = timedelta(minutes=get_token_ttl())
    sub_data = user.dict(include={"username", "kelvin_admin"})
    sub_data["schools"] = user.attributes.get("ucsschoolSchool", [])
    sub_data["roles"] = user.attributes.get("ucsschoolRole", [])
    access_token = await create_access_token(data={"sub": sub_data}, expires_delta=access_token_expires)
    logger.debug("User %r retrieved access_token.", user.username)
    return {"access_token": access_token, "token_type": "bearer"}

@app.get(f"{URL_API_PREFIX}/changelog", response_class=HTMLResponse)
async def get_history():
    async with aiofiles.open(STATIC_FILE_CHANGELOG) as fp:
        return await fp.read()

@app.get(f"{URL_API_PREFIX}/readme", response_class=HTMLResponse)
async def get_readme():
    async with aiofiles.open(STATIC_FILE_README) as fp:
        return await fp.read()

app.include_router(
    school_class.router,
    prefix=f"{URL_API_PREFIX}/classes",
    tags=["classes"],
)
app.include_router(
    workgroup.router,
    prefix=f"{URL_API_PREFIX}/workgroups",
    tags=["workgroups"],
)
# app.include_router(
#     computer_room.router,
#     prefix=f"{URL_API_PREFIX}/computer_rooms",
#     tags=["computer_rooms"],
#     dependencies=[Depends(get_current_active_user)],
# )
# app.include_router(
#     computer_client.router,
#     prefix=f"{URL_API_PREFIX}/computers",
#     tags=["computers"],
#     dependencies=[Depends(get_current_active_user)],
# )
app.include_router(
    role.router,
    prefix=f"{URL_API_PREFIX}/roles",
    tags=["roles"],
)
app.include_router(
    school.router,
    prefix=f"{URL_API_PREFIX}/schools",
    tags=["schools"],
)
# app.include_router(
#     computer_server.router,
#     prefix=f"{URL_API_PREFIX}/servers",
#     tags=["servers"],
#     dependencies=[Depends(get_current_active_user)],
# )
app.include_router(
    user.router,
    prefix=f"{URL_API_PREFIX}/users",
    tags=["users"],
)
app.mount(
    f"{URL_API_PREFIX}/static",
    StaticFiles(directory=str(STATIC_FILES_PATH)),
    name="static",
)

@app.on_event("startup")
def log_version():  # should be the last 'startup' event function
    logger = logging.getLogger(__name__)
    logger.info(f"Started {app.title} version {app.version}.")


def add(*args):
    sum = 0
    for i in args:
        sum += i
    return sum

print(add(2,3,4,5,6))

def calculate(a,**kwargs):
    a += kwargs['sum']
    a *= kwargs["mult"]
    print(a)

calculate(sum=10, mult= 10, a= 0)

class Car:

    def __init__(self, **kwargs):
        self.name = kwargs.get("name")
        self.brand = kwargs.get("brand")

car = Car(name= "skj", brand = "gtr")
print(car.name)


import argparse

# Getting the scripts
parser = argparse.ArgumentParser()
parser.add_argument('--regularization', type = float, dest = 'reg_rate', default = 0.01, help = 'Enter regularization rate')
parser.add_argument('--input-data', type = str, dest = 'training_dataset_id', help = 'training dataset')
args = parser.parse_args()

# Set regularization rate
reg = args.reg_rate

# Get the experiment run context
from azureml.core import Run

run = Run.get_context()

# Load the diabetes dataset
diabetes = run.input_datasets['training_data'].to_pandas_dataframe()

# Seperate features and labels
X, y = diabetes[['Pregnancies','PlasmaGlucose','DiastolicBloodPressure','TricepsThickness','SerumInsulin','BMI','DiabetesPedigree','Age']].values, diabetes['Diabetic'].values

# Split data into training set and test set
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 0)

# Train a logistic regression model
from sklearn.linear_model import LogisticRegression
import numpy as np

print('Training a logistic regression model with regularization rate of', reg)
run.log('Regularization Rate',  np.float(reg))
model = LogisticRegression(C=1/reg, solver="liblinear").fit(X_train, y_train)

# calculate accuracy
y_hat = model.predict(X_test)
acc = np.average(y_hat == y_test)
print('Accuracy:', acc)
run.log('Accuracy', np.float(acc))

# calculate AUC
from sklearn.metrics import roc_auc_score

y_scores = model.predict_proba(X_test)
auc = roc_auc_score(y_test,y_scores[:,1])
print('AUC: ' + str(auc))
run.log('AUC', np.float(auc))

# plot ROC curve
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve

fpr, tpr, thresholds = roc_curve(y_test, y_scores[:,1])
fig = plt.figure(figsize=(6, 4))

# Plot the diagonal 50% line
plt.plot([0, 1], [0, 1], 'k--')

# Plot the FPR and TPR achieved by our model
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve')

run.log_image(name = "ROC", plot = fig)
plt.show()

# Creating output folder
os.makedirs('practice-arena/outputs', exist_ok = True)

# Save the model
import joblib

joblib.dump(value = model, filename = 'practice-arena/outputs/diabetes_model.pkl')

run.complete()

Work with Compute in Azure Machine Learning/diabetes-training-logistic/diabetes_training.py