from rest_framework import viewsets
from gamification.serializers import UserSerializer, TransactionSerializer, CategorySerializer, \
    UserCreateSerializer, FeedbackMessageSerializer, UserFIOSerializer, CreateFeedbackMessageSerializer, \
    ProductSerializer, \
    OrderProductSerializer, OrderCreateSerializer, OrderSerializer, OrderStatusSerializer, UserBadgeSerializer
from django.contrib.auth import get_user_model
from .models import Category, Transaction, FeedbackMessage, Product, Order, OrderProduct, UserBadge
from rest_framework.response import Response
from rest_framework import status
from django.http import HttpResponseBadRequest, HttpResponse
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from .permissions import IsStaffOrReadOnly, IsOwnerOrReadOnly, IsStaff
from django.contrib.auth.hashers import make_password, PBKDF2SHA1PasswordHasher
from django.core import mail
import xlwt, os, base64
from django.shortcuts import render
from django.utils import timezone

from rest_framework.decorators import api_view, permission_classes, action

from rest_framework.throttling import UserRateThrottle
from django.core.files.base import ContentFile

class OncePerDayUserThrottle(UserRateThrottle):
    rate = '1/day'

class UserViewSet(viewsets.ModelViewSet):
    queryset = get_user_model().objects.all()
    serializer_class = UserSerializer

    def get_permissions(self):

        if (self.action == 'list') or (self.action == 'update'):
            permission_classes = [IsOwnerOrReadOnly]
        else:
            if (self.action == 'add_interest') or (self.action == 'interests'):
                permission_classes =[IsAuthenticated]
            else:
                permission_classes = [IsAdminUser]
        return [permission() for permission in permission_classes]

    def create(self, request, *args, **kwargs):
        data = request.data
        data['password'] = make_password(data['password'])
        serializer = UserCreateSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save();
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def partial_update(self, request, *args, **kwargs):
        data = request.data
        if 'password' in data:
            data['password'] = make_password(data['password'])
        # if 'image' in data:
        #     m = get_user_model()
        #     m.image = request.FILES['image']
        #     m.save()

        serializer = UserCreateSerializer(request.user, data=request.data, partial=True, context={"request": request})
        if serializer.is_valid():
            instance = self.get_object()
            serializer.update(instance, serializer.validated_data)
            response = serializer.to_representation(instance)
            # serialized_object = UserSerializer('json', [get_user_model(),])

            return Response(response, status=status.HTTP_202_ACCEPTED)
            # return Response(serializer.data, status=status.HTTP_202_ACCEPTED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @api_view(['POST'])
    @permission_classes([IsAdminUser])
    def month_update (request, format=None):
        users = get_user_model().objects.all()
        for user in users:
            user.share_points = '10'
            user.save()

        return Response('success', status=status.HTTP_202_ACCEPTED)

    # @permission_classes([IsAuthenticated])
    @action(methods=['post'], detail=False)
    def add_interest(self, request):
        print(request)
        data = request.data
        data['user'] = request.user.pk
        try:
            b = UserBadge.objects.get(user=data['user'], badge=data['badge'])
        except UserBadge.DoesNotExist:
            b = None

        if b == None:
            serializer = UserBadgeSerializer(data=data)
            if serializer.is_valid():
                serializer.save()
            # obj, created = UserBadge.objects.get_or_create(user=serializer.validated_data['user'] ,
            #                                                badge=serializer.validated_data['badge'] )
                return Response('added', status=status.HTTP_202_ACCEPTED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        else:
            b.delete()
            return Response('excluded', status=status.HTTP_202_ACCEPTED)

    @action(methods=['get'], detail=True)
    def interests (self, request, pk=None):

        obj = get_user_model().objects.get(pk=pk)
        queryset = UserBadge.objects.filter(user=obj).values('badge')
        interests = []
        for i in queryset:
            interests.append(i['badge'])

        return Response(interests)
        #
        # return Response('success', status=status.HTTP_202_ACCEPTED)

class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    permission_classes = IsStaffOrReadOnly,

    def create(self, request, *args, **kwargs):
        # Добавить валидацию на аутисткий ввод строчки опций
        data = request.data

        serializer = CategorySerializer(data=data)
        # serializer.author_id = request.user.pk
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class TransactionsViewSet(viewsets.ReadOnlyModelViewSet):
    """
    This viewset automatically provides `list` and `detail` actions.
    """
    queryset = Transaction.objects.all().order_by('created_at').reverse()
    serializer_class = TransactionSerializer
    permission_classes = IsAuthenticated,

    def post(self, request, format=None):
        serializer = TransactionSerializer(data=request.data)
        from_user = request.user.pk
        request.data['from_user'] = from_user
        request.data['category'] = 1
        # сделать гет по имени категории

        cat = Category.objects.get(pk=1)
        if str(request.data['amount']) not in (cat.values.split(',')):
            return HttpResponseBadRequest({'Not valid amount of points for this category'})

        if serializer.is_valid():
            to_user = request.data['to_user']
            amount = int(request.data['amount'])
            From_User = get_user_model().objects.get(pk=from_user)
            To_User = get_user_model().objects.get(pk=to_user)
            if int(From_User.share_points) < amount:
                return HttpResponseBadRequest({'Недостаточно средств'})
            To_User.personal_points = str(int(To_User.personal_points) + amount)
            From_User.share_points = str(int(From_User.share_points) - amount)
            To_User.save()
            From_User.save()
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @api_view(['POST'])
    def superpost(request, format=None):
        data = request.data
        data['from_user'] = request.user.pk
        upd_users = data['to_user']

        try:
            cat = Category.objects.get(pk=data['category'])
            print(cat.name)
            if cat.name == "Спасибо":
                return HttpResponseBadRequest({'Category "Спасибо" is not valid for special actions'})
        except:
            return HttpResponseBadRequest({'Category does not exist'})

        if str(data['amount']) not in (cat.values.split(',')):
            return HttpResponseBadRequest({'Not valid amount of points'})

        s_data = []
        for to_user in upd_users:
            data['to_user'] = to_user
            line = data.copy()
            s_data.append(line)

        serializer = TransactionSerializer(data=s_data, many=True)
        if serializer.is_valid():

            users = get_user_model().objects.filter(pk__in=upd_users)
            for to_user in users:
                to_user.personal_points = str(int(to_user.personal_points) + int(data['amount']))
                to_user.save()
            serializer.save()
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        return Response(serializer.data, status=status.HTTP_201_CREATED)

class FeedbackMessageViewSet(viewsets.ModelViewSet):
    queryset = FeedbackMessage.objects.all().order_by('created_at').reverse()
    serializer_class = FeedbackMessageSerializer

    def get_permissions(self):
        if (self.action == 'create'):
            permission_classes = [IsAuthenticated]
        else:
            permission_classes = [IsAdminUser]
        return [permission() for permission in permission_classes]

    def create(self, request, *args, **kwargs):

        data = request.data

        data['author'] = request.user.pk

        serializer = CreateFeedbackMessageSerializer(data=data)
        if serializer.is_valid():
            user = get_user_model().objects.get(pk=data['author'])
            admin = get_user_model().objects.get(pk=1)

            backmessage = user.first_name + ',\n' + \
                          'Мы получили твоё обращение и уже обрабатываем его!\n' \
                          + 'Текст: \n' \
                          + data['text'] + \
                          '\n\nПосле рассмотрения администратор свяжется с тобой  \n\n\n\n' + \
                          'С уважением, \nкоманда Murano Gamification'

            formatopic = data['topic'].replace(' ', "%20")
            adminmessage = 'От: ' + user.first_name + " " + user.last_name + \
                           '\nТема: ' + serializer.validated_data['topic'] + ' \n    ' + \
                           serializer.validated_data['text'] \
                           + ' \n \n \n mailto:' + user.email + '?subject=' + formatopic + '&body=' + user.first_name + ',%20cпасибо%20за%20обращение!'

            connection = mail.get_connection()
            connection.open()

            mailer = 'muranomailer@mail.ru'

            email1 = mail.EmailMessage(
                'Новое обращение',
                adminmessage,
                mailer,
                [admin.email],
            )
            email2 = mail.EmailMessage(
                'Обратная связь с MuranoGamification',
                backmessage,
                mailer,
                [user.email],
            )

            connection.send_messages([email1, email2])
            connection.close()

            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class ExcelHandler(viewsets.ViewSet):
    permission_classes = IsAdminUser,
    throttle_classes = OncePerDayUserThrottle,

    def export_xls(self, request, *args, **kwargs):
        user = get_user_model().objects.get(pk=request.user.pk)

        wb = xlwt.Workbook(encoding='utf-8')
        empty = True

        if "Users" in request.data['selected']:
            ws = wb.add_sheet('Users')
            # Sheet header, first row
            row_num = 0
            font_style = xlwt.XFStyle()
            font_style.font.bold = True

            columns = ['Имя', 'Фамилия', 'Email', 'Баллы Спасибо', "Личные Баллы"]
            for col_num in range(len(columns)):
                ws.write(row_num, col_num, columns[col_num], font_style)
            # Sheet body, remaining rows
            font_style = xlwt.XFStyle()
            rows = get_user_model().objects.all().order_by('personal_points').values_list('first_name', 'last_name',
                                                                                'email', 'share_points',
                                                                                'personal_points')
            for row in rows:
                row_num += 1
                for col_num in range(len(row)):
                    ws.write(row_num, col_num, row[col_num], font_style)
            empty = False

        if "Transactions" in request.data['selected']:
            ws1 = wb.add_sheet('Транзакции')
            # Sheet header, first row
            row_num = 0
            font_style = xlwt.XFStyle()
            font_style.font.bold = True

            columns = ['От', 'Кому', 'Категроия', 'Количество', "Комментарий", "Дата"]
            for col_num in range(len(columns)):
                ws1.write(row_num, col_num, columns[col_num], font_style)
            # Sheet body, remaining rows
            font_style = xlwt.XFStyle()
            rows = Transaction.objects.all().order_by('created_at').reverse().values_list('from_user_id', 'to_user_id',
                                                                                'category', 'amount',
                                                                                'comment', 'created_at')
            for row in rows:
                row_num += 1
                from_user = get_user_model().objects.get(pk=row[0])
                f_fio = from_user.first_name + " " + from_user.last_name
                to_user = get_user_model().objects.get(pk=row[1])
                t_fio = to_user.first_name + " " + to_user.last_name
                cat = Category.objects.get(pk=row[2]).name

                ws1.write(row_num, 0, f_fio, font_style)
                ws1.write(row_num, 1, t_fio, font_style)
                ws1.write(row_num, 2, cat, font_style)
                ws1.write(row_num, 3, row[3], font_style)
                ws1.write(row_num, 4, row[4], font_style)
                ws1.write(row_num, 5, str(row[5]), font_style)
            empty = False

        if empty:
            return Response(data={'error': 'no matching for your keywords'}, status=status.HTTP_400_BAD_REQUEST)

        wb.save('Gamification.xls');

        connection = mail.get_connection()
        connection.open()

        mailer = 'muranomailer@mail.ru'

        email = mail.EmailMessage(
            'Gamification XLS',
            "Вы запросили данные в XLS формате",
            mailer,
            [user.email],
        )

        email.attach_file('Gamification.xls')

        connection.send_messages([email])
        connection.close()

        os.remove('Gamification.xls')

        return Response({'text': "Yass"})

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    permission_classes = IsStaffOrReadOnly,

    def create(self, request, *args, **kwargs):
        serializer = ProductSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def partial_update(self, request, *args, **kwargs):
        serializer = ProductSerializer(data=request.data, partial=True)
        if serializer.is_valid():
            # instance = Product.objects.get(pk=request.data['id'])
            instance = self.get_object()

            serializer.update(instance, serializer.validated_data)
            print('_+_+_+_+_+_+_+_+_+')
            response = serializer.to_representation(instance)
            return Response(response, status=status.HTTP_202_ACCEPTED)

            if 'image' not in request.data:
                return Response(request.data, status=status.HTTP_202_ACCEPTED)
            else:
                return Response("idk how return form data", status=status.HTTP_202_ACCEPTED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class OrderViewSet(viewsets.ModelViewSet):
    queryset = Order.objects.all().order_by('created_at').reverse()
    serializer_class = OrderSerializer

    def get_permissions(self):
        if (self.action == 'create'):
            permission_classes = [IsAuthenticated]
        else:
            permission_classes = [IsAdminUser]
        return [permission() for permission in permission_classes]

    def create(self, request, *args, **kwargs):
        data = request.data
        data['customer'] = request.user.pk
        serializer = OrderCreateSerializer(data=data)
        if serializer.is_valid():
            order = serializer.save()
            serializer = OrderCreateSerializer(order)
            return Response({'data': 'f'}, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def partial_update(self, request, *args, **kwargs):
        data = request.data
        if not data['active']:
            now = timezone.now()
            data['delivered_at'] = now
        else:
            data['delivered_at'] = None

        serializer = OrderStatusSerializer(data=data, partial=True)
        if serializer.is_valid():
            # instance = Product.objects.get(pk=request.data['id'])
            instance = self.get_object()
            serializer.update(instance, serializer.validated_data)
            resp = serializer.data.copy()
            resp['id'] = self.get_object().pk
            return Response(resp, status=status.HTTP_202_ACCEPTED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

# class InterestViewSet(viewsets.ModelViewSet):
#     queryset = Interest.objects.all().order_by('created_at').reverse()
#     serializer_class = InterestSerializer

def start(request):
    return render(request, 'dist/index.html')


import argparse
import gzip
import os
import requests

def parse_arguments():
  """Parses command line arguments."""
  parser = argparse.ArgumentParser()
  parser.add_argument("source_url",
                      type=str,
                      metavar="<source-url>",
                      help="Source URL to download")
  parser.add_argument("-o",
                      "--output",
                      type=str,
                      required=True,
                      metavar="<output-file>",
                      help="Output file path")
  return parser.parse_args()

def main(args):
  output_dir = os.path.dirname(args.output)

  if not os.path.isdir(output_dir):
    os.makedirs(output_dir)

  response = requests.get(args.source_url)
  if response.status_code != 200:
    raise requests.RequestException(
        f"Failed to download file with status code {response.status_code}")

  data = response.content
  if args.source_url.endswith(".gz"):
    data = gzip.decompress(data)

  with open(args.output, "wb") as f:
    f.write(data)

if __name__ == "__main__":
  main(parse_arguments())


import base64

# Read data from stdin

def main():
    # if str == 'Start':
    #     print "OK"
    #     print "Cancel"
    with open("/home/pi/ios/ble/python/sample.png", "rb") as imageFile:
        image_str = base64.b64encode(imageFile.read())
    fh = open("/home/pi/ios/ble/data/imageToSave", "wb")
    fh.write(image_str)
    fh.close()
    fh = open("/home/pi/ios/ble/data/string", "wb")
    fh.write("Hello Raspberry Pi")
    fh.close()
    fh = open("/home/pi/ios/ble/data/status", "wb")
    fh.write("Finished " + str(len(image_str)))
    fh.close()

if __name__ == '__main__':
    main()


import os
from datetime import datetime
from itertools import groupby, islice
from operator import itemgetter
from os import listdir
from os.path import isdir, join
from typing import Optional

from fastapi import APIRouter, Query

from ...core.base import TokenV3
from ...core.helpers import sum_proofs
from ...core.settings import settings
from ...lightning.base import (
    InvoiceResponse,
    PaymentResponse,
    PaymentStatus,
    StatusResponse,
)
from ...nostr.client.client import NostrClient
from ...tor.tor import TorProxy
from ...wallet.crud import get_lightning_invoices, get_reserved_proofs
from ...wallet.helpers import (
    deserialize_token_from_string,
    init_wallet,
    list_mints,
    receive,
    send,
)
from ...wallet.nostr import receive_nostr, send_nostr
from ...wallet.wallet import Wallet as Wallet
from ..lightning.lightning import LightningWallet
from .api_helpers import verify_mints
from .responses import (
    BalanceResponse,
    BurnResponse,
    InfoResponse,
    InvoicesResponse,
    LockResponse,
    LocksResponse,
    PendingResponse,
    ReceiveResponse,
    RestoreResponse,
    SendResponse,
    SwapResponse,
    WalletsResponse,
)

router: APIRouter = APIRouter()

async def mint_wallet(
    mint_url: Optional[str] = None, raise_connection_error: bool = True
) -> LightningWallet:
    lightning_wallet = await LightningWallet.with_db(
        mint_url or settings.mint_url,
        db=os.path.join(settings.cashu_dir, settings.wallet_name),
        name=settings.wallet_name,
    )
    await lightning_wallet.async_init(raise_connection_error=raise_connection_error)
    return lightning_wallet

wallet = LightningWallet(
    settings.mint_url,
    db=os.path.join(settings.cashu_dir, settings.wallet_name),
    name=settings.wallet_name,
)

@router.on_event("startup")
async def start_wallet():
    global wallet
    wallet = await mint_wallet(settings.mint_url, raise_connection_error=False)
    if settings.tor and not TorProxy().check_platform():
        raise Exception("tor not working.")

@router.post(
    "/lightning/pay_invoice",
    name="Pay lightning invoice",
    response_model=PaymentResponse,
)
async def pay(
    bolt11: str = Query(default=..., description="Lightning invoice to pay"),
    mint: str = Query(
        default=None,
        description="Mint URL to pay from (None for default mint)",
    ),
) -> PaymentResponse:
    global wallet
    if mint:
        wallet = await mint_wallet(mint)
    payment_response = await wallet.pay_invoice(bolt11)
    return payment_response

@router.get(
    "/lightning/payment_state",
    name="Request lightning invoice",
    response_model=PaymentStatus,
)
async def payment_state(
    payment_hash: str = Query(default=None, description="Id of paid invoice"),
    mint: str = Query(
        default=None,
        description="Mint URL to create an invoice at (None for default mint)",
    ),
) -> PaymentStatus:
    global wallet
    if mint:
        wallet = await mint_wallet(mint)
    state = await wallet.get_payment_status(payment_hash)
    return state

@router.post(
    "/lightning/create_invoice",
    name="Request lightning invoice",
    response_model=InvoiceResponse,
)
async def create_invoice(
    amount: int = Query(default=..., description="Amount to request in invoice"),
    mint: str = Query(
        default=None,
        description="Mint URL to create an invoice at (None for default mint)",
    ),
) -> InvoiceResponse:
    global wallet
    if mint:
        wallet = await mint_wallet(mint)
    invoice = await wallet.create_invoice(amount)
    return invoice

@router.get(
    "/lightning/invoice_state",
    name="Request lightning invoice",
    response_model=PaymentStatus,
)
async def invoice_state(
    payment_hash: str = Query(default=None, description="Payment hash of paid invoice"),
    mint: str = Query(
        default=None,
        description="Mint URL to create an invoice at (None for default mint)",
    ),
) -> PaymentStatus:
    global wallet
    if mint:
        wallet = await mint_wallet(mint)
    state = await wallet.get_invoice_status(payment_hash)
    return state

@router.get(
    "/lightning/balance",
    name="Balance",
    summary="Display balance.",
    response_model=StatusResponse,
)
async def lightning_balance() -> StatusResponse:
    try:
        await wallet.load_proofs(reload=True)
    except Exception as exc:
        return StatusResponse(error_message=str(exc), balance_msat=0)
    return StatusResponse(
        error_message=None, balance_msat=wallet.available_balance * 1000
    )

@router.post(
    "/swap",
    name="Multi-mint swaps",
    summary="Swap funds between mints",
    response_model=SwapResponse,
)
async def swap(
    amount: int = Query(default=..., description="Amount to swap between mints"),
    outgoing_mint: str = Query(default=..., description="URL of outgoing mint"),
    incoming_mint: str = Query(default=..., description="URL of incoming mint"),
):
    if not settings.lightning:
        raise Exception("lightning not supported")
    incoming_wallet = await mint_wallet(incoming_mint)
    outgoing_wallet = await mint_wallet(outgoing_mint)
    if incoming_wallet.url == outgoing_wallet.url:
        raise Exception("mints for swap have to be different")

    # request invoice from incoming mint
    invoice = await incoming_wallet.request_mint(amount)

    # pay invoice from outgoing mint
    await outgoing_wallet.load_proofs(reload=True)
    total_amount, fee_reserve_sat = await outgoing_wallet.get_pay_amount_with_fees(
        invoice.bolt11
    )
    assert total_amount > 0, "amount must be positive"
    if outgoing_wallet.available_balance < total_amount:
        raise Exception("balance too low")

    _, send_proofs = await outgoing_wallet.split_to_send(
        outgoing_wallet.proofs, total_amount, set_reserved=True
    )
    await outgoing_wallet.pay_lightning(send_proofs, invoice.bolt11, fee_reserve_sat)

    # mint token in incoming mint
    await incoming_wallet.mint(amount, id=invoice.id)
    await incoming_wallet.load_proofs(reload=True)
    mint_balances = await incoming_wallet.balance_per_minturl()
    return SwapResponse(
        outgoing_mint=outgoing_mint,
        incoming_mint=incoming_mint,
        invoice=invoice,
        balances=mint_balances,
    )

@router.get(
    "/balance",
    name="Balance",
    summary="Display balance.",
    response_model=BalanceResponse,
)
async def balance():
    await wallet.load_proofs(reload=True)
    keyset_balances = wallet.balance_per_keyset()
    mint_balances = await wallet.balance_per_minturl()
    return BalanceResponse(
        balance=wallet.available_balance, keysets=keyset_balances, mints=mint_balances
    )

@router.post("/send", name="Send tokens", response_model=SendResponse)
async def send_command(
    amount: int = Query(default=..., description="Amount to send"),
    nostr: str = Query(default=None, description="Send to nostr pubkey"),
    lock: str = Query(default=None, description="Lock tokens (P2PK)"),
    mint: str = Query(
        default=None,
        description="Mint URL to send from (None for default mint)",
    ),
    nosplit: bool = Query(
        default=False, description="Do not split tokens before sending."
    ),
):
    global wallet
    if mint:
        wallet = await mint_wallet(mint)
    if not nostr:
        balance, token = await send(
            wallet, amount=amount, lock=lock, legacy=False, split=not nosplit
        )
        return SendResponse(balance=balance, token=token)
    else:
        token, pubkey = await send_nostr(wallet, amount=amount, pubkey=nostr)
        return SendResponse(balance=wallet.available_balance, token=token, npub=pubkey)

@router.post("/receive", name="Receive tokens", response_model=ReceiveResponse)
async def receive_command(
    token: str = Query(default=None, description="Token to receive"),
    nostr: bool = Query(default=False, description="Receive tokens via nostr"),
    all: bool = Query(default=False, description="Receive all pending tokens"),
):
    wallet = await mint_wallet()
    initial_balance = wallet.available_balance
    if token:
        tokenObj: TokenV3 = deserialize_token_from_string(token)
        await verify_mints(wallet, tokenObj)
        balance = await receive(wallet, tokenObj)
    elif nostr:
        await receive_nostr(wallet)
        balance = wallet.available_balance
    elif all:
        reserved_proofs = await get_reserved_proofs(wallet.db)
        balance = None
        if len(reserved_proofs):
            for _, value in groupby(reserved_proofs, key=itemgetter("send_id")):  # type: ignore
                proofs = list(value)
                token = await wallet.serialize_proofs(proofs)
                tokenObj = deserialize_token_from_string(token)
                await verify_mints(wallet, tokenObj)
                balance = await receive(wallet, tokenObj)
    else:
        raise Exception("enter token or use either flag --nostr or --all.")
    assert balance
    return ReceiveResponse(initial_balance=initial_balance, balance=balance)

@router.post("/burn", name="Burn spent tokens", response_model=BurnResponse)
async def burn(
    token: str = Query(default=None, description="Token to burn"),
    all: bool = Query(default=False, description="Burn all spent tokens"),
    force: bool = Query(default=False, description="Force check on all tokens."),
    delete: str = Query(
        default=None,
        description="Forcefully delete pending token by send ID if mint is unavailable",
    ),
    mint: str = Query(
        default=None,
        description="Mint URL to burn from (None for default mint)",
    ),
):
    global wallet
    if not delete:
        wallet = await mint_wallet(mint)
    if not (all or token or force or delete) or (token and all):
        raise Exception(
            "enter a token or use --all to burn all pending tokens, --force to"
            " check all tokens or --delete with send ID to force-delete pending"
            " token from list if mint is unavailable.",
        )
    if all:
        # check only those who are flagged as reserved
        proofs = await get_reserved_proofs(wallet.db)
    elif force:
        # check all proofs in db
        proofs = wallet.proofs
    elif delete:
        reserved_proofs = await get_reserved_proofs(wallet.db)
        proofs = [proof for proof in reserved_proofs if proof["send_id"] == delete]
    else:
        # check only the specified ones
        tokenObj = TokenV3.deserialize(token)
        proofs = tokenObj.get_proofs()

    if delete:
        await wallet.invalidate(proofs, check_spendable=False)
    else:
        await wallet.invalidate(proofs)
    return BurnResponse(balance=wallet.available_balance)

@router.get("/pending", name="Show pending tokens", response_model=PendingResponse)
async def pending(
    number: int = Query(default=None, description="Show only n pending tokens"),
    offset: int = Query(
        default=0, description="Show pending tokens only starting from offset"
    ),
):
    reserved_proofs = await get_reserved_proofs(wallet.db)
    result: dict = {}
    if len(reserved_proofs):
        sorted_proofs = sorted(reserved_proofs, key=itemgetter("send_id"))  # type: ignore
        if number:
            number += offset
        for i, (key, value) in islice(
            enumerate(
                groupby(
                    sorted_proofs,
                    key=itemgetter("send_id"),  # type: ignore
                )
            ),
            offset,
            number,
        ):
            grouped_proofs = list(value)
            token = await wallet.serialize_proofs(grouped_proofs)
            tokenObj = deserialize_token_from_string(token)
            mint = [t.mint for t in tokenObj.token if t.mint][0]
            reserved_date = datetime.utcfromtimestamp(
                int(grouped_proofs[0].time_reserved)  # type: ignore
            ).strftime("%Y-%m-%d %H:%M:%S")
            result.update(
                {
                    f"{i}": {
                        "amount": sum_proofs(grouped_proofs),
                        "time": reserved_date,
                        "ID": key,
                        "token": token,
                        "mint": mint,
                    }
                }
            )
    return PendingResponse(pending_token=result)

@router.get("/lock", name="Generate receiving lock", response_model=LockResponse)
async def lock():
    pubkey = await wallet.create_p2pk_pubkey()
    return LockResponse(P2PK=pubkey)

@router.get("/locks", name="Show unused receiving locks", response_model=LocksResponse)
async def locks():
    pubkey = await wallet.create_p2pk_pubkey()
    return LocksResponse(locks=[pubkey])

@router.get(
    "/invoices", name="List all pending invoices", response_model=InvoicesResponse
)
async def invoices():
    invoices = await get_lightning_invoices(db=wallet.db)
    return InvoicesResponse(invoices=invoices)

@router.get(
    "/wallets", name="List all available wallets", response_model=WalletsResponse
)
async def wallets():
    wallets = [
        d for d in listdir(settings.cashu_dir) if isdir(join(settings.cashu_dir, d))
    ]
    try:
        wallets.remove("mint")
    except ValueError:
        pass
    result = {}
    for w in wallets:
        wallet = Wallet(settings.mint_url, os.path.join(settings.cashu_dir, w), name=w)
        try:
            await init_wallet(wallet)
            if wallet.proofs and len(wallet.proofs):
                active_wallet = False
                if w == wallet.name:
                    active_wallet = True
                if active_wallet:
                    result.update(
                        {
                            f"{w}": {
                                "balance": sum_proofs(wallet.proofs),
                                "available": sum_proofs(
                                    [p for p in wallet.proofs if not p.reserved]
                                ),
                            }
                        }
                    )
        except Exception:
            pass
    return WalletsResponse(wallets=result)

@router.post("/restore", name="Restore wallet", response_model=RestoreResponse)
async def restore(
    to: int = Query(default=..., description="Counter to which restore the wallet"),
):
    if to < 0:
        raise Exception("Counter must be positive")
    await wallet.load_mint()
    await wallet.restore_promises_from_to(0, to)
    await wallet.invalidate(wallet.proofs)
    wallet.status()
    return RestoreResponse(balance=wallet.available_balance)

@router.get("/info", name="Information about Cashu wallet", response_model=InfoResponse)
async def info():
    if settings.nostr_private_key:
        try:
            client = NostrClient(private_key=settings.nostr_private_key, connect=False)
            nostr_public_key = client.private_key.bech32()
            nostr_relays = settings.nostr_relays
        except Exception:
            nostr_public_key = "Invalid key"
            nostr_relays = []
    else:
        nostr_public_key = None
        nostr_relays = []
    mint_list = await list_mints(wallet)
    return InfoResponse(
        version=settings.version,
        wallet=wallet.name,
        debug=settings.debug,
        cashu_dir=settings.cashu_dir,
        mint_urls=mint_list,
        settings=settings.env_file,
        tor=settings.tor,
        nostr_public_key=nostr_public_key,
        nostr_relays=nostr_relays,
        socks_proxy=settings.socks_proxy,
    )


import sys
from collections import defaultdict
input = sys.stdin.readline

n = int(input())
due = defaultdict(list)
latest_due = 0 # 가장 늦은 데드라인
ans = 0

for _ in range(n):
    p, d = map(int, input().split())
    # due[d]는 각각이 리스트임
    due[d].append(p)
    latest_due = max(latest_due, d)

for i in range(latest_due + 1):
    if i in due:
        due[i].sort()

# date 부터 latest_due 까지의 idx 중에서 찾음
for date in range(latest_due, 0, -1):
    mP = None
    mIdx = None

    for i in range(date, latest_due + 1):
        if i in due and due[i] and (mP == None or due[i][-1] > mP):
            mIdx = i
            mP = due[i][-1]

    # 찾으면 그 일정을 수행, pop
    if mP:
        ans += mP
        due[mIdx].pop()

print(ans)


# This code can't scroll. so user should have to scroll while code is executing

from selenium import webdriver
from selenium.webdriver.common.by import By
import time
import firebase_admin
from firebase_admin import credentials
from firebase_admin import db

cred = credentials.Certificate('treatment-97281-firebase-adminsdk-ba112-c7823d2208.json')

firebase_admin.initialize_app(cred, {
    'databaseURL': "https://treatment-97281-default-rtdb.firebaseio.com"
})

ref = db.reference('/bus')

def my_function():
    link = "https://rongdhonustudio.com/DhakaBus.html"
    driver.get(link)
    data1 = driver.find_elements(By.XPATH, "//ul//li")
    data2 = driver.find_elements(By.XPATH, "//ul//li//div//div")

    print(f"total number of item: {len(data1)}")
    for i in range(len(data1)):
        BussName = data1[i].text
        var = data1[i]
        data1[i].click()
        time.sleep(1)
        Route = data2[i].text
        Route_name = Route.replace('Route:','')
        print(BussName, "==", Route_name)
        print(" ")

        ref.push().set({
            'bus_name': BussName,
            'bus_route': Route_name
        })

driver = webdriver.Chrome()
time.sleep(2)

my_function()

time.sleep(2)
driver.quit()


import requests
from bs4 import BeautifulSoup
from urllib.request import urlopen as uReq # command to grab the page

# this program was built as part of my work with SVCI - in order to streamline my workload in data entry

# Function to scrape company information from Crunchbase
def scrape_crunchbase_company(url):
    try:
        # Send a GET request to the Crunchbase URL
        #response = requests.get(url)

        uClient = uReq(url)
        # read the html page and save it inside a var, if you don't store, the html is dumped
        response = uClient.read()
        # close the connection
        uClient.close()

        # Check if the request was successful
        if response.status_code == 200:
            # Parse the HTML content of the page using BeautifulSoup
            soup = BeautifulSoup(response.text, 'html.parser')

            # Extract company information (you can modify this as needed)
            company_name = soup.find('h1', class_='component--field-formatter field-type-identifier-multi').text.strip()
            description = soup.find('span', class_='component--field-formatter field-type-markdown field-label-hidden').text.strip()
            headquarters = soup.find('div', class_='location-icon-2').find_next('span').text.strip()
            founders = soup.find('span', class_='wrappable-label-with-info ng-star-inserted').text.strip()
            website = soup.find('a', rel_='nofollow noopener noreferrer').text.strip()

            # Print the scraped information
            print("Company Name:", company_name)
            print("Description:", description)
            print("Headquarters:", headquarters)
            print("Founders: ", founders)
            print("Website: ", website)
        else:
            print("Couldn't retrieve the page. Status code:", response.status_code)

    except Exception as e:
        print("An error occurred:", str(e))

# URL of the Crunchbase page you want to scrape
crunchbase_url = "https://www.crunchbase.com/organization/databook"

# Call the scrape function with the URL
scrape_crunchbase_company(crunchbase_url)


from datetime import datetime
from uuid import uuid4, UUID
from pydantic import BaseModel, Field
from sqlalchemy import or_

from base import database, table_users_log

class User_log(BaseModel):
    p_id: UUID = Field(default_factory=uuid4)
    r_id: UUID = Field(default_factory=uuid4)
    u_id: UUID = Field(default_factory=uuid4)
    l_time : datetime
    event : str

    async def create(P_ID, R_ID, U_ID, EVENT):
        "Процедура добавления строчки лога"
        query = table_users_log.insert().values(
                p_id = P_ID,
                r_id = R_ID,
                u_id = U_ID,
                l_time = datetime.now(),
                event = EVENT
                )

        return await database.execute(query)

    async def list_events(ID):
        "Процедура чтения лога по проекту референсу или юзеру"
        query = table_users_log.select().values(or_(
            table_users_log.c.p_id == ID,
            table_users_log.c.r_id == ID,
            table_users_log.c.u_id == ID
            ))

        return await database.fetch_all(query)


#!/usr/bin/python3.4
import logging
import monitor
# create logger with 'spam_application'
logger = logging.getLogger('Arduino_app')
logger.setLevel(logging.DEBUG)
# create file handler which logs even debug messages
fh = logging.FileHandler('serial_monitor.log')
fh.setLevel(logging.DEBUG)
# create console handler with a higher log level
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)
# add the handlers to the logger
logger.addHandler(fh)
logger.addHandler(ch)

logger.info('launching serial Monitoring')
monitoring = monitor.ArduinoSerial(port='/dev/ttyACM0')
#serialCom = monitoring(port='/dev/ttyACM0')
logger.info('launched an instance of serial Monitoring')
logger.info('starting monitoring loop')
#monitor.readFrom_Serial(monitoring)
monitor.read_dht11_serial(monitoring)
logger.info('ending monitoring loop')


from urllib.parse import urlparse, urlunparse
import requests
from bs4 import BeautifulSoup
from PIL import Image
import crossref_commons.retrieval
import hashlib
import json
import io

import os
if "XDG_CACHE_HOME" in os.environ:
    CACHE_HOME = os.environ["XDG_CACHE_HOME"]
else:
    CACHE_HOME = os.path.join(os.environ["HOME"], ".cache")

CACHEDIR = os.path.join(CACHE_HOME, "eurec4a_meta", "uri_meta")

class URI:
    kind = "unknown"
    def __init__(self, parsed_uri):
        self.o = parsed_uri
        self.extra_attrs = {}

    def __repr__(self):
        return urlunparse(self.o)

    @property
    def title(self):
        if "title" in self.extra_attrs:
            return self.extra_attrs["title"]
        try:
            return self._title
        except AttributeError:
            return ""

    def to_link_object(self):
        return {
            **self.extra_attrs,
            "href": self.url,
            "title": self.title,
            "kind": self.kind,
        }

class HTTP(URI):
    kind = "http"
    __content = None

    @property
    def _content(self):
        if self.__content is None:
            res = requests.get(self.url)
            res.raise_for_status()
            self.__content = res.content
        return self.__content

    @property
    def _soup(self):
        try:
            return BeautifulSoup(self._content.decode("utf-8"), "html.parser")
        except:
            return None

    @property
    def _file_meta(self):
        return {
            "filesize": len(self._content),
        }

    @property
    def _image_meta(self):
        try:
            bio = io.BytesIO(self._content)
            img = Image.open(bio)
        except Exception as e:
            return {}
        else:
            return {
                "type": Image.MIME[img.format],
                "imagesize": list(img.size),
            }

    @property
    def _title(self):
        return self._soup.head.title.get_text()

    def to_link_object(self):
        return {
            **super(HTTP, self).to_link_object(),
            **self._file_meta,
            **self._image_meta,
        }

    @property
    def url(self):
        return urlunparse(self.o)

class DOI(URI):
    kind = "doi"
    __metadata = None

    @property
    def _doi(self):
        return self.o.path

    @property
    def _metadata(self):
        meta_hash = hashlib.sha256(("doi_meta+" + self._doi).encode("utf-8")).hexdigest()
        cache_file = os.path.join(CACHEDIR, meta_hash + ".json")
        if os.path.exists(cache_file):
            with open(cache_file) as cf:
                return json.load(cf)
        else:
            os.makedirs(CACHEDIR, exist_ok=True)
            res = crossref_commons.retrieval.get_publication_as_json(self._doi)
            with open(cache_file, "w") as cf:
                json.dump(res, cf)
            return res

    @property
    def _title(self):
        return self._metadata["title"][0]

    @property
    def url(self):
        return "https://doi.org/{}".format(self._doi)

    def to_link_object(self):
        return {**super(DOI, self).to_link_object(), "doi": self._doi}

HANDLED_URIS = {
    "http": HTTP,
    "https": HTTP,
    "doi": DOI,
}

def parse_uri(uri):
    if isinstance(uri, dict):
        o = _parse_uri(uri["href"])
        o.extra_attrs.update({k: v for k, v in uri.items() if k != "href"})
    else:
        o = _parse_uri(uri)
    return o

def _parse_uri(uri):
    o = urlparse(uri)
    if o.scheme not in HANDLED_URIS:
        raise ValueError("unknown URI scheme {} in {}".format(o.scheme, uri))
    return HANDLED_URIS[o.scheme](o)


from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import auth
from .models import Operador as caixa, Produtos as prod
from .form import ProductForm, CaixaForm
# from django import template
from django.http import HttpResponseRedirect
from django.urls import reverse

#COMPRAS
@login_required
def listar_produtos_disponiveis(request):
        produtos = prod.objects.all()
        return render(request, 'compras.html', {'produtos': produtos})

        def post(self, request, *args, **kwargs):
            if request.method == "POST":
                produto_id = request.POST.getlist('preco[]')
                for preco in produto_id:
                    produtos = prod.objects.get(pk=id)
                    produtos.save()

            return redirect('listar_produtos_disponiveis')

# class Preco_view(View):
#     def get(self, request):
#         produto = prod.objects.all()
#         context ={
#             'produto': produto
#         }
#         return render(request, 'compras.html', context)

#PRODUTOS
@login_required
def list_products(request):
    produtos = prod.objects.all()
    return render(request, 'produtos.html', {'produtos': produtos})

@login_required
def create_products(request):
    form = ProductForm(request.POST or None)

    if request.method == "POST" and form.is_valid():
        form.save()
        return redirect('list_products')

    return render(request, 'produtos-form.html', {'form': form})

@login_required
def update_products(request, id):
    produto = prod.objects.get(id=id)
    form = ProductForm(request.POST or None, instance=produto)

    if request.method == "POST" and form.is_valid():
        form.save()
        return redirect('list_products')

    return render(request, 'produtos-form.html', {'form': form, 'produto': produto})

@login_required
def delete_products(request, id):
    produto = prod.objects.get(id=id)

    if request.method == 'POST':
        produto.delete()
        return redirect('list_products')

    return render(request, 'produtos-delete-confirm.html', {'produto': produto})

#CAIXA
@login_required
def list_caixa(request):
    operadores = caixa.objects.all()
    return render(request, 'caixa.html', {'operadores': operadores})

@login_required
def create_caixa(request):
    form = CaixaForm(request.POST or None)

    if request.method == "POST" and form.is_valid():
        form.save()
        return redirect('list_caixa')

    return render(request, 'caixa-form.html', {'form': form})

@login_required
def update_caixa(request, id):
    operadores = caixa.objects.get(id=id)
    form = CaixaForm(request.POST or None, instance=operadores)

    if request.method == "POST" and form.is_valid():
        form.save()
        return redirect('list_caixa')

    return render(request, 'caixa-form.html', {'form': form, 'operadores': operadores})

@login_required
def delete_caixa(request, id):
    operadores = caixa.objects.get(id=id)

    if request.method == 'POST':
        operadores.delete()
        return redirect('list_caixa')

    return render(request, 'caixa-delete-confirm.html', {'operadores': operadores})

#LOGOUT
def logout(request):
    auth.logout(request)
    return redirect('/')


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import copy
from decimal import Decimal
from django.conf import settings

from product.models import Product, Slab, PackageList
from stock.models import Location

class Cart:
    def __init__(self, request):
        self.session = request.session
        cart = self.session.get(settings.CART_SESSION_ID)
        if not cart:
            cart = self.session[settings.CART_SESSION_ID] = {}
        self.cart = cart

    def add(self, product_id, location_id, piece=None, quantity=None, slab_id_list=None):
        product = Product.objects.get(pk=product_id)
        if product.type == 'slab':
            if not slab_id_list:
                return False
            piece = len(slab_id_list)
            quantity = sum(slab.get_quantity() for slab in Slab.objects.filter(id__in=slab_id_list))
        elif product.type == 'block':
            piece = 1
            quantity = quantity
        line = len(self.cart) + 1 if product_id not in self.cart else self.cart[product_id]['line']
        self.cart[product_id] = {'line': line, 'piece': piece, 'quantity': str(quantity),
                                 'slab_id_list': slab_id_list, 'location_id': location_id}
        self.save()

    def save(self):
        self.session.modified = True

    def get_select_slabs(self):
        lst = []
        for i in self.cart.values():
            lst.extend(i['slab_id_list'])
        return lst

    def remove(self, product_id):
        product_id = str(product_id)
        if product_id in self.cart:
            del self.cart[product_id]
            self.save()

    def clean(self):
        del self.session[settings.CART_SESSION_ID]
        self.save()

    def __iter__(self):
        product_id_list = self.cart.keys()
        products = Product.objects.filter(id__in=product_id_list)
        cart = copy.deepcopy(self.cart)
        for product in products:
            cart[str(product.id)]['product'] = product
            if product.type == 'slab':
                cart[str(product.id)]['part'] = {s.part_number for s in
                                                 Slab.objects.filter(id__in=cart[str(product.id)]['slab_id_list'])}

        for item in cart.values():
            item['quantity'] = item['quantity']
            yield item

    def __len__(self):
        return len(self.cart)


import gym
import numpy as np
import scipy as sp
# import torch

import sys
sys.path.append('../../')
from tensor import KoopmanTensor, OLS
sys.path.append('../../../')
# import cartpole_reward
import observables

#%% Initialize environment
env = gym.make('CartPole-v0')
# env = gym.make('env:CartPoleControlEnv-v0')

# def reward(xs, us):
#     return cartpole_reward.defaultCartpoleRewardMatrix(xs, us)
# def cost(xs, us):
#     return -reward(xs, us)

gamma = 0.99
eta = 0.001

w_r = np.zeros([4,1])

Q_ = np.array([
    [10, 0,  0, 0],
    [ 0, 1,  0, 0],
    [ 0, 0, 10, 0],
    [ 0, 0,  0, 1]
])
R = 0.1
def cost(x, u):
    # Assuming that data matrices are passed in for X and U. Columns vectors are snapshots
    _x = x - w_r
    mat = np.vstack(np.diag(_x.T @ Q_ @ _x)) + np.power(u, 2)*R
    return mat

#%% Construct snapshots of u from random agent and initial states x0
N = 20000 # Number of datapoints
U = np.zeros([1,N])
X = np.zeros([4,N+1])
Y = np.zeros([4,N])
i = 0
while i < N:
    X[:,i] = env.reset()
    done = False
    while i < N and not done:
        U[0,i] = env.action_space.sample()
        Y[:,i], _, done, __ = env.step( int(U[0,i]) ) # np.array([int(U[0,i])])
        if not done:
            X[:,i+1] = Y[:,i]
        i += 1
X = X[:,:-1]

#%% Estimate Koopman tensor
order = 2
tensor = KoopmanTensor(
    X,
    Y,
    U,
    phi=observables.monomials(order),
    psi=observables.monomials(2),
    regressor='ols'
)

#%% Setup vars
state_dim = 4 # env.observation_space.shape[0]
action_dim = 1
M_plus_N_minus_ones = np.arange( (state_dim-1), order + (state_dim-1) + 1 )
phi_dim = int( np.sum( sp.special.comb( M_plus_N_minus_ones, np.ones_like(M_plus_N_minus_ones) * (state_dim-1) ) ) )
u_range = np.array([-5, 5])
step_size = 1 # 0.1
all_us = np.arange(u_range[0], u_range[1]+step_size, step_size)

#%% Handy functions
w_hat_batch_size = X.shape[1] # was 2**10
def w_hat_t(pi_t):
    x_batch_indices = np.random.choice(X.shape[1], w_hat_batch_size, replace=False)
    x_batch = X[:, x_batch_indices] # (x_dim, w_hat_batch_size)
    phi_x_batch = tensor.phi(x_batch) # (phi_dim, w_hat_batch_size)

    pi_response  = pi_t( x_batch, np.array([all_us]) )

    phi_x_prime_batch = tensor.K_(np.array([all_us])) @ phi_x_batch # (all_us.shape[0], phi_dim, w_hat_batch_size)
    phi_x_prime_batch_prob = phi_x_prime_batch * \
                                pi_response.reshape(
                                    pi_response.shape[0],
                                    1,
                                    pi_response.shape[1]
                                ) # (all_us.shape[0], phi_dim, w_hat_batch_size)
    expectation_term_1 = np.sum(phi_x_prime_batch_prob, axis=0) # (phi_dim, w_hat_batch_size)

    cost_batch_prob = cost(x_batch, np.array([all_us])) * pi_response # (all_us.shape[0], w_hat_batch_size)
    expectation_term_2 = np.array([
        np.sum(cost_batch_prob, axis=0) # (w_hat_batch_size,)
    ]) # (1, w_hat_batch_size)

    return OLS(
        (phi_x_batch - (gamma*expectation_term_1)).T,
        expectation_term_2.T
    )

def Q(x, u):
    return cost(x, u) + gamma*w_hat_t(x).T @ tensor.phi_f(x, u)

def inner_pi_us(us, xs):
    phi_x_primes = tensor.K_(us) @ tensor.phi(xs)
    inner_pi_us_response = -(cost(xs, us).T + gamma*(w_hat.T @ phi_x_primes)[:,0])
    return inner_pi_us_response

def pi_t_plus_1(w_hat, pi_t):
    # delta = 1e-25
    def g(us, xs):
        inner_pi_us_response = inner_pi_us(us, xs, w_hat) #(np.array([all_us]), xs, w_hat)
        print("inner_pi_us_response shape:", inner_pi_us_response.shape)
        inner_pi_us_response = np.real(inner_pi_us_response)
        max_inner_pi_u = np.amax(inner_pi_us_response, axis=0)
        print("max_inner_pi_u shape:", max_inner_pi_u.shape)
        diff = inner_pi_us_response - max_inner_pi_u
        print("diff shape:", diff.shape)
        pi_us = np.exp(diff) * pi_t(xs) # + delta
        print("pi_us shape:", pi_us.shape)
        Z_x = np.sum(pi_us, axis=0)
        print("Z_x shape:", Z_x)

        print("pi_us / Z_x shape:", (pi_us / Z_x).shape)
        return pi_us / Z_x

    return g

#%% ###Policy Iteration###

def pi_0(us, xs):
    return np.ones([us.shape[1], xs.shape[1]]) * 1 / all_us.shape[0]

all_pis = [pi_0]

batch_size = 512
iter = 10000
for i in range(iter):
    pi_t = all_pis[-1]
    w_hat = w_hat_t(pi_t)
    all_pis.append(pi_t_plus_1(w_hat, pi_t))
all_pis = np.array(all_pis)

#%% Test evaluation
pi_T = all_pis[-1]
print( pi_T(U[:,100], X[:,100]) )


"""
    ACCURACY PREDICTED.py
        by Tim Müller

    A script that is used to predict the accuracy of a predicted ranking and
    the expected ranking. Note that it reads the file outputted by
    predict_compare.py.
"""

import os
import sys
import argparse
import pandas as pd
from collections import defaultdict

DEFAULT_RANKING_LOCATION = "rankings.csv"
DEFAULT_PODIUM_SIZE = 3

def main(rankings_path, ranking_id, podium_size):
    print("\n*** ACCURACY computation for RANKINGS ***\n")

    print("Configuration:")
    print(f" - Rankings location : '{rankings_path}'")
    print(f" - ID to check       : {ranking_id}")
    print(f" - Size of podium    : {podium_size}")
    print("")

    print("Loading rankings... ", end=""); sys.stdout.flush()
    rankings = pd.read_csv(rankings_path)
    print("Done")

    print("Fetching ranking... ", end=""); sys.stdout.flush()
    # Fetch all rankings by ID, then put 'em in a dict
    params = None
    ranking = {"predicted_rowwise": {}, "benchmarked_rowwise": {}, "predicted_samplewise": {}, "benchmarked_samplewise": {}}
    for i, row in rankings[rankings["ranking_id"] == ranking_id].iterrows():
        if params is None: params = tuple(row.iloc[2:8])
        elif tuple(row.iloc[2:8]) != params:
            print(f"ERROR: Parameters for row {i} are unexpected.", file=sys.stderr)
            return -1
        ranking["predicted_rowwise"][row["ranking_position"]] = tuple(row.iloc[8:12])
        ranking["benchmarked_rowwise"][row["ranking_position"]] = tuple(row.iloc[12:16])
        ranking["benchmarked_samplewise"][tuple(row.iloc[12:15])] = row.iloc[15]
    print("Done\n")

    print("Computing accuracy... ", end=""); sys.stdout.flush()
    # This is where the magic happens!
    # METRIC 1: Absolute rank position: if they are correct they are correct, and if they are not they are not
    accuracy = 0
    total = 0
    for rank in ranking["predicted_rowwise"]:
        if ranking["predicted_rowwise"][rank][:3] == ranking["benchmarked_rowwise"][rank][:3]:
            accuracy += 1
        total += 1
    # Make it into an accuracy
    accuracy = accuracy / total * 100
    print("Done")

    print("Computing performance loss... ", end=""); sys.stdout.flush()
    # This is where the magic happens!
    # METRIC 2: Performance loss: we given the model points off for the benchmarked time of predicted best VS actual best
    performance_loss = defaultdict(int)
    total = 0
    for rank in range(min(len(ranking["predicted_rowwise"]), podium_size)):
        # Get the position of the actual best rank
        predicted_best = ranking["benchmarked_samplewise"][ranking["predicted_rowwise"][rank][:3]]
        actual_best = ranking["benchmarked_rowwise"][rank][3]
        performance_loss[rank] += abs(predicted_best - actual_best)
        performance_loss["total"] += abs(predicted_best - actual_best)
    print("Done\n")

    line_size = 60
    print(f"Ranking {ranking_id}:")
    print("  Predicted:" + " " * (line_size - 6) + "Benchmarked:")
    for i in ranking["predicted_rowwise"]:
        pm, pv, pt, pr = ranking["predicted_rowwise"][i]
        bm, bv, bt, br = ranking["benchmarked_rowwise"][i]

        text = f"   {i + 1}) {pm.upper()} ({pt} thread{'' if pt == 1 else 's'}) with {pv.upper()} ({pr:.4f}s)"
        text += " " * (line_size - len(text)) + " VS "
        text += f"   {i + 1}) {bm.upper()} ({bt} thread{'' if bt == 1 else 's'}) with {bv.upper()} ({br:.4f}s)"
        print(text)

    print(f"Accuracy               : {accuracy:.2f}%")
    print(f"Total performance loss : {performance_loss['total']:.6f}s")
    print(" - Per ranking:")
    for rank, runtime in {rank: performance_loss[rank] for rank in performance_loss if rank != 'total'}.items():
        print(f"    - Rank {rank + 1:02d}          : {runtime:.6f}s")

    print("\nDone.\n")

    return 0

if __name__ == "__main__":
    # Parse the arguments
    parser = argparse.ArgumentParser()

    parser.add_argument("-r", "--rankings", required=False, default=DEFAULT_RANKING_LOCATION, help="The location of the file containing the rankings.")
    parser.add_argument("-i", "--id", required=True, type=int, help="The ID of the ranking that we want to compare")
    parser.add_argument("-p", "--podium_size", required=False, type=int, default=DEFAULT_PODIUM_SIZE, help=f"Top N rankings to check for the performance loss metric. (DEFAULT: {DEFAULT_PODIUM_SIZE})")

    args = parser.parse_args()

    # Check if rankings exist
    if not os.path.exists(args.rankings):
        print(f"ERROR: File '{args.rankings}' does not exist.", file=sys.stderr)
        exit(-1)
    if not os.path.isfile(args.rankings):
        print(f"ERROR: File '{args.rankings}' is not a file.", file=sys.stderr)
        exit(-1)

    exit(main(args.rankings, args.id, args.podium_size))


from cgi import parse_qs, escape

def simple_app(environ, start_response):
    html = """

         POST:
        %(post)s

 GET:
        %(get)s

    """
    htmlfomet = """
 Key "%(key)s" = "%(value)s" """
    try:
        request_body_size = int(environ.get('CONTENT_LENGTH', 0))
    except (ValueError):
        request_body_size = 0
    request_body = environ['wsgi.input'].read(request_body_size)
    dataPost = parse_qs(request_body)
    keys = dataPost.keys()
    post = ""
    for k in keys:
        post = post + htmlfomet % {
                'key': escape(k),
                'value': dataPost[k]
                }
    dataGet = parse_qs(environ['QUERY_STRING'])
    keys = dataGet.keys()
    get = ""
    for k in keys:
        get = get + htmlfomet % {
                'key': escape(k),
                'value': dataGet[k]
                }

    response_body = html % {
            'post': post or 'None',
            'get': get or 'None'
            }
    status = '200 OK'
    response_headlers = [('Content-type', 'text/html'),
            ('Content-Length', str(len(response_body)))
            ]
    start_response(status, response_headlers)
    return [response_body]


import os
import os.path as osp
import random

import PIL
from PIL import Image
from matplotlib import pyplot as plt

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import transforms
import voc12
import cv2

def save_img(path, img, cam=None):

    plt.imshow(img)
    if cam is not None:
        plt.imshow(cam, cmap='jet', alpha=0.6)
    plt.axis('off')
    plt.tight_layout()
    plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0, hspace = 0, wspace = 0)
    plt.margins(0,0)
    plt.gca().xaxis.set_major_locator(plt.NullLocator())
    plt.gca().yaxis.set_major_locator(plt.NullLocator())
    plt.savefig(path)
    plt.close()

def cam_on_image(img, cam):

    heatmap = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET)
    heatmap = cv2.cvtColor(heatmap, cv2.COLOR_BGR2RGB)
    heatmap = np.float32(heatmap) / 255

    cam = heatmap.transpose((2,0,1)) + img
    cam = cam / np.max(cam)
    return np.uint8(255 * cam)

def cam_on_image2(img, cam_pos, cam_neg):

    heatmap_pos = cv2.applyColorMap(np.uint8(255 * cam_pos), cv2.COLORMAP_HOT)
    heatmap_neg = cv2.applyColorMap(np.uint8(255 * cam_neg), cv2.COLORMAP_COOL)
    heatmap_pos = cv2.cvtColor(heatmap_pos, cv2.COLOR_BGR2RGB)
    heatmap_neg = cv2.cvtColor(heatmap_neg, cv2.COLOR_BGR2RGB)
    heatmap_pos = np.float32(heatmap_pos) / 255
    heatmap_neg = np.float32(heatmap_neg) / 255

    cam = heatmap_pos.transpose((2,0,1))+ img #+heatmap_neg.transpose((2,0,1))
    cam = cam / np.max(cam)
    return np.uint8(255 * cam)

class random_resize():

    def __init__(self, min_long, max_long):
        self.min_long = min_long
        self.max_long = max_long

    def __call__(self, img, sal=None, get_xy=False, xy=None):

        target_long = random.randint(self.min_long, self.max_long)
        w, h = img.size

        if xy:
            target_long = xy

        if w < h:
            target_shape = (int(round(w * target_long / h)), target_long)
        else:
            target_shape = (target_long, int(round(h * target_long / w)))

        if xy:
            img = img.resize(target_shape, resample=PIL.Image.NEAREST)
        else:
            img = img.resize(target_shape, resample=PIL.Image.CUBIC)

        if sal:
           sal = sal.resize(target_shape, resample=PIL.Image.CUBIC)
           return img, sal

        if get_xy:
            return img, target_long
        else:
            return img

class GaussianBlur(object):
    """blur a single image on CPU"""
    def __init__(self, kernel_size):
        radias = kernel_size // 2
        kernel_size = radias * 2 + 1
        self.blur_h = nn.Conv2d(3, 3, kernel_size=(kernel_size, 1),
                                stride=1, padding=0, bias=False, groups=3)
        self.blur_v = nn.Conv2d(3, 3, kernel_size=(1, kernel_size),
                                stride=1, padding=0, bias=False, groups=3)
        self.k = kernel_size
        self.r = radias

        self.blur = nn.Sequential(
            nn.ReflectionPad2d(radias),
            self.blur_h,
            self.blur_v
        )

        self.pil_to_tensor = transforms.ToTensor()
        self.tensor_to_pil = transforms.ToPILImage()

    def __call__(self, img):
        img = self.pil_to_tensor(img).unsqueeze(0)

        sigma = np.random.uniform(0.1, 2.0)
        x = np.arange(-self.r, self.r + 1)
        x = np.exp(-np.power(x, 2) / (2 * sigma * sigma))
        x = x / x.sum()
        x = torch.from_numpy(x).view(1, -1).repeat(3, 1)

        self.blur_h.weight.data.copy_(x.view(3, 1, self.k, 1))
        self.blur_v.weight.data.copy_(x.view(3, 1, 1, self.k))

        with torch.no_grad():
            img = self.blur(img)
            img = img.squeeze()

        img = self.tensor_to_pil(img)

        return img

class random_crop():

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

    def __call__(self, imgarr, sal=None, get_xy=False, xy=None, seg=True):

        h, w, c = imgarr.shape

        ch = min(self.cropsize, h)
        cw = min(self.cropsize, w)

        w_space = w - self.cropsize
        h_space = h - self.cropsize

        if w_space > 0:
            cont_left = 0
            img_left = random.randrange(w_space+1)
        else:
            cont_left = random.randrange(-w_space+1)
            img_left = 0

        if h_space > 0:
            cont_top = 0
            img_top = random.randrange(h_space+1)
        else:
            cont_top = random.randrange(-h_space+1)
            img_top = 0

        if xy:
            cont_left, img_left, cont_top, img_top = xy

        if not xy or not seg:
            container = np.zeros((self.cropsize, self.cropsize, imgarr.shape[-1]), np.float32)
        else:
            container = np.ones((self.cropsize, self.cropsize, imgarr.shape[-1]), np.float32)*255
        container[cont_top:cont_top+ch, cont_left:cont_left+cw] = \
            imgarr[img_top:img_top+ch, img_left:img_left+cw]
        if sal is not None:
            container_sal = np.zeros((self.cropsize, self.cropsize,1), np.float32)
            container_sal[cont_top:cont_top+ch, cont_left:cont_left+cw,0] = \
                sal[img_top:img_top+ch, img_left:img_left+cw]
            return container, container_sal

        if get_xy:
            xy = cont_left, img_left, cont_top, img_top
            return container, xy
        else:
            return container

class normalize():
    def __init__(self, mean = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)):

        self.mean = mean
        self.std = std

    def __call__(self, img):
        imgarr = np.asarray(img)
        proc_img = np.empty_like(imgarr, np.float32)

        proc_img[..., 0] = (imgarr[..., 0] / 255. - self.mean[0]) / self.std[0]
        proc_img[..., 1] = (imgarr[..., 1] / 255. - self.mean[1]) / self.std[1]
        proc_img[..., 2] = (imgarr[..., 2] / 255. - self.mean[2]) / self.std[2]

        return proc_img

