from rest_framework.decorators import api_view, authentication_classes, permission_classes
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from django.core.mail import EmailMultiAlternatives
from rest_framework.response import Response
from rest_framework import generics
from rest_framework import status
from datetime import date
from auth_api.models import *
from auth_api.serializers import *
from auth_api.models import *

#########################################################################
# Start Shop CRUD
#########################################################################
@api_view(['POST','PUT', 'DELETE' ])
def ShopCUDView(request):
    trail = {}

    # Create Factor
    if request.method == 'POST':
        print(request.data)
        serializer = ShopCreateSerializer(data=request.data)
        if serializer.is_valid():
            new_object = serializer.save(user=request.user)
            trail['message'] = "Shop Sucessfully Created"
            trail['shop_id'] = new_object.shop_id
            trail['shop_name'] = new_object.shop_name
            return Response(trail, status=status.HTTP_200_OK)
        else:
            trail = serializer.errors
            return Response(trail, status=status.HTTP_403_FORBIDDEN)

    # Edit Factor
    if request.method == 'PUT':
        try:
            shop = ShopModel.objects.get(shop_id=request.data.get("shop_id"))
        except:
            raise serializers.ValidationError('Not Found')

        serializer = ShopEditSerializer(shop, data=request.data)
        if serializer.is_valid():
            serializer.save()
            trail["message"] = "Shop Successfully Updated"
            trail["data"] =  serializer.data
            return Response(trail, status=status.HTTP_200_OK)
        else:
            trail = serializer.errors
            return Response(trail, status=status.HTTP_403_FORBIDDEN)

    # Delet Factor
    if request.method == 'DELETE':
        try:
            shop = ShopModel.objects.get(shop_id=request.data.get("shop_id"))
        except:
            raise serializers.ValidationError('Not Found')
        shop.delete()
        trail["message"] = "Shop Successfully Deleted"
        return Response(trail, status=status.HTTP_200_OK)

#########################################################################

#########################################################################
# Shop List from app
@api_view(['POST', ])
def ShopListView(request):
    if request.method == 'POST':
        factors = ShopModel.objects.all()
        trail = []
        frag = {}
        for i in range(0, len(factors)):
            frag['shop_name'] = factors[i].shop_name
            frag['shop_id'] = factors[i].shop_id
            frag['shop_address'] = factors[i].shop_address
            frag['shop_mobile'] = factors[i].shop_mobile
            frag['shop_license'] = factors[i].shop_license
            frag['subscription_type'] = factors[i].subscription_type
            frag['subscription_start'] = factors[i].subscription_start
            frag['subscription_end'] = factors[i].subscription_end
            trail.append(frag)
            frag = {}
        return Response(trail)

#########################################################################

#########################################################################
# Shop Detail from app
@api_view(['POST', ])
def ShopDetailView(request):
    if request.method == 'POST':
        # print(request.user.shop)

        factor = ShopModel.objects.get(shop_id = request.data.get("shop_id"))
        # factor = ShopModel.objects.get(shop_id = request.user.shop.shop_id)

        # try:
        # except:
        #     raise serializers.ValidationError('Not Found')

        frag = {}
        frag['shop_name'] = factor.shop_name
        frag['shop_id'] = factor.shop_id
        frag['shop_active'] = factor.shop_active
        frag['shop_address'] = factor.shop_address
        frag['shop_mobile'] = factor.shop_mobile
        frag['shop_logo'] = factor.shop_logo
        frag['subscription_type'] = factor.subscription_type
        frag['subscription_start'] = factor.subscription_start
        frag['subscription_end'] = factor.subscription_end

        # ##################################################################################
        # today = date.today()
        # product_valuation = 0
        # month_revenue = 0
        # day_revenue = 0

        # products = ProductModel.objects.filter(shop = factor)
        # orders = OrderModel.objects.filter(shop = factor).filter(time_stamp__month = today.month)

        # for x in range(0, len(products)):
        #     if (products[x].product_stock):
        #         product_valuation += products[x].product_stock * products[x].product_mrp_price

        # for x in range(0, len(orders)):
        #     month_revenue += orders[x].order_price

        # frag['product_count'] = len(products)
        # frag['product_valuation'] = product_valuation
        # frag['month_revenue'] = month_revenue

        # orders = orders.filter(time_stamp__day = today.day)
        # for x in range(0, len(orders)):
        #     day_revenue += orders[x].order_price
        # frag['day_revenue'] = day_revenue

        # print(orders)
        # ##################################################################################

        # # User Details { Admin, Subadmin }
        # user = request.user
        # if user.user_type == 1:
        #     frag['username'] = user.username
        #     frag['mobile_number'] = user.mobile_number
        #     frag['user_type'] = user.user_type
        #     owner = AdminModel.objects.get(user = user)
        #     frag['owner_name'] = owner.owner_name
        #     frag['owner_address'] = owner.owner_address
        #     frag['owner_mobile'] = owner.owner_mobile

        #     frag['user_database'] = 1
        #     frag['lead_followup'] = 1
        #     frag['invoice_followup'] = 1
        #     frag['task_followup'] = 1
        #     frag['journal'] = 1

        # elif user.user_type == 2:
        #     frag['username'] = user.username
        #     frag['mobile_number'] = user.mobile_number
        #     frag['user_type'] = user.user_type

        #     manager = SubadminModel.objects.get(user = user)
        #     print(user.shop)
        #     manager_permission = SubadminPermisionModel.objects.get(shop = user.shop)

        #     frag['manager_name'] = manager.manager_name
        #     frag['manager_address'] = manager.manager_address
        #     frag['manager_mobile'] = manager.manager_mobile

        #     frag['user_database'] = manager_permission.user_database
        #     frag['lead_followup'] = manager_permission.lead_followup
        #     frag['invoice_followup'] = manager_permission.invoice_followup
        #     frag['task_followup'] = manager_permission.task_followup
        #     frag['journal'] = manager_permission.journal

        return Response(frag)

#########################################################################
##  End Shop CRUD  ##
#########################################################################

#########################################################################
#  Party Update Delete
@api_view(['POST',])
def BankDetailsUpdateView(request):
    admin = Admin.objects.get(user=request.user.user_id)
    shop = Shop.objects.get(shop_license=admin.shop)
    bankdetail = Bankdetails.objects.filter(shop=shop)

    if request.method == 'POST':
        serializer = EditPartySerializer(bankdetail[0], data=request.data)
        data = {}
        if serializer.is_valid():
            serializer.save()
            data["message"] = "Successfully Updated"
            data["Data"] = serializer.data

            return Response(data, status=status.HTTP_200_OK)
        return Response(serializer.errors)

#########################################################################
# Bankdetails Edit bot reqs
@api_view(['POST'])
def BankDetailsUpdateView(request):
    try:
        admin = Admin.objects.get(user=request.user.user_id)
        shop = Shop.objects.get(shop_license=admin.shop)
        bank = Bankdetails.objects.filter(shop=shop)

    except:
        return Response({'message':'Not valid parameters'}, status=status.HTTP_400_BAD_REQUEST)

    if request.method == 'POST':
        print(request.data)
        serializer = EditBankDetailsSerializer(bank[0], data=request.data)
        data = {}
        if serializer.is_valid():
            serializer.save()
            data["message"] = "Successfully Updated"
            data["Data"] = serializer.data
            return Response(data, status=status.HTTP_200_OK)
        return Response(serializer.errors)

#########################################################################
# Start SubadminPermission CRUD
#########################################################################
@api_view(['PUT' ])
def SubadminPermissionCUDView(request):
    trail = {}
    # Edit Factor
    if request.method == 'PUT':
        try:
            manager_permission = SubadminPermisionModel.objects.get(manager_permission_id=request.data.get("manager_permission_id"))
        except:
            raise serializers.ValidationError('Not Found')

        serializer = SubadminPermissionEditSerializer(manager_permission, data=request.data)
        if serializer.is_valid():
            serializer.save()
            trail["message"] = "Subadmin Permission Successfully Updated"
            trail["data"] =  serializer.data
            return Response(trail, status=status.HTTP_200_OK)
        else:
            trail = serializer.errors
            return Response(trail, status=status.HTTP_403_FORBIDDEN)

#########################################################################

#########################################################################
##  End SubadminPermission CRUD  ##
#########################################################################


#! /usr/bin/env python3

import os
import sys
import argparse
try:
    import configparser
except:
    import ConfigParser as configparser
import signal
import csv
import json
from datetime import datetime, timedelta
import time
import random

# ----------------------------------------
def pause(question='PRESS ENTER TO CONTINUE ...'):
    """ pause for debug purposes """
    try:
        input(question)
    except KeyboardInterrupt:
        global shutDown
        shutDown = True
    except:
        pass

# ----------------------------------------
def signal_handler(signal, frame):
    print('USER INTERUPT! Shutting down ... (please wait)')
    global shutDown
    shutDown = True
    return

# ----------------------------------------
def splitCost(a, b):
    return (a * b)

# ----------------------------------------
def mergeCost(a, b):
    return (a * b)

# ----------------------------------------
def makeKeytable(fileName, tableName):

    print('loading %s ...' % fileName)

    try:
        with open(fileName, 'r') as f:
            headerLine = f.readline()
    except IOError as err:
        print(err)
        return None
    csvDialect = csv.Sniffer().sniff(headerLine)
    columnNames = next(csv.reader([headerLine], dialect=csvDialect))
    columnNames = [x.upper() for x in columnNames]

    fileMap = {}
    fileMap['algorithmName'] = '<name of the algorthm that produced the entity map>'
    fileMap['clusterField'] = '<csvFieldName> for unique ID'
    fileMap['recordField'] = '<csvFieldName> for the record ID'
    fileMap['sourceField'] = '<csvFieldName> for the data source (only required if multiple)'
    fileMap['sourceValue'] = 'hard coded value that matches Senzing data source source'
    fileMap['scoreField'] = '<csvFieldName> for the matching score (optional)'

    if 'RESOLVED_ENTITY_ID' in columnNames and 'DATA_SOURCE' in columnNames and 'RECORD_ID' in columnNames:
        fileMap['algorithmName'] = 'Senzing'
        fileMap['clusterField'] = 'RESOLVED_ENTITY_ID'
        fileMap['recordField'] = 'RECORD_ID'
        fileMap['sourceField'] = 'DATA_SOURCE'
        fileMap['scoreField'] = 'MATCH_KEY'
    elif 'CLUSTER_ID' in columnNames and 'RECORD_ID' in columnNames:
        fileMap['algorithmName'] = 'Other'
        fileMap['clusterField'] = 'CLUSTER_ID'
        fileMap['recordField'] = 'RECORD_ID'
        if 'DATA_SOURCE' in columnNames:
            fileMap['sourceField'] = 'DATA_SOURCE'
        else:
            del fileMap['sourceField']
            print()
            fileMap['sourceValue'] = input('What did you name the data_source? ')
            print()
            if not fileMap['sourceValue']:
                print('Unfortunately a data source name is required. process aborted.')
                print()
                return None
        if 'SCORE' in columnNames:
            fileMap['scoreField'] = 'SCORE'
        else:
            del fileMap['scoreField']
    else:
        if not os.path.exists(fileName + '.map'):
            print('')
            print('please describe the fields for ' + fileName + ' as follows in a file named ' + fileName + '.map')
            print(json.dumps(fileMap, indent=4))
            print('')
            return None
        else:
            try:
                fileMap = json.load(open(fileName + '.map'))
            except ValueError as err:
                print('error opening %s' % (fileName + '.map'))
                print(err)
                return None
            if 'clusterField' not in fileMap:
                print('clusterField missing from file map')
                return None
            if 'recordField' not in fileMap:
                print('recordField missing from file map')
                return None
            if 'sourceField' not in fileMap and 'sourceValue' not in fileMap:
                print('either a sourceField or sourceValue must be specified in the file map')
                return None

    fileMap['fileName'] = fileName
    fileMap['tableName'] = tableName
    fileMap['columnHeaders'] = columnNames
    if fileMap['clusterField'] not in fileMap['columnHeaders']:
        print('column %s not in %s' % (fileMap['clusterField'], fileMap['fileName']))
        return 1
    if fileMap['recordField'] not in fileMap['columnHeaders']:
        print('column %s not in %s' % (fileMap['recordField'], fileMap['fileName']))
        return 1
    # if  fileMap['sourceField'] not in fileMap['columnHeaders']:
    #    print('column %s not in %s' % (fileMap['sourceField'], fileMap['fileName']))
    #    return 1

    fileMap['clusters'] = {}
    fileMap['records'] = {}
    fileMap['relationships'] = {}
    nextMissingCluster_id = 0

    with open(fileMap['fileName'], 'r') as csv_file:
        csv_reader = csv.reader(csv_file, dialect=csvDialect)
        next(csv_reader)  # --remove header
        for row in csv_reader:
            rowData = dict(zip(columnNames, row))
            if fileMap['algorithmName'] == 'Senzing' and 'RELATED_ENTITY_ID' in rowData and rowData['RELATED_ENTITY_ID'] != '0':
                ent1str = str(rowData['RESOLVED_ENTITY_ID'])
                ent2str = str(rowData['RELATED_ENTITY_ID'])
                relKey = ent1str + '-' + ent2str if ent1str < ent2str else ent2str + '-' + ent1str
                if relKey not in fileMap['relationships']:
                    fileMap['relationships'][relKey] = rowData['MATCH_KEY']
                continue
            if 'sourceField' in fileMap:
                sourceValue = rowData[fileMap['sourceField']]
            else:
                sourceValue = fileMap['sourceValue']
            if 'scoreField' in fileMap:
                scoreValue = rowData[fileMap['scoreField']]
            else:
                scoreValue = None

            rowData[fileMap['recordField']] = str(rowData[fileMap['recordField']]) + '|DS=' + str(sourceValue)
            if not rowData[fileMap['clusterField']]:
                nextMissingCluster_id += 1
                rowData[fileMap['clusterField']] = '(sic) ' + str(nextMissingCluster_id)
            else:
                rowData[fileMap['clusterField']] = str(rowData[fileMap['clusterField']])
            fileMap['records'][rowData[fileMap['recordField']]] = rowData[fileMap['clusterField']]
            if rowData[fileMap['clusterField']] not in fileMap['clusters']:
                fileMap['clusters'][rowData[fileMap['clusterField']]] = {}
            fileMap['clusters'][rowData[fileMap['clusterField']]][rowData[fileMap['recordField']]] = scoreValue

    return fileMap