class normalize_res2vgg():
    def __init__(self, mean = (0.485, 0.456, 0.406), std = (0.229, 0.224, 0.225)):

        self.mean = mean
        self.std = std

    def __call__(self, img):
        imgarr = np.asarray(img)
        proc_img = np.empty_like(imgarr, np.float32)

        proc_img[..., 0] = (imgarr[..., 0] / 255. - self.mean[0]) / self.std[0]
        proc_img[..., 1] = (imgarr[..., 1] / 255. - self.mean[1]) / self.std[1]
        proc_img[..., 2] = (imgarr[..., 2] / 255. - self.mean[2]) / self.std[2]

        return proc_img

class AddGaussianNoise(object):
    def __init__(self, mean=0., std=1.):
        self.std = std
        self.mean = mean

    def __call__(self, tensor):
        return tensor + torch.randn(tensor.size()) * self.std + self.mean

    def __repr__(self):
        return self.__class__.__name__ + '(mean={0}, std={1})'.format(self.mean, self.std)

class normalize_vgg():
    def __init__(self, mean = (122.675, 116.669, 104.008)):

        self.mean = mean

    def __call__(self, img):
        imgarr = np.asarray(img) #RGB
        proc_img = np.empty_like(imgarr, np.float32)

        proc_img[..., 0] = (imgarr[..., 2] - self.mean[2])
        proc_img[..., 1] = (imgarr[..., 1] - self.mean[1])
        proc_img[..., 2] = (imgarr[..., 0] - self.mean[0])

        return proc_img #BGR