def erCompare(fileName1, fileName2, outputRoot):

    # --load the second file into a database table (this is the prior run or prior ground truth)
    fileMap2 = makeKeytable(fileName2, 'prior')
    if not fileMap2:
        return 1

    # --load the first file into a database table (this is the newer run or candidate for adoption)
    fileMap1 = makeKeytable(fileName1, 'newer')
    if not fileMap1:
        return 1

    # --set output files and columns
    outputCsvFile = outputRoot + '.csv'
    outputJsonFile = outputRoot + '.json'
    try:
        csvHandle = open(outputCsvFile, 'w')
    except IOError as err:
        print(err)
        print('could not open output file %s' % outputCsvFile)
        return 1

    csvHeaders = []
    csvHeaders.append('audit_id')
    csvHeaders.append('audit_category')
    csvHeaders.append('audit_result')
    csvHeaders.append('data_source')
    csvHeaders.append('record_id')
    csvHeaders.append('prior_id')
    csvHeaders.append('prior_score')
    csvHeaders.append('newer_id')
    csvHeaders.append('newer_score')
    try:
        csvHandle.write(','.join(csvHeaders) + '\n')
    except IOError as err:
        print(err)
        print('could not write to output file %s' % outputCsvFile)
        return
    nextAuditID = 0

    # --initialize stats
    statpack = {}
    statpack['SOURCE'] = 'G2Audit'

    statpack['ENTITY'] = {}
    statpack['ENTITY']['PRIOR_COUNT'] = 0
    statpack['ENTITY']['NEWER_COUNT'] = 0
    statpack['ENTITY']['COMMON_COUNT'] = 0

    statpack['CLUSTERS'] = {}
    statpack['CLUSTERS']['PRIOR_COUNT'] = 0
    statpack['CLUSTERS']['NEWER_COUNT'] = 0
    statpack['CLUSTERS']['COMMON_COUNT'] = 0

    statpack['RECORDS'] = {}
    statpack['RECORDS']['PRIOR_POSITIVE'] = 0
    statpack['RECORDS']['SAME_POSITIVE'] = 0
    statpack['RECORDS']['NEW_POSITIVE'] = 0
    statpack['RECORDS']['NEW_NEGATIVE'] = 0

    statpack['PAIRS'] = {}
    statpack['PAIRS']['NEWER_COUNT'] = 0
    statpack['PAIRS']['PRIOR_COUNT'] = 0
    statpack['PAIRS']['COMMON_COUNT'] = 0

    statpack['SLICE'] = {}
    statpack['SLICE']['COST'] = 0

    statpack['AUDIT'] = {}
    statpack['MISSING_RECORD_COUNT'] = 0

    # --to track the largest matching clusters with new positives
    newPositiveClusters = {}

    # --go through each cluster in the second file
    # print('processing %s ...' % fileMap2['fileName'])
    batchStartTime = time.time()
    entityCnt = 0
    for side2clusterID in fileMap2['clusters']:

        # --progress display
        entityCnt += 1
        if entityCnt % 10000 == 0:
            now = datetime.now().strftime('%I:%M%p').lower()
            elapsedMins = round((time.time() - batchStartTime) / 60, 1)
            eps = int(float(sqlCommitSize) / (float(time.time() - batchStartTime if time.time() - batchStartTime != 0 else 1)))
            batchStartTime = time.time()
            print(' %s entities processed at %s, %s per second' % (entityCnt, now, eps))

        # --store the side2 cluster
        statpack['ENTITY']['PRIOR_COUNT'] += 1
        side2recordIDs = fileMap2['clusters'][side2clusterID]
        side2recordCnt = len(side2recordIDs)
        if debugOn:
            print('-' * 50)
            print('prior cluster [%s] has %s records (%s)' % (side2clusterID, side2recordCnt, ','.join(sorted(side2recordIDs)[:10])))

        # --lookup those records in side1 and see how many clusters they created (ideally one)
        auditRows = []
        missingCnt = 0
        side1recordCnt = 0
        side1clusterIDs = {}
        for recordID in side2recordIDs:
            auditData = {}
            auditData['_side2clusterID_'] = side2clusterID
            auditData['_recordID_'] = recordID
            auditData['_side2score_'] = fileMap2['clusters'][side2clusterID][recordID]
            try:
                side1clusterID = fileMap1['records'][recordID]
            except:
                missingCnt += 1
                auditData['_auditStatus_'] = 'missing'
                auditData['_side1clusterID_'] = 'unknown'
                auditData['_side1score_'] = ''
                if debugOn:
                    print('newer run missing record [%s]' % recordID)
            else:
                side1recordCnt += 1
                auditData['_auditStatus_'] = 'same'  # --default, may get updated later
                auditData['_side1clusterID_'] = fileMap1['records'][recordID]
                auditData['_side1score_'] = fileMap1['clusters'][auditData['_side1clusterID_']][recordID]

                if fileMap1['records'][recordID] in side1clusterIDs:
                    side1clusterIDs[fileMap1['records'][recordID]] += 1
                else:
                    side1clusterIDs[fileMap1['records'][recordID]] = 1
            auditRows.append(auditData)
        side1clusterCnt = len(side1clusterIDs)
        statpack['MISSING_RECORD_COUNT'] += missingCnt

        if debugOn:
            print('newer run has those %s records in %s clusters [%s]' % (side1recordCnt, side1clusterCnt, ','.join(map(str, side1clusterIDs.keys()))))

        # --count as prior positive and see if any new negatives
        newNegativeCnt = 0
        if side2recordCnt > 1:
            statpack['CLUSTERS']['PRIOR_COUNT'] += 1
            statpack['PAIRS']['PRIOR_COUNT'] += ((side2recordCnt * (side2recordCnt - 1)) / 2)
            statpack['RECORDS']['PRIOR_POSITIVE'] += side2recordCnt
            if len(side1clusterIDs) > 1:  # --gonna be some new negatives here

                # --give credit for largest side1cluster
                largestSide1clusterID = None
                for clusterID in side1clusterIDs:
                    if (not largestSide1clusterID) or side1clusterIDs[clusterID] > side1clusterIDs[largestSide1clusterID]:
                        largestSide1clusterID = clusterID
                statpack['PAIRS']['COMMON_COUNT'] += ((side1clusterIDs[largestSide1clusterID] * (side1clusterIDs[largestSide1clusterID] - 1)) / 2)

                # --mark the smaller clusters as new negatives
                for i in range(len(auditRows)):
                    if auditRows[i]['_side1clusterID_'] != largestSide1clusterID:
                        newNegativeCnt += 1
                        auditRows[i]['_auditStatus_'] = 'new negative'
            else:
                statpack['PAIRS']['COMMON_COUNT'] += ((side2recordCnt * (side2recordCnt - 1)) / 2)

        # --now check for new positives
        newPositiveCnt = 0
        for side1clusterID in side1clusterIDs:
            clusterNewPositiveCnt = 0
            for recordID in fileMap1['clusters'][side1clusterID]:
                if recordID not in side2recordIDs:
                    newPositiveCnt += 1
                    clusterNewPositiveCnt += 1
                    side1recordCnt += 1
                    auditData = {}
                    auditData['_recordID_'] = recordID
                    auditData['_side1clusterID_'] = side1clusterID
                    auditData['_side1score_'] = fileMap1['clusters'][auditData['_side1clusterID_']][recordID]

                    # --must lookup the side2 clusterID
                    try:
                        side2clusterID2 = fileMap2['records'][recordID]
                    except:
                        missingCnt += 1
                        auditData['_auditStatus_'] = 'missing'
                        auditData['_side2clusterID_'] = 'unknown'
                        if debugOn:
                            print('side 2 missing record [%s]' % recordID)
                    else:
                        auditData['_auditStatus_'] = 'new positive'
                        auditData['_side2clusterID_'] = side2clusterID2
                        auditData['_side2score_'] = fileMap2['clusters'][auditData['_side2clusterID_']][recordID]
                    auditRows.append(auditData)

            if clusterNewPositiveCnt > 0:
                if debugOn:
                    print('newer cluster %s has %s more records!' % (side1clusterID, clusterNewPositiveCnt))

        # --if exactly same, note and goto top
        if side1clusterCnt == 1 and side1recordCnt == side2recordCnt:
            if debugOn:
                print('RESULT IS SAME!')
            statpack['ENTITY']['COMMON_COUNT'] += 1
            if side1recordCnt > 1:
                statpack['CLUSTERS']['COMMON_COUNT'] += 1
                statpack['RECORDS']['SAME_POSITIVE'] += side1recordCnt
            continue

        # --log it to the proper categories
        auditCategory = ''
        if missingCnt:
            auditCategory += '+MISSING'
        if side1clusterCnt > 1:
            auditCategory += '+SPLIT'
        if side1recordCnt > side2recordCnt:
            auditCategory += '+MERGE'
        if not auditCategory:
            auditCategory = '+UNKNOWN'
        auditCategory = auditCategory[1:] if auditCategory else auditCategory

        # --only count if current side2 cluster is largest merged
        largerClusterID = None
        lowerClusterID = None
        if 'MERGE' in auditCategory:
            side2clusterCounts = {}
            for auditData in auditRows:
                if auditData['_side2clusterID_'] not in side2clusterCounts:
                    side2clusterCounts[auditData['_side2clusterID_']] = 1
                else:
                    side2clusterCounts[auditData['_side2clusterID_']] += 1

            for clusterID in side2clusterCounts:
                if side2clusterCounts[clusterID] > side2clusterCounts[side2clusterID]:
                    largerClusterID = clusterID
                    break
                elif side2clusterCounts[clusterID] == side2clusterCounts[side2clusterID] and clusterID < side2clusterID:
                    lowerClusterID = clusterID

            if debugOn:
                if largerClusterID:
                    print('largerClusterID found! %s' % largerClusterID)
                elif lowerClusterID:
                    print('lowerClusterID if equal size found! %s' % lowerClusterID)

        # --if the largest audit status is not same, wait for the largest to show up
        if largerClusterID or lowerClusterID:
            if debugOn:
                print('AUDIT RESULT BYPASSED!')
                pause()
            continue
        else:
            if debugOn:
                print('AUDIT RESULT WILL BE COUNTED!')

        # --compute the slice algorithm's cost
        if newNegativeCnt > 0:
            statpack['SLICE']['COST'] += splitCost(side1recordCnt, newNegativeCnt)

        if newPositiveCnt > 0:
            statpack['SLICE']['COST'] += splitCost(side1recordCnt, newPositiveCnt)

        # --initialize audit category
        if auditCategory not in statpack['AUDIT']:
            statpack['AUDIT'][auditCategory] = {}
            statpack['AUDIT'][auditCategory]['COUNT'] = 0
            statpack['AUDIT'][auditCategory]['SUB_CATEGORY'] = {}

        # --adjust the side1Score (match key for senzing)
        clarifyScores = True
        if clarifyScores:

            # --get the same entity details
            same_side1clusterID = 0
            same_side1matchKeys = []  # --could be more than one
            for i in range(len(auditRows)):
                if auditRows[i]['_auditStatus_'] == 'same':
                    same_side1clusterID = auditRows[i]['_side1clusterID_']
                    if auditRows[i]['_side1score_'] and auditRows[i]['_side1score_'] not in same_side1matchKeys:
                        same_side1matchKeys.append(auditRows[i]['_side1score_'])

            # --adjust the new positives/negatives
            for i in range(len(auditRows)):
                # --clear the scores on the records that are the same
                if auditRows[i]['_auditStatus_'] == 'same':
                    auditRows[i]['_side2score_'] = ''
                    auditRows[i]['_side1score_'] = ''
                # --see if split rows are related
                elif auditRows[i]['_auditStatus_'] == 'new negative':
                    ent1str = same_side1clusterID
                    ent2str = auditRows[i]['_side1clusterID_']
                    relKey = ent1str + '-' + ent2str if ent1str < ent2str else ent2str + '-' + ent1str
                    if relKey in fileMap1['relationships']:
                        auditRows[i]['_side1score_'] = 'related on: ' + fileMap1['relationships'][relKey]
                    # else:
                    #    auditRows[i]['_side1score_'] = 'no relation'
                elif auditRows[i]['_auditStatus_'] == 'new positive':
                    if not auditRows[i]['_side1score_']:  # --maybe statisize this
                        if len(same_side1matchKeys) == 1:
                            auditRows[i]['_side1score_'] = same_side1matchKeys[0]
                        # else:
                        #    auditRows[i]['_side1score_'] = 'not_logged'

        # --write the record
        scoreCounts = {}
        statpack['AUDIT'][auditCategory]['COUNT'] += 1
        nextAuditID += 1
        sampleRows = []
        score1List = {}  # --will be matchKey for senzing
        for auditData in auditRows:
            csvRow = []
            csvRow.append(nextAuditID)
            csvRow.append(auditCategory)
            csvRow.append(auditData['_auditStatus_'])
            recordIDsplit = auditData['_recordID_'].split('|DS=')
            auditData['_dataSource_'] = recordIDsplit[1]
            auditData['_recordID_'] = recordIDsplit[0]
            csvRow.append(auditData['_dataSource_'])
            csvRow.append(auditData['_recordID_'])
            csvRow.append(auditData['_side2clusterID_'])
            csvRow.append(auditData['_side2score_'] if '_side2score_' in auditData else '')
            csvRow.append(auditData['_side1clusterID_'])
            csvRow.append(auditData['_side1score_'] if '_side1score_' in auditData else '')
            if auditData['_auditStatus_'] == 'new negative':
                statpack['RECORDS']['NEW_NEGATIVE'] += 1
            elif auditData['_auditStatus_'] == 'new positive':
                statpack['RECORDS']['NEW_POSITIVE'] += 1
            elif auditData['_auditStatus_'] == 'same':
                statpack['RECORDS']['SAME_POSITIVE'] += 1
            if auditData['_auditStatus_'] in ('new negative', 'new positive') and auditData['_side1score_']:
                if auditData['_side1score_'] not in scoreCounts:
                    scoreCounts[auditData['_side1score_']] = 1
                else:
                    scoreCounts[auditData['_side1score_']] += 1
            if debugOn:
                print(auditData)
            sampleRows.append(dict(zip(csvHeaders, csvRow)))

            try:
                csvHandle.write(','.join(map(str, csvRow)) + '\n')
            except IOError as err:
                print(err)
                print('could not write to output file %s' % outputCsvFile)
                return
            # print(','.join(map(str, csvRow)))

        # --assign the best score (most used)
        if True:
            if len(scoreCounts) == 0:
                bestScore = 'none'
            elif len(scoreCounts) == 1:
                bestScore = list(scoreCounts.keys())[0]
            else:
                bestScore = 'multiple'
        # --assign the best score (most used)
        else:
            bestScore = 'none'
            bestCount = 0
            for score in scoreCounts:
                if scoreCounts[score] > bestCount:
                    bestScore = score
                    bestCount = scoreCounts[score]

        # --initialize sub category
        if bestScore not in statpack['AUDIT'][auditCategory]['SUB_CATEGORY']:
            statpack['AUDIT'][auditCategory]['SUB_CATEGORY'][bestScore] = {}
            statpack['AUDIT'][auditCategory]['SUB_CATEGORY'][bestScore]['COUNT'] = 0
            statpack['AUDIT'][auditCategory]['SUB_CATEGORY'][bestScore]['SAMPLE'] = []
        statpack['AUDIT'][auditCategory]['SUB_CATEGORY'][bestScore]['COUNT'] += 1

        # --place in the sample list
        if len(statpack['AUDIT'][auditCategory]['SUB_CATEGORY'][bestScore]['SAMPLE']) < 100:
            statpack['AUDIT'][auditCategory]['SUB_CATEGORY'][bestScore]['SAMPLE'].append(sampleRows)
        else:
            randomSampleI = random.randint(1, 99)
            if randomSampleI % 10 != 0:
                statpack['AUDIT'][auditCategory]['SUB_CATEGORY'][bestScore]['SAMPLE'][randomSampleI] = sampleRows

        if debugOn:
            pause()

    csvHandle.close()

    # --completion display
    now = datetime.now().strftime('%I:%M%p').lower()
    elapsedMins = round((time.time() - procStartTime) / 60, 1)
    eps = int(float(sqlCommitSize) / (float(time.time() - batchStartTime if time.time() - batchStartTime != 0 else 1)))
    batchStartTime = time.time()
    print(' %s entities processed at %s, %s per second, complete!' % (entityCnt, now, eps))

    # --compute the side 1 (result set) cluster and pair count
    print('computing statistics ...')

    # --get all cluster counts for both sides

    # --get cluster and pair counts for side1
    for side1clusterID in fileMap1['clusters']:
        statpack['ENTITY']['NEWER_COUNT'] += 1
        side1recordCnt = len(fileMap1['clusters'][side1clusterID])
        if side1recordCnt == 1:
            continue
        statpack['CLUSTERS']['NEWER_COUNT'] += 1
        statpack['PAIRS']['NEWER_COUNT'] += ((side1recordCnt * (side1recordCnt - 1)) / 2)

    # --entity precision and recall
    statpack['ENTITY']['PRECISION'] = 0
    statpack['ENTITY']['RECALL'] = 0
    statpack['ENTITY']['F1-SCORE'] = 0
    if statpack['ENTITY']['NEWER_COUNT'] and statpack['ENTITY']['PRIOR_COUNT']:
        statpack['ENTITY']['PRECISION'] = round((statpack['ENTITY']['COMMON_COUNT'] + .0) / (statpack['ENTITY']['NEWER_COUNT'] + .0), 5)
        statpack['ENTITY']['RECALL'] = round(statpack['ENTITY']['COMMON_COUNT'] / (statpack['ENTITY']['PRIOR_COUNT'] + .0), 5)
        if (statpack['ENTITY']['PRECISION'] + statpack['ENTITY']['RECALL']) != 0:
            statpack['ENTITY']['F1-SCORE'] = round(2 * ((statpack['ENTITY']['PRECISION'] * statpack['ENTITY']['RECALL']) / (statpack['ENTITY']['PRECISION'] + statpack['ENTITY']['RECALL'] + .0)), 5)

    # --cluster precision and recall
    statpack['CLUSTERS']['PRECISION'] = 0
    statpack['CLUSTERS']['RECALL'] = 0
    statpack['CLUSTERS']['F1-SCORE'] = 0
    if statpack['CLUSTERS']['NEWER_COUNT'] and statpack['CLUSTERS']['PRIOR_COUNT']:
        statpack['CLUSTERS']['PRECISION'] = round((statpack['CLUSTERS']['COMMON_COUNT'] + .0) / (statpack['CLUSTERS']['NEWER_COUNT'] + .0), 5)
        statpack['CLUSTERS']['RECALL'] = round(statpack['CLUSTERS']['COMMON_COUNT'] / (statpack['CLUSTERS']['PRIOR_COUNT'] + .0), 5)
        if (statpack['CLUSTERS']['PRECISION'] + statpack['CLUSTERS']['RECALL']) != 0:
            statpack['CLUSTERS']['F1-SCORE'] = round(2 * ((statpack['CLUSTERS']['PRECISION'] * statpack['CLUSTERS']['RECALL']) / (statpack['CLUSTERS']['PRECISION'] + statpack['CLUSTERS']['RECALL'] + .0)), 5)

    # --pairs precision and recall
    statpack['PAIRS']['SAME_POSITIVE'] = statpack['PAIRS']['COMMON_COUNT']
    statpack['PAIRS']['NEW_POSITIVE'] = statpack['PAIRS']['NEWER_COUNT'] - statpack['PAIRS']['COMMON_COUNT'] if statpack['PAIRS']['NEWER_COUNT'] > statpack['PAIRS']['COMMON_COUNT'] else 0
    statpack['PAIRS']['NEW_NEGATIVE'] = statpack['PAIRS']['PRIOR_COUNT'] - statpack['PAIRS']['COMMON_COUNT'] if statpack['PAIRS']['PRIOR_COUNT'] > statpack['PAIRS']['COMMON_COUNT'] else 0

    statpack['PAIRS']['PRECISION'] = 0
    statpack['PAIRS']['RECALL'] = 0
    statpack['PAIRS']['F1-SCORE'] = 0
    if statpack['PAIRS']['NEWER_COUNT'] and statpack['PAIRS']['PRIOR_COUNT']:
        statpack['PAIRS']['PRECISION'] = round(statpack['PAIRS']['SAME_POSITIVE'] / (statpack['PAIRS']['SAME_POSITIVE'] + statpack['PAIRS']['NEW_POSITIVE'] + .0), 5)
        statpack['PAIRS']['RECALL'] = round(statpack['PAIRS']['SAME_POSITIVE'] / (statpack['PAIRS']['SAME_POSITIVE'] + statpack['PAIRS']['NEW_NEGATIVE'] + .0), 5)
        if (statpack['PAIRS']['PRECISION'] + statpack['PAIRS']['RECALL']) != 0:
            statpack['PAIRS']['F1-SCORE'] = round(2 * ((statpack['PAIRS']['PRECISION'] * statpack['PAIRS']['RECALL']) / (statpack['PAIRS']['PRECISION'] + statpack['PAIRS']['RECALL'] + .0)), 5)

    # --accuracy precision and recall
    statpack['RECORDS']['PRECISION'] = 0
    statpack['RECORDS']['RECALL'] = 0
    statpack['RECORDS']['F1-SCORE'] = 0
    if statpack['RECORDS']['PRIOR_POSITIVE']:
        statpack['RECORDS']['PRECISION'] = round(statpack['RECORDS']['SAME_POSITIVE'] / (statpack['RECORDS']['SAME_POSITIVE'] + statpack['RECORDS']['NEW_POSITIVE'] + .0), 5)
        statpack['RECORDS']['RECALL'] = round(statpack['RECORDS']['SAME_POSITIVE'] / (statpack['RECORDS']['SAME_POSITIVE'] + statpack['RECORDS']['NEW_NEGATIVE'] + .0), 5)
        if (statpack['RECORDS']['PRECISION'] + statpack['RECORDS']['RECALL']) != 0:
            statpack['RECORDS']['F1-SCORE'] = round(2 * ((statpack['RECORDS']['PRECISION'] * statpack['RECORDS']['RECALL']) / (statpack['RECORDS']['PRECISION'] + statpack['RECORDS']['RECALL'] + .0)), 5)

    # --dump the stats to screen and file
    with open(outputJsonFile, 'w') as outfile:
        json.dump(statpack, outfile)

    # print ('')
    # print ('%s prior positives ' % statpack['RECORDS']['PRIOR_POSITIVE'])
    # print ('%s same positives ' % statpack['RECORDS']['SAME_POSITIVE'])

    # print ('%s new positives ' % statpack['RECORDS']['NEW_POSITIVE'])
    # print ('%s new negatives ' % statpack['RECORDS']['NEW_NEGATIVE'])
    # print ('%s precision ' % statpack['RECORDS']['PRECISION'])
    # print ('%s recall ' % statpack['RECORDS']['RECALL'])
    # print ('%s f1-score ' % statpack['RECORDS']['F1-SCORE'])
    print ('')
    print ('%s prior pairs ' % statpack['PAIRS']['PRIOR_COUNT'])
    print ('%s newer pairs ' % statpack['PAIRS']['NEWER_COUNT'])
    print ('%s common pairs ' % statpack['PAIRS']['COMMON_COUNT'])
    print ('')
    print ('%s same positives ' % statpack['PAIRS']['SAME_POSITIVE'])
    print ('%s new positives ' % statpack['PAIRS']['NEW_POSITIVE'])
    print ('%s new negatives ' % statpack['PAIRS']['NEW_NEGATIVE'])
    print ('%s precision ' % statpack['PAIRS']['PRECISION'])
    print ('%s recall ' % statpack['PAIRS']['RECALL'])
    print ('%s f1-score ' % statpack['PAIRS']['F1-SCORE'])
    print ('')

    print ('%s prior entities ' % statpack['ENTITY']['PRIOR_COUNT'])
    print ('%s new entities ' % statpack['ENTITY']['NEWER_COUNT'])
    print ('%s common entities ' % statpack['ENTITY']['COMMON_COUNT'])
    print ('%s merged entities ' % (statpack['AUDIT']['MERGE']['COUNT'] if 'MERGE' in statpack['AUDIT'] else 0))
    print ('%s split entities ' % (statpack['AUDIT']['SPLIT']['COUNT'] if 'SPLIT' in statpack['AUDIT'] else 0))
    print ('%s split+merge entities ' % (statpack['AUDIT']['SPLIT+MERGE']['COUNT'] if 'SPLIT+MERGE' in statpack['AUDIT'] else 0))
    print ('')
    # print ('%s slice edit distance ' % statpack['SLICE']['COST'])
    # print('')
    if statpack['MISSING_RECORD_COUNT']:
        print ('%s ** missing clusters **' % statpack['MISSING_RECORD_COUNT'])
        print('')
    if shutDown:
        print('** process was aborted **')
    else:
        print('process completed successfully!')
    print('')
    return