def invTrans(img):
    inv_trans= transforms.Compose([ transforms.Normalize(mean = [ 0., 0., 0. ],
                                                     std = [ 1/0.229, 1/0.224, 1/0.225 ]),
                                transforms.Normalize(mean = [ -0.485, -0.456, -0.406 ],
                                                     std = [ 1., 1., 1. ]),
                               ])
    return inv_trans(img)

def denorm(img):
    # ImageNet statistics
    mean_img = [0.485, 0.456, 0.406]
    std_img = [0.229, 0.224, 0.225]

    tf_denorm = transforms.Normalize(mean = [-mean_img[0] / std_img[0], -mean_img[1] / std_img[1], -mean_img[2] / std_img[2]],
                                     std = [1 / std_img[0], 1 / std_img[1], 1 / std_img[2]])

    return tf_denorm(img)

def norm(img):
    # ImageNet statistics
    mean_img = [0.485, 0.456, 0.406]
    std_img = [0.229, 0.224, 0.225]

    tf_norm = transforms.Normalize(mean = [mean_img[0], mean_img[1], mean_img[2]],std = [std_img[0],std_img[1], std_img[2]])

    return tf_norm(img)

def norm_vgg(img):
    # ImageNet statistics
    mean_img = [122.675, 116.669, 104.008]
    # std_img = [0.229, 0.224, 0.225]

    tf_norm = transforms.Normalize(mean = [mean_img[0], mean_img[1], mean_img[2]],std = [1,1,1])

    return tf_norm(img)

def norm_gray(img):
    # ImageNet statistics
    mean_img = [0.485, 0.456, 0.406]
    std_img = [0.229, 0.224, 0.225]

    tf_norm = transforms.Normalize(mean = [mean_img[0]],std = [std_img[0]])

    return tf_norm(img)

class Upsample(nn.Module):
    """ nn.Upsample is deprecated """

    def __init__(self, scale_factor, mode="nearest"):
        super(Upsample, self).__init__()
        self.scale_factor = scale_factor
        self.mode = mode

    def forward(self, x):
        x = F.interpolate(x, scale_factor=self.scale_factor, mode=self.mode)
        return x

def denorm_vgg(img):
    # ImageNet statistics
    # mean_img = [0.485, 0.456, 0.406]
    mean = [122.675, 116.669, 104.008] #RGB

    img= img.permute(1,2,0).cpu().detach().numpy()

    # img = img.permute(1,2,0) #c h w to h w c

    imgarr = np.asarray(img)
    proc_img = np.empty_like(imgarr, np.float32)

    proc_img[..., 0] = (imgarr[..., 2] + mean[0])
    proc_img[..., 1] = (imgarr[..., 1] + mean[1])
    proc_img[..., 2] = (imgarr[..., 0] + mean[2])

    proc_img = proc_img.transpose((2,0,1))

    proc_img=proc_img/255.

    return proc_img