# ===== The main function =====
if __name__ == '__main__':
    global shutDown
    shutDown = False
    signal.signal(signal.SIGINT, signal_handler)
    procStartTime = time.time()

    sqlCommitSize = 10000  # -this is really just for stat display

    # --capture the command line arguments
    argParser = argparse.ArgumentParser()
    argParser.add_argument('-n', '--newer_csv_file', dest='newerFile', default=None, help='the latest entity map file')
    argParser.add_argument('-p', '--prior_csv_file', dest='priorFile', default=None, help='the prior entity map file')
    argParser.add_argument('-o', '--output_file_root', dest='outputRoot', default=None, help='the ouputfile root name (both a .csv and a .json file will be created')
    argParser.add_argument('-D', '--debug', dest='debug', action='store_true', default=False, help='print debug statements')
    args = argParser.parse_args()
    newerFile = args.newerFile
    priorFile = args.priorFile
    outputRoot = args.outputRoot
    debugOn = args.debug

    # --validations
    if not newerFile:
        print('ERROR: A newer entity map file must be specified with -n')
        sys.exit(1)
    if not priorFile:
        print('ERROR: A prior entity map file must be specified with -p')
        sys.exit(1)
    if not outputRoot:
        print('ERROR: An output root must be specified with -o')
        sys.exit(1)
    if os.path.splitext(outputRoot)[1]:
        print("Please don't use a file extension as both a .json and a .csv file will be created")
        sys.exit(1)

    erCompare(newerFile, priorFile, outputRoot)

    sys.exit(0)


from functools import reduce #for extreme lazyness, praise lambda
from tkinter import *
class student:

    def __init__(self,n,d):
        self.courses = {}
        self.name = ""
        self.idno = ""
        self.floating = 0
        self.name = n
        self.idno = d

    def getName(self):
        return self.name
    def getCode(self):
        return self.idno
    def setName(self,x):
        self.name = x

    def setId(self,x):
        self.idno = x

    def addClass(self,x,y):
        if(x.getUnits() == 'floating'):
            self.floating = self.floating+1
        self.courses[x.getCode()] = [x, y]
    def checkIfStudentIsHere(self,x):
        for i in self.courses:
            if (i == x):
                return True
        return False
    def getClass(self, x):
        for i in self.courses:
            if (str(x) == str(self.courses[i][0].getCode())):
                return self.courses[x][0]
        return None
    def removeClass(self, x):
        hehe = self.courses
        self.courses.pop(x,None)
        #del self.courses[x]

    def getClasses(self):
        return self.courses
    def checkEnroll(self,x):
        try:
            self.courses[x]
            return True
        except:
            return False
    def editGrade(self, x, y):
        self.courses[x][1] = y
        return True

    def getGrade(self, x):
        return self.courses[x][1]
    def cantLambdaThisSad(self,x):
        if(x[0].getUnits() != 'floating'):
            return (float)(x[0].getUnits())
        else:
            return 0
    def displayGrade(self):
        print('REPORT CARD LOL:')
        GPA = 0
        floaters = 0
        try:
            totalUnits = reduce(lambda x,y: (float)(x)+(float)(y), list(map(self.cantLambdaThisSad, list(self.courses.values()))))
            screen = Tk()
            screen.title(self.idno)
            lab0 = Label(screen, text = 'ID number: '+str(self.idno), borderwidth=2, relief="solid")
            lab0.grid(row = 0)
            lab1 = Label(screen, text = 'Student name: '+str(self.name), borderwidth=2, relief="solid")
            lab1.grid(row = 1)
            labx = Label(screen, text = 'Course', borderwidth=2, relief="solid")
            labx.grid(row = 2, column = 0)
            labx = Label(screen, text = 'Grade', borderwidth=2, relief="solid")
            labx.grid(row = 2, column = 1)
            labx = Label(screen, text = 'Unit', borderwidth=2, relief="solid")
            labx.grid(row = 2, column = 2)
            cnt = 3
            for i in self.courses:

                corth = self.courses[i][0]
                lab = Label(screen, text = str(corth.getCode()))
                lab2 = Label(screen, text = str(corth.getUnits()))
                CCCCComboBREAKER = Label(screen, text = str(self.courses[i][1]))
                lab.grid(row = cnt, column = 0)
                CCCCComboBREAKER.grid(row = cnt, column = 1)
                lab2.grid(row = cnt, column = 2)

                print(str(corth.getCode())+'\t\t\t'+str(corth.getUnits())+'\t\t\t'+str(self.courses[i][1]))
                if(corth.getUnits() != 'floating'):
                    GPA = float(GPA) + float(self.courses[i][1]) * (float(corth.getUnits())/float(totalUnits))

                cnt = cnt+1
            lab3 = Label(screen, text = 'Total units: '+str(totalUnits), borderwidth=2, relief="solid")
            lab3.grid(row =cnt)
            lab4 = Label(screen, text = 'GPA: '+str(GPA), borderwidth=2, relief="solid")
            lab4.grid(row =cnt+1)
            print('Total units: '+str(totalUnits))
            print('Ll your GPA is: '+str(GPA))
        except Exception as inst:
            print('Not yet enrolled')


import os
from qgis.core import Qgis, QgsFeatureRequest, QgsRectangle, QgsProject, \
    QgsFeature
from .ewid import Ewidencja
from .baza import Baza
from .ewid_okno import EwidUI

class EwidWskazana(Ewidencja):
    def __init__(self, iface):
        self.iface = iface
        self.tryb = ''  # 'pryw'-'DZKAT'; 'sulmn'-'DZ_EWID'

    def sprawdz_podstawe(self):
        """Metoda sprawdza czy w warstwie zaznaczonej w TOC znajduje się
        odpowiednia kolumna PARCELID, a następnie czy polaczenie
        z baza jest poprawne

        PARCELID w postaci:
        '24050220012.142/7' lub '240502_20012.142/7' albo
        '24050220012.AR_1.142/7'
        """

        # czy jest poprawna baza?
        if not self.podczytaj_baze():
            return False

        try:
            # tryb warstwy prywatnej
            lyrp = [x for x in QgsProject.instance().mapLayers().values()
                    if x.name() == 'DZKAT']
            if len(lyrp) == 1:
                self.dz = lyrp[0]
                pola = [x.name() for x in
                        self.dz.dataProvider().fields().toList()
                        if x.name() == 'PARCELID']
                if len(pola) == 1:
                    self.tryb = 'pryw'
                    self.padr = 'PARCELID'
                else:
                    self.iface.messageBar().pushMessage(
                        'BŁĄD',
                        'Brak odpowiedniego pola w zaznaczonej '
                        'warstwie \'PARCELID\' (24050220012.142/7)',
                        Qgis.Critical,
                        20
                    )
                    return False
            elif len(lyrp) > 1:
                self.iface.messageBar().pushMessage(
                    'BŁĄD',
                    'W projekcie powinna znajdować się tylko 1 warstwa DZKAT!',
                    Qgis.Critical,
                    20
                )
                return False
        except Exception:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'Coś poszło nie tak w podczytywaniu warstwy DZKAT',
                Qgis.Critical,
                20
            )
            return False

        # tryb warstwy sulmn  (DZ_EWID)
        try:
            lyrs = [x for x in QgsProject.instance().mapLayers().values()
                    if x.name() == 'DZ_EWID']
            if len(lyrs) == 1:
                self.dz = lyrs[0]
                pola = [x.name() for x in
                        self.dz.dataProvider().fields().toList()
                        if x.name() in ['ADR_ADM', 'NR_EW']]
                if len(pola) == 2:
                    self.tryb = 'sulmn'
                else:
                    self.iface.messageBar().pushMessage(
                        'BŁĄD',
                        'Brak odpowiednich pól w zaznaczonej '
                        'warstwie (ADR_ADM, NR_EW)',
                        Qgis.Critical,
                        20
                    )
                    return False
            else:
                self.iface.messageBar().pushMessage(
                    'BŁĄD',
                    'W projekcie powinna znajdować się tylko '
                    '1 warstwa DZ_EWID!',
                    Qgis.Critical,
                    20
                )
                return False
        except Exception:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'Coś poszło nie tak w podczytywaniu warstwy DZ_EWID',
                Qgis.Critical,
                20
            )
            return False

        if len(lyrs) + len(lyrp) == 0:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'Brak warstw z działkami [DZKAT, DZ_EWID]',
                Qgis.Critical,
                20
            )
            return False

        return True

    def sprawdz_reszte(self, k):
        koord = list(k)
        rec = QgsRectangle(koord[0]-0.1, koord[1]-0.1,
                           koord[0]+0.1, koord[1]+0.1)
        req = QgsFeatureRequest().setFilterRect(rec)

        fd = False
        try:
            fd = next(self.dz.getFeatures(req))
        except StopIteration:
            pass

        if not isinstance(fd, QgsFeature):
            self.iface.messageBar().pushWarning(
                'BŁĄD', 'Proszę wskazać poligon działki'
            )
            return False

        fadr = False
        if self.tryb == 'pryw':
            ftemp = str(fd[self.padr])  # str bo inaczej moze byc QVariant
            if len(ftemp) == 0:
                self.iface.messageBar().pushWarning(
                    'BŁĄD', 'Kolumna PARCELID musi być wypełniona!'
                )
                return False

            if '_' in ftemp:
                ftemp = ftemp.replace('_', '')
            fadr = ftemp

        if self.tryb == 'sulmn':
            adr = str(fd['ADR_ADM']).replace('-', '')
            dz = str(fd['NR_EW'])

            if len(adr) == 0 and len(dz) == 0:
                self.iface.messageBar().pushWarning(
                    'BŁĄD', 'Kolumny ADR_ADM i NR_EW muszą być wypełnione!'
                )
                return False

            fadr = f'{adr}.{dz}'
        self.sprawdz(fadr)

    def sprawdz(self, f):
        self.fwoj = ''
        self.fpow = ''
        self.fgmi = ''
        self.fobr = ''
        self.fark = ''
        self.fnr = ''
        self.fpid = ''
        if len(f) < 11:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'Proszę sprawdzić czy adres działki w warstwie jest poprawny'
                ', proszę sprawdzić kolumnę: '+self.padr,
                Qgis.Critical, 10)
            return False

        self.baza_l = Baza(self.baza)
        self.baza_l.polacz()
        self.okno = EwidUI()
        self.okno.dodaj_baze(self.baza)
        self.okno.przygotuj_strukture()
        self.okno.przygotuj_adresy()

        if f[:2] not in self.okno.sl_adr:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'We wskazanej bazie nie występuje takie województwo, '
                'sprawdź czy czy wskazałeś poprawną bazę', Qgis.Critical, 10)
            self.baza_l.zamknij()
            return False
        self.fwoj = f[:2]

        if f[2:4] not in self.okno.sl_adr[f[:2]]:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'We wskazanej bazie nie występuje taki powiat, '
                'sprawdź czy czy wskazałeś poprawną bazę', Qgis.Critical, 10)
            self.baza_l.zamknij()
            return False
        self.fpow = f[2:4]

        if f[4:7] not in self.okno.sl_adr[f[:2]][f[2:4]]:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'We wskazanej bazie nie występuje taka gmina,  '
                'sprawdź czy czy wskazałeś poprawną bazę', Qgis.Critical, 10)
            self.baza_l.zamknij()
            return False
        self.fgmi = f[4:7]

        if f[7:11] not in self.okno.sl_adr[f[:2]][f[2:4]][f[4:7]]:
            self.iface.messageBar().pushMessage(
                'BŁĄD',
                'We wskazanej bazie nie występuje taki obręb ewid.,  '
                'sprawdź czy czy wskazałeś poprawną bazę', Qgis.Critical, 10)
            self.baza_l.zamknij()
            return False
        self.fobr = f[7:11]

        # przypadek gdy w obrebach nie ma arkuszy
        if len(f.split('.')) == 2:
            self.fnr = f.split('.')[1]
        elif len(f.split('.')) == 3:
            self.fnr = f.split('.')[2]
            self.fark = f.split('.')[1]

        self.fpid = self.baza_l.pobierz_pid(self.fwoj,
                                            self.fpow,
                                            self.fgmi,
                                            self.fobr,
                                            self.fnr,
                                            self.fark
                                            )[0][0]

        if self.fpid is False:
            return False

        self.baza_l.zamknij()
        self.pokaz_okno_wybrane()

    def pokaz_okno_wybrane(self):
        self.okno.pokaz_dz_wybrana(self.fwoj,
                                   self.fpow,
                                   self.fgmi,
                                   self.fobr,
                                   self.fpid,
                                   )
        self.okno.exec_()


from keras import Sequential
from keras.optimizers import Adam

class DCGAN:
    def __init__(self, discriminator, generator):
        self.actual_dcgan = self.build_dcgan(discriminator, generator)

    def build_dcgan(self, discriminator, generator):
        model = Sequential()

        discriminator.trainable = False
        model.add(generator.actual_generator)
        model.add(discriminator.actual_discriminator)

        model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5),
                      metrics=['accuracy'])
        return model


from __future__ import print_function
import os
import logging
import tempfile

from abc import ABC, abstractmethod
from dabble import DabbleError
from pkg_resources import resource_filename
from vmd import atomsel