def denorm_vgg2(img):
    # ImageNet statistics
    # mean_img = [0.485, 0.456, 0.406]
    mean = [122.675, 116.669, 104.008]  # RGB

    img = img.permute(1, 2, 0).cpu().detach().numpy()

    # img = img.permute(1,2,0) #c h w to h w c

    imgarr = np.asarray(img)
    proc_img = np.empty_like(imgarr, np.float32)

    proc_img[..., 0] = (imgarr[..., 2] + mean[0])
    proc_img[..., 1] = (imgarr[..., 1] + mean[1])
    proc_img[..., 2] = (imgarr[..., 0] + mean[2])

    # proc_img = proc_img.transpose((2, 0, 1))

    proc_img=proc_img/255.

    return proc_img

    #
    #
    # tf_denorm = transforms.Normalize(mean = [-mean_img[0], -mean_img[1], -mean_img[2]],std=[1,1,1])
    #
    # return tf_denorm(img)

def HWC_to_CHW(tensor, sal=False):
    if sal:
        tensor = np.expand_dims(tensor, axis=0)
    else:
        tensor = np.transpose(tensor, (2, 0, 1))
    return tensor

def voc_palette(label):
	m = label.astype(np.uint8)
	r,c = m.shape
	cmap = np.zeros((r,c,3), dtype=np.uint8)
	cmap[:,:,0] = (m&1)<<7 | (m&8)<<3
	cmap[:,:,1] = (m&2)<<6 | (m&16)<<2
	cmap[:,:,2] = (m&4)<<5
	cmap[m==255] = [255,255,255]
	return cmap

def crf_inference(img, probs, t=10, scale_factor=1, labels=21):
    import pydensecrf.densecrf as dcrf
    from pydensecrf.utils import unary_from_softmax

    h, w = img.shape[:2]
    n_labels = labels

    d = dcrf.DenseCRF2D(w, h, n_labels)

    unary = unary_from_softmax(probs)
    unary = np.ascontiguousarray(unary)

    d.setUnaryEnergy(unary)
    d.addPairwiseGaussian(sxy=3/scale_factor, compat=3)
    d.addPairwiseBilateral(sxy=80/scale_factor, srgb=13, rgbim=np.copy(img), compat=10)
    Q = d.inference(t)

    return np.array(Q).reshape((n_labels, h, w))

def _crf_with_alpha(cam_dict, img, alpha=10):
        orig_img = np.ascontiguousarray(np.uint8(Image.open(os.path.join('./data/VOC2012/JPEGImages', img + '.jpg'))))
        mean_img = [0.485, 0.456, 0.406]
        std_img = [0.229, 0.224, 0.225]

        # tf_denorm = transforms.Normalize(
        #     mean=[-mean_img[0] / std_img[0], -mean_img[1] / std_img[1], -mean_img[2] / std_img[2]],
        #     std=[1 / std_img[0], 1 / std_img[1], 1 / std_img[2]])

        # img = tf_denorm(img).permute(1,2,0).detach().cpu().numpy()
        # orig_img = np.ascontiguousarray(np.uint8(img*255))

        v = np.array(list(cam_dict.values()))
        bg_score = np.power(1 - np.max(v, axis=0, keepdims=True), alpha)
        bgcam_score = np.concatenate((bg_score, v), axis=0)
        crf_score = crf_inference_ysh(orig_img, bgcam_score, labels=bgcam_score.shape[0])

        n_crf_al = dict()

        n_crf_al[0] = crf_score[0]
        for i, key in enumerate(cam_dict.keys()):
            n_crf_al[key + 1] = crf_score[i + 1]

        return n_crf_al