logger = logging.getLogger(__name__) # pylint: disable=invalid-name

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#                                   CLASSES                                   #
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
class MoleculeWriter(ABC):
    """
    Represents a writer that will parameterize built systems into input files
    for some simulation program.

    Attributes:
        molid (int): VMD molecule ID to write
        output_prefix (str): Prefix for output file names. Appropriate suffix
            will be added depending on the file type.
    """
    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    #                                CONSTANTS                                    #
    #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    # Will be populated by appropriate writer
    WATER_NAMES = {}
    WATER_O_NAME = None
    WATER_H_NAMES = None

    #==========================================================================

    def __init__(self, molid, **kwargs):
        """
        Creates a molecule writer

        Args:
            molid (int): VMD molecule ID of system to write
            tmp_dir (str): Directory for temporary files. Defaults to "."
            lipid_sel (str): Lipid selection string. Defaults to "lipid"
            forcefield (str): Force field to use
            water_model (str): Water model to use
            hmr (bool): If hydrogen masses should be repartitioned. Defaults
                to False.

            extra_topos (list of str): Additional topology (.str, .off, .lib) to
                include.
            extra_params (list of str): Additional parameter sets (.str, .frcmod)
            override_defaults (bool): If set, omits default forcefield parameters
            debug_verbose (bool): Prints additional output, like from tleap.
        """
        self.molid = molid
        self.outprefix = ""
        self.matcher = None

        # Set default options
        self.tmp_dir = kwargs.get("tmp_dir", os.getcwd())
        self.lipid_sel = kwargs.get("lipid_sel", "lipid")
        self.debug = kwargs.get("debug_verbose", False)
        self.override = kwargs.get("override_defaults", False)
        self.hmr = kwargs.get("hmr", False)

        self.forcefield = kwargs.get("forcefield")
        self.water_model = kwargs.get("water_model", "tip3")

        self.extra_topos = kwargs.get("extra_topos")
        self.extra_params = kwargs.get("extra_params")
        # Handle None from argparse in command line invocation
        if self.extra_topos is None:
            self.extra_topos = []
        if self.extra_params is None:
            self.extra_params = []

        # Handle None from argparse in command line invocation
        if self.extra_topos is None:
            self.extra_topos = []
        if self.extra_params is None:
            self.extra_params = []

    #==========================================================================

    def _rename_by_resname(self, resname, renumber=False):
        """
        Tries to match up all of one resname in one go, by getting an
        isomorphism to one residue in the selection and applying the resulting
        name matching to all other residues. Lots of error checking, will
        refuse to rename residues that don't have the same original atom
        names. Only one isomorphism will be  performed, non-matching residues
        with this resname will be left alone.

        Args:
            resname (str): Residue name to rename
            renumber (bool): Whether to renumber the resids of renamed residues

        Returns:
            (list of int): Residues that were successfully matched
        """
        residues = set(atomsel("resname '%s'" % resname,
                               molid=self.molid).residue)
        matched = []

        # Gather info about first residue. We'll check the others against this.
        firstres = residues.pop()
        sel = atomsel('residue %s' % firstres)
        resid = 1

        # Find a name match for the first residue
        newresname, atomnames = self.matcher.get_names(sel, print_warning=True)
        if not newresname:
            raise DabbleError("No residue definition for residue %s:%s, "
                              "residue %d"
                              % (sel.name[0], sel.resid[0], sel.residue[0]))

        refnames = sel.name # Correct names, before renaming

        # Do the renaming for this residue
        self._apply_naming_dictionary(atomnames=atomnames,
                                      resnames=newresname,
                                      verbose=False)
        newnames = sel.name # New names, after renaming
        newresname = sel.resname[0]
        matched.append(firstres)

        if renumber:
            sel.resid = resid
            resid += 1

        # Now loop through all other residues in the selection
        for res in residues:
            sel = atomsel("residue %s" % res)

            # Check original atom names are the same
            if sel.name != refnames:
                logger.warning("Resid %s doesn't appear to be a standard "
                               "'%s' residue. Will attempt to match another "
                               "topology definition." % (sel.resid[0], resname))
                continue

            # Match up atom names. Since we know atoms are in the same
            # order as the reference residue, we can safely assign refatoms
            # to our names without more atom selections
            sel.name = newnames
            sel.resname = newresname
            matched.append(res)

            if renumber:
                sel.resid = resid
                resid += 1

        return matched

    #==========================================================================

    def _set_water_names(self):
        """
        Sets the names of water residues and atoms according to the given
        water model. We do it this way instead of with the GraphMatcher because
        waters can have a fake bond
        """
        # Sanity check
        if self.water_model not in self.WATER_NAMES:
            raise DabbleError("Unsupported water model '%s' with forcefield "
                              "'%s'" % (self.water_model, self.forcefield))

        watres = self.WATER_NAMES[self.water_model]
        if watres not in self.matcher.known_res:
            raise DabbleError("Water resname '%s' for model '%s' not defined "
                              "in topology files" % (watres, self.water_model))

        # Set consistent residue and atom names, crystal waters
        # can be named HOH, etc
        residues = set(atomsel("water").residue)

        # If no water, nothing to do
        if not residues:
            return

        watsel = "residue %s" % ' '.join(str(_) for _ in residues)

        atomsel(watsel).resname = self.WATER_NAMES[self.water_model]
        atomsel("%s and noh" % watsel).name = self.WATER_O_NAME
        atomsel("%s and not noh" % watsel).name = self.WATER_H_NAMES * len(residues)

    #==========================================================================

    def _write_water_pdbs(self):
        """
        Renames waters and writes them, 10,000 at a time, to PDB files.
        This handles character limit in PDB files, and multiple water
        models

        Returns:
            (list of str): PDB files saved
        """

        allw = atomsel('water and user 1.0')
        pdbs = []
        print("Found %d water residues" % len(set(allw.residue)))

        # Find the problem waters with unordered indices
        problems = []
        for r in set(allw.residue):
            widx = atomsel('residue %s' % r).index
            if max(widx) - min(widx) != 2:
                problems.append(r)
                atomsel('residue %s' % r).user = 0.0 # get it out of allw

        allw.update()
        num_written = int(len(allw)/(9999*3))+1
        print("Going to write %d files for %d water atoms"
              % (num_written, len(allw)))

        # Pull out and write 10k waters at a time if we have normal waters
        if allw:
            for i in range(num_written):
                _, temp = tempfile.mkstemp(suffix='_%d.pdb' % i,
                                           prefix='psf_wat_',
                                           dir=self.tmp_dir)
                os.close(_)
                residues = list(set(allw.residue))[:9999]

                batch = atomsel("residue %s"% ' '.join(str(x) for x in residues))
                try:
                    batch.resid = [k for k in range(1, int(len(batch)/3)+1)
                                   for _ in range(3)]
                except ValueError:
                    raise DabbleError("\nERROR! You have some waters missing "
                                      "hydrogens!\nFound %d water residues, but"
                                      " %d water atoms. Check your crystal "
                                      "waters in the input structure."
                                      % (len(residues), len(batch)))
                batch.user = 0.0
                batch.write('pdb', temp)
                pdbs.append(temp)
                allw.update()

        # Now write the problem waters
        if problems:
            updb = self._write_unorderedindex_waters(problems, self.molid)
            pdbs.append(updb)

        return pdbs

    #==========================================================================

    def _write_unorderedindex_waters(self, residues, molid):
        """
        Renumbers and sorts the specified waters manually. This is much less
        efficient but is necessary in cases where atoms within a water molecule
        are not sequential in index, preventing quick renaming with VMD.
        Identify problem waters, then call this on them. It'll write its own
        psf_wat_* file with just those waters, minimizing inefficiency.

        Args:
            residues (list of int): Problem water molecules
            molid (int): VMD molecule ID to write
        Returns:
            (str): Filename where waters are written
        """
        f, temp = tempfile.mkstemp(suffix='_indexed.pdb', prefix='psf_wat_',
                                   dir=self.tmp_dir)
        idx = 1
        with os.fdopen(f, 'w') as fileh:
            for ridx, residue in enumerate(residues):
                res = atomsel('residue %d' % residue, molid=molid)

                for i in res.index:
                    a = atomsel('index %d' % i, molid)
                    fileh.write(self.get_pdb_line(a, idx, ridx+1))
                    idx += 1

            fileh.write('END\n')
        return temp

    #==========================================================================

    @abstractmethod
    def write(self, filename):
        pass

    @abstractmethod
    def get_topologies(self, forcefield, water_model):
        pass

    @abstractmethod
    def get_parameters(self, forcefield, water_model):
        pass

    #==========================================================================
    #                              Static methods
    #==========================================================================

    @staticmethod
    def _apply_naming_dictionary(resnames, atomnames, verbose=False):
        """
        Applies the atom names from a matcher.

        Args:
            resnames (dict int->str or str): Atom index to residue name,
                or just residue name for all atoms
            atomnames (dict int->str): Atom index to atom name
            verbose (bool): If renamings should be printed out

        Raises:
            ValueError: If indices in atomnames and resnames dictionary
                differ
        """
        if isinstance(resnames, dict) and \
           set(resnames.keys()) != set(atomnames.keys()):
            raise ValueError("Invalid matching dictionary for resnames '%s'"
                             % resnames.keys())

        for idx, name in atomnames.items():
            atom = atomsel("index %s" % idx)
            # TODO: Name short circuiting here??
            if verbose and atom.name[0] != name:
                print("Renaming %s:%s: %s -> %s" % (atom.resname[0],
                                                    atom.resid[0], atom.name[0],
                                                    name))
            atom.name = name

            if isinstance(resnames, dict):
                atom.resname = resnames[idx]
            else:
                atom.resname = resnames

    #==========================================================================

    @staticmethod
    def get_pdb_line(atom, index, resindex, hetatom=False):
        """
        Get the PDB-formatted line corresponding to this atom, with a newline
        at the end.

        Args:
            atom (VMD atomsel): Atom selected
            index (int): Index in PDB file.
            resindex (int): Residue number in PDB file
            hetatom (bool): If this is part of a non-standard residue

        Returns:
            (str) PDB file line for this atom
        """
        if len(atom) != 1:
            raise ValueError("PDB entry selection must be only one atom")

        ins = atom.insertion[0]
        result = "%-6s%5d %-5s%-4s%c%4d%c  %8.3f%8.3f%8.3f%6.2f%6.2f" \
                 "     %-4s%2s\n" % ("HETATM" if hetatom else "ATOM",
                                     index,
                                     atom.name[0],
                                     atom.resname[0],
                                     atom.chain[0],
                                     resindex,
                                     ins if ins else " ",
                                     atom.x[0],
                                     atom.y[0],
                                     atom.z[0],
                                     0.0, 0.0,
                                     atom.segname[0],
                                     atom.element[0])
        return result

    #==========================================================================

    @staticmethod
    def _get_forcefield_path(filename):
        """
        Gets the absolute path to a given bundled forcefield file
        """
        rn = resource_filename(__name__, os.path.join("parameters", filename))
        return os.path.abspath(rn)

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


# coding: utf-8
import socket

from django.shortcuts import render_to_response,HttpResponseRedirect, render
from django.http import  HttpResponse
#from jipiao.mq.models import AirAirplaneOrder
# import MySQLdb
import pymysql
import requests
import random
import string
import time
import re
import json

s = requests.Session()
def queryDB(orderCode):
    conn = pymysql.connect(
        host='***.***.***.***', #主机名
        port=3306,        #端口号(默认的)
        user='i******',  #用户名
        passwd='*********',   #密码
        db='***',  #数据库名
        charset='utf8', #这里设置编码是为了输出中文
    )
    cursor = conn.cursor()
    sql = 'select order_code,user_id,order_money,cost_money from air_airplane_order where order_code=%s' % orderCode
    cursor.execute(sql)
    resultdb  = cursor.fetchmany(1)
    print("resultdb:")
    print(resultdb[0][2])
    cursor.close()
    conn.close()
    return resultdb[0]

def search(request):
    if request.session['is_login']:
        error = []
        if 'q' in request.GET:
            q = request.GET['q']
            if not q:
                error.append("Please enter a order_code.")
            elif len(q) > 11 or len(q) < 11:
                error.append("Please enter right order_code")
            else:
                orders = queryDB(q)
                sendMQ(orders)
                print("orders:")
                print(orders)
                return render_to_response('search_results.html', {'orders': orders, 'query': q})
        return render_to_response('search_form.html', {'error': error})
    else:
        return HttpResponse('http://' + get_host_ip() + ':8088/index')

def refund(request):

    if request.session['is_login']:
        error = []
        if 'order_code' in request.GET:
            order_code = request.GET['order_code']
            if not order_code:
                error.append("Please enter a order_code.")
            elif len(order_code) > 11 or len(order_code) < 11:
                error.append("Please enter right order_code")
            else:
                #print(queryUUID(order_code))
                # return render_to_response('refund_list.html',{'refundMessages':json.dumps(queryUUID(order_code))})
                return render_to_response('refund_list.html', {'refundMessages': queryUUID(order_code)})
        if 'refundIds' in request.GET:
            if not request.GET['refundIds']:
                error.append("Please enter refundId.")
            else:
                refundIds = request.GET['refundIds'].split(",")
                orderId = request.GET['orderId']
                for refundId in refundIds:
                    rfundEntry = {}
                    for refundMessage in queryUUID(orderId):
                        if refundMessage.get('refundId') == refundId:
                            rfundEntry = refundMessage
                    sendMQ_refund(orderId, rfundEntry.get('refundPrice'), rfundEntry.get('uuid'),
                                  rfundEntry.get('refundId'))
                return render_to_response('refund_results.html', {'orders': orderId, 'refundIds': refundIds})
                print(request.GET['orderId'])
                print(refundIds + '***************')
        return render_to_response('refund_form.html', {'error': error})
    else:
        return HttpResponse('http://'+get_host_ip()+':8088/index')

def login():
    url = 'http://***.***.***.***/jmq-web/j_spring_security_check'
    header = {
        'Host': '***.***.***.***',
        'Connection': 'keep-alive',
        'Cache-Control': 'max-age=0',
        'Origin': 'http://***.***.***.***',
        'Upgrade-Insecure-Requests': '1',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Referer': 'http://***.***.***.***/jmq-web/login.html'
    }
    data = {
        'j_username': '***',
        'j_password': '***'
    }
    r = s.request('post', url, headers=header, data=data)
    print(r.status_code, '\n')
    print(r.request._cookies, '\n')
    return r.request._cookies