def _crf_with_alpha_nodict(cam_dict, img, alpha=10):
    # orig_img = np.ascontiguousarray(np.uint8(Image.open(os.path.join('./data/VOC2012/JPEGImages', img + '.jpg'))))
    mean_img = [0.485, 0.456, 0.406]
    std_img = [0.229, 0.224, 0.225]

    tf_denorm = transforms.Normalize(
        mean=[-mean_img[0] / std_img[0], -mean_img[1] / std_img[1], -mean_img[2] / std_img[2]],
        std=[1 / std_img[0], 1 / std_img[1], 1 / std_img[2]])

    # img = tf_denorm(img).permute(1,2,0).detach().cpu().numpy()
    # orig_img = np.ascontiguousarray(np.uint8(img*255))
    img = img.permute(1,2,0).detach().cpu().numpy()
    orig_img = np.ascontiguousarray(np.uint8(img*255))

    v = np.array(list(cam_dict.values()))
    bg_score = np.power(1 - np.max(v, axis=0, keepdims=True), alpha)
    bgcam_score = np.concatenate((bg_score, v), axis=0)
    crf_score = crf_inference_ysh(orig_img, bgcam_score, labels=bgcam_score.shape[0])

    # return crf_score
    n_crf_al = dict()

    n_crf_al[0] = crf_score[0]
    for i, key in enumerate(cam_dict.keys()):
        n_crf_al[key + 1] = crf_score[i + 1]

    return n_crf_al

def _crf_with_alpha_rrm(cam_dict, img, alpha=10):
    # orig_img = np.ascontiguousarray(np.uint8(Image.open(os.path.join('./data/VOC2012/JPEGImages', name + '.jpg'))))
    mean_img = [0.485, 0.456, 0.406]
    std_img = [0.229, 0.224, 0.225]

    # tf_denorm = transforms.Normalize(
    #     mean=[-mean_img[0] / std_img[0], -mean_img[1] / std_img[1], -mean_img[2] / std_img[2]],
    #     std=[1 / std_img[0], 1 / std_img[1], 1 / std_img[2]])

    img = img.permute(1, 2, 0).detach().cpu().numpy()
    orig_img = np.ascontiguousarray(np.uint8(img * 255))

    v = np.array(list(cam_dict.values()))
    bg_score = np.power(1 - np.max(v, axis=0, keepdims=True), alpha)
    bgcam_score = np.concatenate((bg_score, v), axis=0)
    crf_score = crf_inference_ysh(orig_img, bgcam_score, labels=bgcam_score.shape[0])

    n_crf_al = np.zeros([21, bg_score.shape[1], bg_score.shape[2]])

    n_crf_al[0] = crf_score[0]
    for i, key in enumerate(cam_dict.keys()):
        n_crf_al[key + 1] = crf_score[i + 1]

    return n_crf_al

import PIL.Image
import random
import numpy as np

def crf_inference_ysh(img, probs, t=10, scale_factor=1, labels=21): #t=10 best
    import pydensecrf.densecrf as dcrf
    from pydensecrf.utils import unary_from_softmax

    h, w = img.shape[:2]
    n_labels = labels

    d = dcrf.DenseCRF2D(w, h, n_labels)

    unary = unary_from_softmax(probs)
    unary = np.ascontiguousarray(unary)

    d.setUnaryEnergy(unary)
    d.addPairwiseGaussian(sxy=3/scale_factor, compat=3)
    d.addPairwiseBilateral(sxy=80/scale_factor, srgb=13, rgbim=np.copy(img), compat=10)
    # d.addPairwiseGaussian(sxy=1, compat=3)
    # d.addPairwiseBilateral(sxy=67, srgb=3, rgbim=np.copy(img), compat=4)
    # d.addPairwiseGaussian(sxy=3, compat=3)
    # d.addPairwiseBilateral(sxy=80, srgb=13, rgbim=np.copy(img), compat=4)

    Q = d.inference(t)

    return np.array(Q).reshape((n_labels, h, w))