def login_gw():
    url = 'http://***.***.***.***/sso/login?ReturnUrl=http://***.***.***.***'
    header = {
        'Host': 't***.***.***.***',
        'Connection': 'keep-alive',
        'Content - Length': '129',
        'Cache-Control': 'max-age=0',
        'Origin': 'http://***.***.***.***',
        'Upgrade-Insecure-Requests': '1',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Referer': 'http://***.***.***.***/sso/login?ReturnUrl=http://***.***.***.***/'
    }
    data = {
        'fp': 'FLHQPKIPZV2RVCQG66V4EYHD4RWGFY3OUIPV5IK2ZH25NG6P63O35C4NASGOMLIJEA4ZWCSXIF32WS4PU27O3JY25A',
        'username': '***',
        'password': '****'
    }
    try:
        r = s.request('post', url, headers=header, data=data)
    except Exception as e:
        print(e)
    print(r.status_code, '\n')
    print(r.request._cookies, '\n')
    return r.request._cookies

def queryUUID(orderId):
    loginCookie=login_gw()
    search_url = 'http://***.***.***.***/refund/refundList?orderId=++'+orderId+'&businessType=-1&pin=&refundStatus=-1&isHis=false'
    search_header = {
        'Host': 'gw.man.jd.com',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Referer': 'http://***.***.***.***/refund/refundList',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    }
    search_Response = s.request('get', search_url, headers=search_header, cookies=loginCookie)
    text=search_Response.text
    r=r'\d{7}	'
    pattern = re.compile(r)
    #result=pattern.search(text)
    result=pattern.findall(text)
    refundMessages = []
    for refundId_str in result:
        refundId = re.search(r'\d{7}',refundId_str).group(0)
        refundDetail_url = 'http://***.***.***.***/refund/refundDetailList?refundId=' + refundId + '&refundStatus=0'
        refundDetail_header = {
            'Host': '***.***.***.***',
            'Connection': 'keep-alive',
            'Content-Type': 'application/x-www-form-urlencoded',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36',
            'Accept': '*/*',
            'X-Requested-With': 'XMLHttpRequest',
            'Referer': 'http://***.***.***.***/refund/refundList?orderId='+orderId+'&businessType=-1&pin=&refundStatus=-1&isHis=false',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        }
        refundDetail_Response = s.request('get', refundDetail_url, headers=refundDetail_header, cookies=loginCookie)
        UUID = re.search(r'jp_[0-9a-zA-Z\-]+', refundDetail_Response.text).group(0)
        refundPrice = re.search(r'\d*\.\d{2}',re.search(r'￥\d*\.\d{2}	', refundDetail_Response.text).group(0)).group(0)
        refundMessages.append({'orderId':orderId,'uuid': UUID, 'refundPrice': refundPrice, 'refundId': refundId})
    return refundMessages

def sendMQ(orderMessage):
    logginCookie = login()
    sendMqUrl = 'http://***.***.***.***/jmq-web/subscribe/addConsumerRetry.do'
    sendMqheader = {
        'Host': '***.***.***.***',
        'Connection': 'keep-alive',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Cache-Control': 'max-age=0',
        'Origin': 'http://***.***.***.***',
        'X-Requested-With': 'XMLHttpRequest',
        'Upgrade-Insecure-Requests': '1',
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Referer': 'http://***.***.***.***/jmq-web/consumerMonitor.do'
    }
    #orderConfirmId='2212101001131793275a656756'
    orderConfirmId=''.join(random.sample(string.ascii_letters + string.digits, 30))
    orderConfirmTime=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
    sendMqdata = {
        'topicId': '',
        'app': 'popjipiao',
        'topic':'PS_DZvirtual_Success',
        'businessId':'35',
        'message':'{ "orderId":"%s", "parentOrderId":"0", "payId":"", "orderConfirmPrice":%s, "confirmType":"createPay", "confirmResultType":"full", "pin":"%s", "orderConfirmTime":"%s", "orderConfirmId":"%s", "orderType":35, "ver":0, "realDuePrice":%s, "realPayPrice":%s, "paidIn":%s, "auditStatus":0, "dbIndex":"4", "lastOrderBankStatus":1, "refundType":0, "payMode":4, "psMode":0, "price":%s, "id":%s, "shouldMorePayRefund":0.0000 }'%(orderMessage[0],orderMessage[2],orderMessage[1],orderConfirmTime,orderConfirmId,orderMessage[2],orderMessage[2],orderMessage[3],orderMessage[3],orderMessage[0])
    }
    mqResponse=s.request('post',sendMqUrl,headers=sendMqheader,data=sendMqdata,cookies=logginCookie)
    print(orderConfirmId)
    print(orderConfirmTime)
    print(sendMqdata.get('message'))
    print(mqResponse.json(),'\n')

    def queryUUID(orderId):
        loginCookie = login_gw()
        search_url = 'http://***.***.***.***/refund/refundList?orderId=++' + orderId + '&businessType=-1&pin=&refundStatus=-1&isHis=false'
        search_header = {
            'Host': 'gw.man.jd.com',
            'Connection': 'keep-alive',
            'Upgrade-Insecure-Requests': '1',
            'Content-Type': 'application/x-www-form-urlencoded',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'Referer': 'http://***.***.***.***/refund/refundList',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        }
        search_Response = s.request('get', search_url, headers=search_header, cookies=loginCookie)
        text = search_Response.text
        r = r'\d{7}	'
        pattern = re.compile(r)
        refundId = re.search(r'\d{7}', pattern.search(text).group(0)).group(0)
        print(refundId)

        refundDetail_url = 'http://***.***.***.***/refund/refundDetailList?refundId=' + refundId + '&refundStatus=0'
        refundDetail_header = {
            'Host': '***.***.***.***',
            'Connection': 'keep-alive',
            'Content-Type': 'application/x-www-form-urlencoded',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
            'Accept': '*/*',
            'X-Requested-With': 'XMLHttpRequest',
            'Referer': 'http://***.***.***.***/refund/refundList?orderId=++56288525121&businessType=-1&pin=&refundStatus=-1&isHis=false',
            'Accept-Encoding': 'gzip, deflate',
            'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        }
        refundDetail_Response = s.request('get', refundDetail_url, headers=refundDetail_header, cookies=loginCookie)
        UUID = re.search(r'jp_\d{6}', refundDetail_Response.text).group(0)
        return UUID

def sendMQ_refund(orderId,refundMoney,uuid,refundId):
    logginCookie = login()
    sendMqUrl = 'http://1***.***.***.***/jmq-web/subscribe/addConsumerRetry.do'
    sendMqheader = {
        'Host': '***.***.***.***',
        'Connection': 'keep-alive',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Cache-Control': 'max-age=0',
        'Origin': 'http://***.***.***.***',
        'X-Requested-With': 'XMLHttpRequest',
        'Upgrade-Insecure-Requests': '1',
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Referer': 'http://***.***.***.***/jmq-web/consumerMonitor.do'
    }
    jdRefundId=refundId
    refundTime=time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
    transactionNumber=uuid
    sendMqdata = {
        'topicId': '',
        'app': 'airplane',
        'topic':'refundCallback',
        'businessId':orderId,
        'message':'{"bussinessType":"35","field1":"35","field2":"","jdRefundId": %s,"memo":"","orderId":%s,"refundMoney": %s,"refundTime":"%s","status":"0","transactionNumber":"%s"}' % (jdRefundId,orderId,refundMoney,refundTime,transactionNumber)
    }
    mqResponse=s.request('post',sendMqUrl,headers=sendMqheader,data=sendMqdata,cookies=logginCookie)
    print(mqResponse.content)
    print(sendMqdata)

def index(request):
    url = 'http://***.***.***.***.88:8080/sso?appid=6a325be8-8e11-3b67-a8e5-d9f113b23847&erpusername=****&param={"returnurl":"http://'+get_host_ip()+':8088/allInOne"}'
    r = requests.get(url)
    ajson = json.loads(r.text)
    print(ajson)
    print(ajson['result'])
    response = HttpResponseRedirect(ajson['result'])
    return response

def allInOne(request):
    rr = request.GET['sso_service_ticket']
    if rr == request.GET['sso_service_ticket']:
        request.session['is_login'] = True
        print(request.session['is_login'])
    else:
        return HttpResponse('http://'+get_host_ip()+':8088/index')

    if request.session['is_login']:
        return render(request, 'allInOne.html')
def get_host_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()
    return ip


n = int(input())

hyuns = []

dp = dict()

for _ in range(n):
    hyuns.append(tuple(map(int, input().split())))

def isin(hyun1, hyun2): # -1 for outside, 1 for inside, 0 for invalid
    h1s = hyun1[0]
    h1l = hyun1[1]
    h2s = hyun2[0]
    h2l = hyun2[1]
    if hyun1[0] > hyun1[1]:
        h1s = hyun1[1]
        h1l = hyun1[0]
    if hyun2[0] > hyun2[1]:
        h2s = hyun2[1]
        h2l = hyun2[0]
    if h2s < h1s:
        if h2l < h1l and h2l > h1s:
            return 0
    else:
        if h2l > h1l and h2s < h1l:
            return 0
    if h1s <h2s and h2s<h1l:
        return 1
    else:
        return -1

def findmax(hyuns):
    if len(hyuns) <= 1:
        return len(hyuns)
    if hyuns in dp.keys():
        return dp[hyuns]
    if len(hyuns) == 2:
        if isin(hyuns[0], hyuns[1])!=0:
            dp[hyuns] = 2
            return 2
        else:
            dp[hyuns] = 1
            return 1
    maxv = 1
    for i in hyuns:
        ins = []
        outs = []
        for j in hyuns:
            if i!=j:
                isinr = isin(i,j)
                if isinr == 1:
                    ins.append(j)
                elif isinr == -1:
                    outs.append(j)
        maxv = max(findmax(tuple(ins)) + findmax(tuple(outs))+1, maxv)
    dp[hyuns] = maxv
    return maxv

print(findmax(tuple(hyuns)))


# 3진법 뒤집기

def solution(n):
    result = ''
    i = 3
    tmp = 0
    a = 0
    while a > 0:
        a, b = divmod(n, i.sqrt(tmp))
    max = i-1
    print(max)

    # for i in range(1, max, -1):
    #   result += str(n//i)
    #   n %= i
    # print(result)
    return
# return result[::-1]

print(solution(45))
# print(solution(125)


ANSIBLE_METADATA = {
    'metadata_version': '1.2',
    'status': ['ready'],
    'supported_by': 'cherkavi'
}

DOCUMENTATION = '''
---
module: oc_collaboration
author: cherkavi
short_description: create/delete and waiting for the start of resource ( pod, job, deployment... )
description: example of collaboration with OpenShift via REST API
options:
    operation:
      description:
         one of possible operations: create, delete, waiting_for_start
    file:
      description:
         full path to file with description
    timeout:
      description:
         default value is 120 sec, useful for 'waiting_for_start' only

requirements: 'os status'

the same you can reach out using K8S module: https://docs.ansible.com/ansible/latest/modules/k8s_module.html
'''

EXAMPLES = '''
apiVersion: batch/v1
kind: Job
metadata:
  name: test-job
spec:
  nodeSelector:
    composer: true
  template:
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["echo", "'hello'"]
      restartPolicy: Never
  backoffLimit: 1

- hosts: all
  gather_facts: False
  tasks:
  - name: create deployment
    openshift-wait-for-start:
      operation: create
      file: /home/projects/test-job.yml
    register: creation_result

  - name: print result
    debug:
      msg: "result is {{ creation_result }}"

  - name: waiting for start/fail
    openshift-wait-for-start:
      operation: waiting_for_start
      file: /home/projects/test-job.yml
      timeout: 50
    register: waiting_result
'''

import requests
import yaml
import subprocess
import time
from ansible.module_utils.basic import AnsibleModule
import abc
# import pdb

def clear_binary_line(b_line):
    return b_line.decode('utf-8').rstrip()

def parse_info(path_to_file):
    return_value = []
    with open(path_to_file, 'r') as data_file:
        yaml_data = yaml.load_all(data_file)
        for each_yaml in yaml_data:
            resource_type = each_yaml['kind'].lower()
            resource_name = each_yaml['metadata']['name']
            return_value.append((resource_type, resource_name))
    return return_value

class Checker:
    def __init__(self, resource_name):
        self.name = resource_name
        # need to check again, result is not ready
        self.need_to_check = True
        # result is defined, readiness status ( Running/Completed or Failed )
        self.ready = False

    @staticmethod
    def create(resource_type, resource_name):
        """ factory method """
        if resource_type == "job":
            return JobChecker(resource_name)
        if resource_type == "deployment":
            return DeploymentChecker(resource_name)
        if resource_type == "pod":
            return PodChecker(resource_name)
        return None

    @staticmethod
    def _parse_response(response):
        if not (200 <= response.status_code < 300):
            return None
        return response.json()['status']

    @abc.abstractmethod
    def _check_phase(self, result):
        self._not_ready()

    def _not_ready(self):
        self.need_to_check = False
        self.ready = False

    @abc.abstractmethod
    def _build_url(self, endpoint, namespace):
        return endpoint + namespace

    def check(self, endpoint, namespace, token):
        url = self._build_url(endpoint, namespace)
        with requests.get(url,
                          verify=False,
                          headers={"Authorization": "Bearer {}".format(token), "Accept": "application/json"}) as response:
            result = Checker._parse_response(response)
            if not result:
                self._not_ready()
            else:
                self._check_phase(result)

class PodChecker(Checker):
    def __init__(self, resource_name):
        super().__init__(resource_name)

    def _build_url(self, endpoint, namespace):
        return "{}/api/v1/namespaces/{}/pods/{}".format(endpoint, namespace, self.name)

    def _check_phase(self, status):
        if status["phase"]:
            if status["phase"]=="Failed":
                self.need_to_check = False
                self.ready = False
                return
            if status["phase"]=="Running":
                self.need_to_check = False
                self.ready = False
                for each_condition in status["conditions"]:
                    if each_condition["type"]=="Ready":
                        self.ready = each_condition["status"]=="True"
                return
        self.need_to_check = True
        self.ready = False

class JobChecker(Checker):
    def __init__(self, resource_name):
        super().__init__(resource_name)

    def _build_url(self, endpoint, namespace):
        return "{}/apis/batch/v1/namespaces/{}/jobs/{}".format(endpoint, namespace, self.name)

    def _check_phase(self, status):
        if "succeeded" in status and status["succeeded"] > 0:
            self.need_to_check = False
            self.ready = True
            return
        if "failed" in status and status["failed"] > 0:
            self.need_to_check = False
            self.ready = True
            return

        for each_condition in status["conditions"]:
            if each_condition["type"] == "Complete":
                self.need_to_check = False
                self.ready = True
                return
            if each_condition["type"] == "Failed":
                self.need_to_check = False
                self.ready = False
                return
        self.need_to_check = True
        return

class DeploymentChecker(Checker):
    def __init__(self, resource_name):
        super().__init__(resource_name)

    def _build_url(self, endpoint, namespace):
        return "{}/apis/extensions/v1beta1/namespaces/{}/deployments/{}".format(endpoint, namespace, self.name)

    def _check_phase(self, status):
        for each_condition in status["conditions"]:
            if each_condition["type"] == "Available":
                self.need_to_check = False
                self.ready = True
                return
            if each_condition["type"] == "Failed":
                self.need_to_check = False
                self.ready = False
                return
        self.need_to_check = True
        return

def is_resource_was_started(endpoint, namespace, token, path_to_description, waiting_seconds=120):
    all_documents = parse_info(path_to_description)
    documents = list(filter(lambda entity: entity is not None, map(lambda x: Checker.create(x[0], x[1]), all_documents)))
    # to debug via PDF
    # pdb.set_trace()
    if len(documents) == 0:
        raise ValueError("file should contain at least one of: pod, job, deployment...")
    while any(map(lambda doc: doc.need_to_check, documents)):
        for each_document in documents:
            each_document.check(endpoint, namespace, token)
        waiting_seconds = waiting_seconds - 1
        time.sleep(1)
    return all(map(lambda doc: doc.ready, documents))

def create(path_to_file):
    try:
        return True, clear_binary_line(subprocess.check_output(["oc", "create", "-f", path_to_file]))
    except subprocess.CalledProcessError:
        return False, "possible resource is already exist "

def delete(path_to_file):
    try:
        return True, clear_binary_line(subprocess.check_output(["oc", "delete", "-f", path_to_file]))
    except subprocess.CalledProcessError:
        return False, "not deleted, maybe not exists"

def module_result(module, return_status, return_value):
    message = return_value if return_value else ""
    if return_status:
        module.exit_json(changed=True, msg=message)
    else:
        module.fail_json(changed=False, msg=message)

def main():
    input_fields = {
        "operation": {"required": True, "type": "str"},
        "file": {"required": True, "type": "str"},
        "timeout": {"required": False, "type": "str", "default": "120"}
    }
    module = AnsibleModule(argument_spec=input_fields)
    operation = module.params["operation"]
    file = module.params["file"]
    timeout = int(module.params["timeout"].strip())

    oc_token = clear_binary_line(subprocess.check_output(["oc", "whoami", "-t"]))
    if "Error from server" in oc_token:
        module_result(module, False, "you must be logged in into OpenShift")
        return

    if operation not in ["create", "delete", "waiting_for_start"]:
        module_result(module, False, "'operation' must be one of: create, delete, waiting_for_start ")
        return

    if operation == "create":
        return_status, return_value = create(file)
        module_result(module, return_status, return_value)
        return

    if operation == "delete":
        return_status, return_value = delete(file)
        module_result(return_status, return_value)
        return

    oc_status = clear_binary_line(subprocess.check_output(["oc", "status"])).split("\n")[0].split(" ")
    oc_endpoint = oc_status[5]
    oc_namespace = oc_status[2]
    try:
        return_status = is_resource_was_started(oc_endpoint, oc_namespace, oc_token, file, waiting_seconds=timeout)
        module_result(module, return_status, "")
        return
    except ValueError as e:
        module_result(module, False, e.args[0])

if __name__ == '__main__':
    main()


import datetime
import random
import sys
import time

LOG_PATH = "./batch.log"
log = open(LOG_PATH, "wa")

start = time.time()
progress = time.time()
count = 0

while progress - start < 180:
    log = open(LOG_PATH, "ab")
    progress = time.time()
#    time.sleep(0.1)
    timestamp = datetime.datetime.now()
    timestamp = timestamp.isoformat()
    value = random.randint(0,100)
#    print type(timestamp), type(value), type(sys.argv[1])
#    print "[%s][Random]: Application-id: %s: #%i\n" % (timestamp, sys.argv[1], value)
    if count % 60000 == 0:
        log.write("[%s][Random]: Application-id: %s: #%i\n" % (timestamp, sys.argv[1], value))
    log.close()
    count += 1

log = open(LOG_PATH, "ab")
log.write("[END]")


lista = []

pross = True
while pross:
    try:
        print("Ingrese numeros\nPulse 0 para terminar")
        num = int(input())
        if num > 0 and num <= 100:
            lista.append(num)
            lista.sort()
            print(lista)
            print("")

        elif num == 0:
            pross = False;

        else:
            print("SOLO NUMEROS DEL 1 AL 100")

    except ValueError:
        print("INGRESE UN VALOR VALIDO")


from zope.interface import implementer
from guillotina.events import ObjectEvent
from guillotina_cms.interfaces import IWorkflowChangedEvent

@implementer(IWorkflowChangedEvent)
class WorkflowChangedEvent(ObjectEvent):
    """An object has been moved"""

    def __init__(self, object, workflow, action, comments):
        ObjectEvent.__init__(self, object)
        self.object = object
        self.workflow = workflow
        self.action = action
        self.comments = comments


import numpy as np
from matplotlib import pyplot as plt

def LogisticMap(x0, r):
    return (r*x0)*(1-x0)

def LogisticMapDerivative(x0, r):
    return r-2*r*x0

def Bifurcation(x0, rMin, rMax, dr, iters = 150, includeTransients = False):
    Xn = []
    R = []
    rArr = np.linspace(rMin, rMax, int(1/dr))
    for r in rArr:
        xn = x0
        # Calculate Several generations first before adding data
        for i in range(iters):
            xn = LogisticMap(xn, r)
            # only start adding once a certain number of iterations occur (Let Points Stabalize)
            if includeTransients:
                Xn.append(xn)
                R.append(r)
            elif i > (int(iters/2)) and not includeTransients:
                Xn.append(xn)
                R.append(r)

    return (Xn, R)

def getStablePoints(r, Xn):
    stablePoints = {"r":[], "Xn":[]}
    pass

# Plots
def plotBifurcation(r, Xn, showPlot = True, savePlot = False, saveName = "Plots/Bifurcation.png",
                    xLimLeft = 2.0, xLimRight = 4.0, yLimBottom = 0.0, yLimTop = 1.0,
                    title = "Bifurcation Diagram", xLabel = "r", yLabel = "X*", markerSize = 0.5, closePlot = True, color = "black"):
    #Plot Bifurcation - use subplots because marker sizes go smaller as well
    plt.subplots(figsize = (23, 13))
    plt.scatter(r, Xn, s = markerSize, marker = '.', linewidth = 0, c = color)
    plt.ylim(bottom = yLimBottom, top= yLimTop)
    plt.xlim(left = xLimLeft, right = xLimRight)
    plt.title(title)
    plt.xlabel(xLabel)
    plt.ylabel(yLabel)
    if showPlot:
        plt.show()
    elif savePlot:
        plt.savefig(saveName)
    if closePlot:
        plt.close()


def bubble_sort(a):
    #a : array
    n = len(a)
    for i in range(n):
        for j in range(0,n-i-1):
            if a[j]>a[j+1]:
                a[j],a[j+1]=a[j+1],a[j]

def linear_sort(n,x):
    element=[]
    for i in range(1,n):
        element.append(i)
    flag = 0
    for i in element:
        if i==x:
            print('Yes! I foung my number at position:'+str(i))
            flag = 1
    if flag==0:
        print('Number is not found!')

def binary_search(a,x):
    first_pos = 0
    last_pos = len(a)-1
    #flag=0 mean that the element has not be found yet
    flag = 0
    count = 0
    while first_pos<=last_pos and flag==0:
        count+=1
        mid = (first_pos+last_pos)//2
        if x==a[mid]:
            flag=1
            print('Element is present at position: '+str(mid))
            print('The number of iterations are: '+str(count))
            return
        else:
            if x<a[mid]:
                last_pos = mid-1
            else:
                first_pos = mid+1
    print('The number is not present!')