def crf_dl(name, probs, t=10, scale_factor=1, labels=21):
    import pydensecrf.densecrf as dcrf
    from pydensecrf.utils import unary_from_softmax

    image_path = os.path.join('./data/VOC2012/JPEGImages', name + '.jpg')
    img = cv2.imread(image_path, cv2.IMREAD_COLOR).astype(np.float32)
    # img = img - np.array([104.008,116.669,122.675]) #Not used
    img = np.ascontiguousarray(np.uint8(img))

    # img_temp = cv2.imread(image_path)
    # img_temp = cv2.cvtColor(img_temp, cv2.COLOR_BGR2RGB).astype(np.float)
    # img = img_temp.astype(np.uint8)

    h, w = img.shape[:2]
    n_labels = labels

    d = dcrf.DenseCRF2D(w, h, n_labels)

    unary = unary_from_softmax(probs)
    unary = np.ascontiguousarray(unary)

    d.setUnaryEnergy(unary)

    # d.addPairwiseGaussian(sxy=1, compat=3)  # 64.85
    # d.addPairwiseBilateral(sxy=67, srgb=3, rgbim=np.copy(img), compat=4)  # 64.85

    d.addPairwiseGaussian(sxy=1, compat=3)  # 64.86/no normal
    d.addPairwiseBilateral(sxy=67, srgb=3, rgbim=np.copy(img), compat=4)  #64.86/no normal

    # d.addPairwiseGaussian(sxy=3, compat=3)  #RRM
    # d.addPairwiseBilateral(sxy=80, srgb=13, rgbim=np.copy(img), compat=10)  #RRM t=10

    # d.addPairwiseGaussian(sxy=1, compat=3) #good
    # d.addPairwiseBilateral(sxy=67, srgb=3, rgbim=np.copy(img), compat=4) #good

    # d.addPairwiseGaussian(sxy=2, compat=3,kernel=dcrf.DIAG_KERNEL,normalization=dcrf.NORMALIZE_SYMMETRIC)
    # d.addPairwiseBilateral(sxy=80, srgb=13, rgbim=np.copy(img),kernel=dcrf.DIAG_KERNEL, normalization=dcrf.NORMALIZE_SYMMETRIC,compat=4) #good

    # d.addPairwiseGaussian(sxy=2, compat=3, kernel=dcrf.DIAG_KERNEL, normalization=dcrf.NORMALIZE_SYMMETRIC)
    # d.addPairwiseBilateral(sxy=80, srgb=13, rgbim=np.copy(img), kernel=dcrf.DIAG_KERNEL,normalization=dcrf.NORMALIZE_SYMMETRIC, compat=4)  # good

    Q = d.inference(t)

    return np.array(Q).reshape((n_labels, h, w))

def _crf_with_alpha_rrm(cam_dict, img, alpha=10):
        # orig_img = np.ascontiguousarray(np.uint8(Image.open(os.path.join('./data/VOC2012/JPEGImages', name + '.jpg'))))
        mean_img = [0.485, 0.456, 0.406]
        std_img = [0.229, 0.224, 0.225]

        tf_denorm = transforms.Normalize(
            mean=[-mean_img[0] / std_img[0], -mean_img[1] / std_img[1], -mean_img[2] / std_img[2]],
            std=[1 / std_img[0], 1 / std_img[1], 1 / std_img[2]])

        img = tf_denorm(img).permute(1,2,0).detach().cpu().numpy()
        orig_img = np.ascontiguousarray(np.uint8(img*255))

        v = np.array(list(cam_dict.values()))
        bg_score = np.power(1 - np.max(v, axis=0, keepdims=True), alpha)
        bgcam_score = np.concatenate((bg_score, v), axis=0)
        crf_score = crf_inference_ysh(orig_img, bgcam_score, labels=bgcam_score.shape[0])

        n_crf_al = np.zeros([21, bg_score.shape[1], bg_score.shape[2]])

        n_crf_al[0] = crf_score[0]
        for i, key in enumerate(cam_dict.keys()):
            n_crf_al[key + 1] = crf_score[i + 1]

        return n_crf_al


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Dec 19 20:35:53 2019

@author: maxime
"""
from datetime import date
import pandas as pd

from .base import CyclingInitBot, PyItem, Race
from .data import calendar_list

class ChampListCreator(CyclingInitBot):
    def __init__(
            self,
            man_or_woman:str,
            start_year:int,
            actualize:bool):
        '''
        Perform queries in wikidata to find out the national champions for all years. It is saved in a csv file.
        It is a kind of cashing of this queries, as it would too long to perform it every time it is needed.

        Parameters
        ----------
        man_or_woman : str
            age category and gender of the races to be created
        start_year : int
        actualize : bool
            Do we want to actualize the list or recreated it completely
        '''
        super().__init__()
        self.man_or_woman=man_or_woman
        self.start_year=start_year
        self.end_year=date.today().year+1
        self.actualize=actualize

        self.dic =calendar_list.nationChampionshipMaster()
        self.dic_road_race_women, self.dic_clm_women,\
        self.dic_road_race_men, self.dic_clm_men=calendar_list.worldCCchampionships()

        self.champ_table=[]

        self.verbose=False

    def main(self):
        '''
        Main function of this script
        '''
        #Road
        if self.man_or_woman=="woman":
            self.filename='src/input/champ2.csv'
            self.old_filename='src/input/champ.csv'
            self.dic_worldconti=self.dic_road_race_women
            self.pattern="Course en ligne féminine aux"
        else:
            self.filename='src/input/champ_man2.csv'
            self.old_filename='src/input/champ_man.csv'
            self.dic_worldconti=self.dic_road_race_men
            self.pattern="Course en ligne masculine aux"

        self.road_or_clm='Road'
        self.sub_create_champ()

        print("road scan finished")
        #Clm
        if self.man_or_woman=="woman":
            self.dic_worldconti=self.dic_clm_women
            self.pattern="Contre-la-montre féminin aux"
        else:
            self.dic_worldconti=self.dic_clm_men
            self.pattern="Contre-la-montre masculin aux"
        self.road_or_clm='Clm'
        self.sub_create_champ()
        print("itt scan finished")

        final_df=pd.DataFrame(self.champ_table)
        if self.actualize:
            old_df = pd.read_csv(self.old_filename,index_col=0)
            old_df=old_df[old_df["WorldCC"]==False] #remove the world
            old_df=old_df[old_df["Year"]<self.start_year]
            final_df=pd.concat([old_df, final_df])

        final_df.to_csv(self.filename)
        print("csv file " + self.filename + " written")

    def sub_findwinner(
            self,
            pyItem:PyItem,
            id_race:str,
            WorldCC:bool=False,
            ):
          '''
            Look for winner in the races, it remove races that does not seem to have correct information

            Parameters
            ----------
            pyItem : PyItem
            id_race : str
                Wikidata id of the race
            WorldCC : bool, optional
                If the race is not a national championship
          '''

          date_found=False
          invalid_precision=False
          there_is_a_winner=False
          warning_written=False
          row={}
          row['Champ']=id_race

          if (u'P585' in pyItem.item.claims):
             list_of_race_date=pyItem.item.claims.get(u'P585')
             race_date=list_of_race_date[0].getTarget()
             if race_date is None:
                 invalid_precision=True
             elif ((race_date.day==1 and race_date.month==1) or
                 race_date.day==0 or
                 race_date.month==0):
                 invalid_precision=True
             else:
                 date_found=True

          if (u'P1346' in pyItem.item.claims): #winner
             winners=pyItem.item.claims.get(u'P1346')
             for winner in winners:
                 there_is_qual=False
                 id_this_qual=None

                 for qual in winner.qualifiers.get('P642', []):
                     there_is_qual=True
                 if there_is_qual:
                     id_this_qual=winner.qualifiers['P642'][0].getTarget().getID()
                 else:
                     print(pyItem.get_label('fr'))
                     print("no qualifier")

                 if id_this_qual is not None and id_this_qual=='Q20882667': #winner general classification
                     #check qualifier
                     if winner.getTarget() is not None:
                         id_temp_winner=winner.getTarget().getID()
                         there_is_a_winner=True
                     if date_found and there_is_a_winner:
                         row['Day']=race_date.day
                         row['Month']=race_date.month
                         row['Year']=race_date.year
                         row['Winner']=id_temp_winner
                         if WorldCC:
                             row['WorldCC']=True
                         else:
                             row['WorldCC']=False
                         if self.road_or_clm=="Clm":
                             row['Clm']=True
                         else:
                             row['Clm']=False
                         self.champ_table.append(row)
                     elif invalid_precision and there_is_a_winner:
                         if warning_written==False:
                             print(pyItem.get_label('fr'))
                             print('unsufficient precision')
                             warning_written=True

    def sub_champlist(self):
        '''
        Run the search of winners in each race of self.dic_worldconti
        '''
        for id_race in self.dic_worldconti:
            race=Race(id=id_race)
            if(u'P527' in race.item.claims):
                 for e in race.item.claims.get(u'P527'):
                     pyItem_this_year=PyItem(id=e.getTarget().getID())
                     self.sub_findwinner(pyItem_this_year, id_race,WorldCC=True)

    def sub_course(self,race):
        '''
        Check the nature of the race and perform the winner search in the parent if necessary
        '''
        this_label=race.get_label('fr')
        if this_label.find(self.pattern)==0: #filter with fr label
            if (u'P31' in race.item.claims):
                list_of_nature=race.item.claims.get(u'P31')
                id_master=list_of_nature[0].getTarget().getID()
            else:
                id_master=u'Q1'
            self.sub_findwinner(race, id_master)

    def sub_create_champ(self):
        '''
        Create the result table

        Note: world and continental championships are recreated all the time
        '''
        self.sub_champlist()
        self.log.concat(self.road_or_clm +" world and continental championships "+ \
                        self.man_or_woman + " completed")

        if self.verbose:
            self.log.concat(self.WorldCC_champ_table)

        #Look in the national championships
        for year in range(self.start_year,self.end_year):
            year=str(year)
            self.log.concat(self.road_or_clm + " start year " + year)

            pyItem_all_national=PyItem(id=self.dic[year])

            if(u'P527' in pyItem_all_national.item.claims):
                 for e in pyItem_all_national.item.claims.get(u'P527'):
                     race_this_national=Race(id=e.getTarget().getID())

                     if(u'P527' in race_this_national.item.claims):
                         for e2 in race_this_national.item.claims.get(u'P527'):
                             race_this_year=Race(id=e2.getTarget().getID())
                             self.sub_course(race_this_year)
                     else:
                         print(race_this_national.get_label('fr') + " has no P527")