from utils.db import connect

def get_active(chat_id):

    db = connect()
    cursor = db.cursor(prepared=True)
    query = "SELECT char_id FROM active WHERE chat_id = %s"

    try:
        cursor.execute(query, (chat_id,))
    except:
        print("can not retriever char_id from active")

    result = cursor.fetchall()

    try:
        char_id = int(result[0][0])
    except:
        return None

    if not result:
        return None

    query = "SELECT char_name FROM `character` WHERE char_id = %s"

    try:
        cursor.execute(query, (char_id,))
    except:
        print("can not retriever char name from character")

    if not result and result[0][0] is not None:
        return None
    else:
        return char_id

def get_hp(char_id):

    db = connect()
    cursor = db.cursor(prepared=True)
    query = "SELECT life FROM `character` WHERE char_id = %s"

    try:
        cursor.execute(query, (char_id,))
    except:
        print("can not retriever char life from character")

    result = cursor.fetchall()

    return int(result[0][0])

def get_name(char_id):

    db = connect()
    cursor = db.cursor(prepared=True)
    query = "SELECT char_name FROM `character` WHERE char_id = %s"

    try:
        cursor.execute(query, (char_id,))
    except:
        print("can not retriever char life from character")

    result = cursor.fetchall()
    return result[0][0]

def update_life(char_id, char_hp):

    db = connect()
    cursor = db.cursor(prepared=True)
    query = "UPDATE `character` SET life = %s WHERE char_id = %s "

    try:
        cursor.execute(query, (char_hp, char_id))
        db.commit()
    except:
        print("can not update char life from character")


import cloudinary
import cloudinary.uploader
from flask import Blueprint, jsonify, request
from models.imagen import Imagen
from models.noticia import Noticia

api = Blueprint('api_noticias', __name__)

#Ruta para agregar una noticia
@api.route('/administrar/agregarNoticia', methods=['POST'])
def upload_image():

    # Asignamos a una variable los valores rescatados del form,
    titulo = request.form['titulo']
    descripcion = request.form['descripcion']
    image = None

    if not titulo: return jsonify({"message": "Titulo is required!"}), 400
    if not descripcion: return jsonify({"message": "Descripcion is required!"}), 400
    if not 'image' in request.files:
        return jsonify({"message": "Image is required!"}), 400
    else:
        image = request.files['image']

    response = cloudinary.uploader.upload(image, folder="imagenesFidi")

    if response:
        nuevaImagen = Imagen()
        nuevaImagen.src_imagen = response['secure_url']
        nuevaImagen.id_publico = response['public_id']
        nuevaImagen.activo = True
        nuevaImagen.save()

        nuevaNoticia = Noticia()
        nuevaNoticia.titulo = titulo
        nuevaNoticia.descripcion = descripcion
        nuevaNoticia.src_imagen = response['secure_url']
        nuevaNoticia.save()

    return jsonify({ "image": nuevaImagen.serialize(), "message": "Noticia creada satisfactoriamente"}), 201

@api.route('/administrar/modificarNoticia')
def modify_notice():

    noticias = Noticia.query.all() # [<User 1>, <User 2>]
    noticias = list(map(lambda noticia: noticia.serialize(), noticias)) # [{"id": 1}, {"id": 2}]

    return jsonify(noticias), 200


import json
from django.http import JsonResponse, FileResponse
import os

# Create your views here.
from gif_gen.src.service.gif_generator import GifGenerator
from gif_gen.src.utils import build_gif_name

def upload_video(request):
    if request.method == "POST":
        my_file = request.FILES.get("my_file", None)
        if not my_file:
            return JsonResponse({'message': 'no files to upload.'})
        file_path = os.path.join(os.getcwd(), "tmp/videos", my_file.name)
        destination = open(file_path, "wb+")
        for chunk in my_file.chunks():
            destination.write(chunk)
        destination.close()
        return JsonResponse({'file_path': file_path, 'file_name': my_file.name})

def video_to_gif_quick(request):
    GIFS_DIR = os.path.join(os.getcwd(), "tmp/gifs/")
    gif_gen = GifGenerator()
    # video_path = eval(request.body.decode()).get('video_path')
    body = json.loads(request.body.decode())
    video_path = body.get('video_path')
    video_name = body.get('video_name')
    gif_name = build_gif_name(video_name)
    gif_gen.video2gif_quick(video_path, GIFS_DIR + gif_name)
    return JsonResponse({'message': 'transform over.'})

def download(request):
    GIFS_DIR = os.path.join(os.getcwd(), "tmp/gifs/")
    video_name = request.GET.get('video_name')
    gif_name = build_gif_name(video_name)
    file = open(GIFS_DIR + gif_name, 'rb')
    response = FileResponse(file)
    response['Content-Type'] = 'application/form-data'
    # content_dis = 'attachment;filename="' + gif_name + '"'
    # response['Content-Disposition'] = content_dis
    return response

if __name__ == '__main__':
    PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.getcwd())))
    a = os.path.join(PROJECT_ROOT, "tmp", "my_file.name")
    print(PROJECT_ROOT)
    print(a)


"""def greet_user(username):
    #显示简单的问候语
    print("Hello, "+username.title()+"!")
greet_user('jesse')
greet_user('sarah')

def display_message():
    print("In this chapter I learn about functions.")
display_message()

def favorite_book(title):
    print("One of my favorite books is "+title.title()+".")
favorite_book('alice in wonderland')

#def describe_pet(animal_type,pet_name):
def describe_pet(pet_name,animal_type='dog'):#默认值：形参指定默认值,要先列出没有默认值得形参
    print("I have a "+animal_type+".")
    print("My "+animal_type+"'s name is "+pet_name.title()+".")
#describe_pet('dog','baibai')#位置实参：要求实参顺序与形参相同
describe_pet(animal_type='cat',pet_name='boss')#关键字实参
describe_pet(pet_name='baibai'.title())#关键字实参

def make_shirt(size,type):
    print("The shirt size is "+size+", and the type is "+type)
make_shirt('xl','Hello world!')"""

def get_formatte_name(first_name,last_name,middle_name=''):
    """if middle_name:
        print(first_name.title()+" "+middle_name.title()+" "+last_name.title())
    else:
        print(first_name.title()+" "+last_name.title())
get_formatte_name('cheng','qin','yu')#位置实参，要按顺序填写
get_formatte_name('wang','shan')"""
    if middle_name:
        full_name=first_name+' '+middle_name+' '+last_name

    else:
        full_name=first_name+' '+last_name
    return full_name.title()
musician=get_formatte_name('cheng','qin','yu')#位置实参，要按顺序填写
print(musician)
musician=get_formatte_name('wang','shan')
print(musician)


from django.urls import path
from . import views

urlpatterns = [
    path('', views.index),
    path('addBook/',views.add_book),
    path('addAuthor/',views.add_author),
    path('book/<book_ID>',views.details),
    path('authors/<author_ID>',views.author_details),
    path('authors/', views.author_index),
    path('addNewAuthor/',views.add_new_author),
    path('addBookToAuthor/',views.add_book_to_author),

]


"""
A module with some scripts for automatic documentation generation

By Ian Bell, NIST, 2016-
"""

from __future__ import print_function
from io import StringIO
import glob, os, json, six, sys, textwrap, time

name_remapping = {'CCRIT':'CSTAR',
                  'SATPEST':None,
                  'SATTEST':None}

fallback_arguments = {'GERG04dll': 'GERG08', 'THERM2dll': ['THERMdll','THERM3dll','AG','DERVPVTdll']}

FLSH_funcs = [k+'FLSHdll' for k in ['DE','DH','DS','ES','HS','PD','PE','PH','PQ','PS','TD','TE','TH','TP','TQ','TS','DQ']]
FLSH_funcs += [k+'FL1dll' for k in ['DE','DH','DS','ES','HS','PD','PE','PH','PQ','PS','TD','TE','TH','TP','TQ','TS','DQ']]
FLSH_funcs += [k+'FL2dll' for k in ['DE','DH','DS','ES','HS','PD','PE','PH','PQ','PS','TD','TE','TH','TP','TQ','TS','DQ']]
FLSH_funcs += ['ENTHALdll','ENTROdll','CVCPdll']

FLSH_other_input_args = ['Z','DMIN','DMAX']
FLSH_args = {
    'P': 'Pressure [kPa]',
    'Q': 'Vapor quality [mol/mol]',
    'T': 'Temperature [K]',
    'E': 'Internal energy [J/mol]',
    'H': 'Enthalpy [J/mol]',
    'S': 'Entropy [J/mol-K]',
    'D': 'Density [mol/L]',
    'DL': 'Molar density of the liquid phase [mol/L]',
    'DV': 'Molar density of the vapor phase [mol/L]',
    'CV': 'Isochoric heat capacity [J/mol-K]',
    'CP': 'Isobaric heat capacity [J/mol-K]',
    'W': 'Speed of sound [m/s]',
    'HJT': 'Isenthalpic Joule-Thomson coefficient [K/kPa]',
    'HERR': 'Error string (character*255)',
    'IERR': 'Error code (no error if ierr==0)',
    'Z': 'Bulk Composition (array of mole fractions)',
    'X': 'Composition of the liquid phase (array of mole fractions)',
    'Y': 'Composition of the vapor phase (array of mole fractions)',
    'DMIN': 'Lower bound on density [mol/L]',
    'DMAX': 'Upper bound on density [mol/L]'
}

High_Level_Header = """

.. This file was auto-generated on {datetime:s}. DO NOT(!!!!) modify this file directly.  Modify the generator script in the scripts folder.

.. _high_level_api:

**************
High-Level API
**************

"""

Legacy_Header = """

.. This file was auto-generated on {datetime:s}. DO NOT(!!!!) modify this file directly.  Modify the generator script in the scripts folder.

**********
Legacy API
**********

.. warning::

    The functions in this legacy application program interface (API) have all been deprecated and will be removed in some future release.  Please use the :ref:`high_level_api`:

"""

High_level_functions = ['REFPROPdll','REFPROP1dll','REFPROP2dll','ALLPROPSdll','ALLPROPS0dll','ALLPROPS1dll','ABFLSHdll','GETENUMdll','ERRMSGdll','SETFLUIDSdll','SETMIXTUREdll','SETPATHdll','FLAGSdll']

def generate_manual_content(FOR_path, JSON_ofname = None):
    """
    Generate a dictionary mapping from function name to documentation

    FOR_path: string
        Path to the folder containing the .FOR files
    JSON_ofname: string, optional
        If provided, the file to which the content will be written in JSON format
    """

    # Get all the fortran files
    for_files = []
    for ending in ['*.FOR','*.for']:
        for_files += glob.glob(os.path.join(FOR_path, ending))
    assert(len(for_files) > 0)

    # Join all the files into one big string
    joined = ''
    for for_file in for_files:
        with open(for_file,'r') as fp:
            joined += fp.read() + '\n'

    # Munge function arguments as needed to replace arguments that span lines
    isubstart = 0
    while isubstart > -1:
        isubstart = joined.find('subroutine',isubstart)

        isubopen = joined.find('(', isubstart)
        isubclose = joined.find(')', isubopen)
        iEOL = joined.find('\n', isubstart)

        # Skip ones with newline between end of subroutine and (
        if iEOL < isubopen:
            isubstart += 1 # go to next instance of subroutine
            continue

        # Skip ones that are in the comments block
        ipreEOL = joined.rfind('\n', 0, isubstart) # Find preceding EOL

        if joined[ipreEOL+1:ipreEOL+3].startswith('c '):
            isubstart = isubclose
            continue

        if '\n' in joined[isubstart:isubclose+1]:
            old = joined[isubstart:isubclose+1]
            new = old.replace('\n','').replace('&','')
            joined = joined.replace(old, new)
            isubstart += 1
            continue

        isubstart = joined.find('subroutine',isubclose)
        if isubstart < 0:
            break

    ####### Uncomment next lines to see what it did
    with open('joined.txt','w') as fp:
        fp.write(joined)

    objects = {}

    lines = joined.split('\n')
    for i in range(len(lines)):

        if lines[i].strip().startswith('subroutine') or lines[i].strip().startswith('function'):

            objname = lines[i].split('(')[0].replace('subroutine ','').replace('function ','').strip()
            objlines = []
            for j in range(10000):
                if i+j == len(lines): break
                if "ritten by" in lines[i+j] or 'original version' in lines[i+j]:
                    break
                elif ' include \'' in lines[i+j] and not lines[i+j].strip().startswith('c '):
                    break
                elif lines[i+j] == ' ':
                    break
                else:
                    objlines.append(lines[i+j])

            objects[objname] = '\n'.join(objlines)

            i += j

    if JSON_ofname:
        with open(JSON_ofname,'w') as fp:
            json.dump(objects, fp, indent =2)
    return objects

def deconstruct_function_info(contents):

    def line_decomment(line):
        if line == 'c': return ''
        if line.startswith('c '):
            return line[1::]
        else:
            return line.strip()

    def line_startswith(s, search, EOL = None):
        o = None
        for iline, line in enumerate(s):
            decomm = line_decomment(line).lstrip()
            if EOL is not None:
                if decomm.startswith(search) and decomm.strip().endswith(EOL):
                    return iline
            else:
                if decomm.startswith(search):
                    return iline
        return o

    def line_containing(s, search):
        o = None
        for iline, line in enumerate(s):
            if search in line:
                return iline
        return o

    def deconstruct_parameters(lines):
        # Find the lines that have '--' in them, and add another at the end
        seps = [iline for iline, line in enumerate(lines) if '--' in line] + [len(lines)]
        args, flags = {}, {}
        # Get all the arguments
        for j in range(len(seps)-1):
            istart,iend = seps[j],seps[j+1]
            # Get the argument based on the first line
            try:
                arg, desc = line_decomment(lines[istart]).strip().split('--')
                if ':' in desc:
                    desc = desc.split(':')[0]
            except ValueError as VE:
                print(line_decomment(lines[istart]).strip())

            # If the line has a ': in it, then the stuff that follows is a list of flags, otherwise, the following lines are glommed together
            if ':' in line_decomment(lines[istart]).strip():
                otherlines = [lines[istart].split(':')[1]] + lines[istart+1:iend]
                if otherlines and iend > istart+1:
                    if len(otherlines) == 1 and not line_decomment(otherlines[0]).strip():
                        # Empty line, don't do anything
                        continue
                    else:
                        lastkey = None
                        info = {}
                        for line in otherlines:
                            cleaned = line_decomment(line).strip()
                            if ' - ' not in cleaned:
                                # if lastkey is None:
                                #     print(lines, info, line)
                                print(lastkey, info, cleaned)
                                if cleaned:
                                    info[lastkey] += ' ' + cleaned
                                # else:
                                #     print('BAD!!!: ', cleaned, '<--', line)
                            else:
                                k,v = cleaned.split(' - ',1)
                                info[k.strip()] = v.strip()
                                lastkey = k.strip()
                        flags[arg.strip().lower()] = info
            else:
                # Keep on glomming the rest in, with spaces between lines
                otherlines = lines[istart+1:iend]
                desc += ' '+ ' '.join([line_decomment(l).strip() for l in otherlines])

            args[arg.strip().lower()] = desc
            # print('OOOOOOOOOOOOOOOOO', lines[istart-1], '||', otherlines, info)
        return args, flags

    # Find the line that contains "Input" and "Output"
    iInputs = line_startswith(contents, 'Input', EOL=':') or line_startswith(contents, 'Inputs', EOL=':')
    iOutput = line_startswith(contents, 'Output', EOL=':') or line_startswith(contents, 'Outputs', EOL=':')

    print(iInputs, iOutput)

    class struct(object): pass
    info = struct()
    info.doc_block = '\n\n'+ ' '*4+'XXXXXXXXXXXXXXXXXXXX  CANNOT GET DOCS\n\n'
    info.in_args, info.in_flags = {},{}
    info.out_args, info.out_flags = {},{}
    def indent(lines, n):
        return '\n'.join([' '*n + l for l in lines])

    if iInputs is None and iOutput is None:
        info.doc_block = indent(textwrap.dedent('\n'.join([line_decomment(line) for line in contents[1::]])).split('\n'), 4)

    if iInputs is not None or iOutput is not None:
        iMax = iInputs if iInputs is not None else iOutput
        info.doc_block = indent(textwrap.dedent('\n'.join([line_decomment(line) for line in contents[1:iMax]])).split('\n'), 4)

        if iInputs is not None:
            if iOutput is not None:
                info.in_args, info.in_flags = deconstruct_parameters(contents[iInputs+1:iOutput])
            else:
                info.in_args, info.in_flags = deconstruct_parameters(contents[iInputs+1::])
        if iOutput is not None:
            info.out_args, info.out_flags = deconstruct_parameters(contents[iOutput+1::])
    # print(info.in_args)
    return info

def parse_manual_contents(contents, function_dict, dll_functions):
    """
    Write the RST data needed by the sphinx-fortran package
    """
    def chop_dll(s):
        if s.endswith('dll'):
            return s[0:-3]
        else:
            return s
    # Functions that end with dll in the PASS_FTN.FOR file
    has_dll = [funcname for funcname, lines in six.iteritems(contents) if funcname.endswith('dll')]
    #
    missing = [chop_dll(func) for func in has_dll if chop_dll(func) not in contents]

    sout_high, sout_legacy = '', ''
    funcs_legacy = 'Function Listing\n----------------\n\n'
    funcs_high = 'Function Listing\n----------------\n\n'
    print(sorted(set(has_dll)))
    for func in sorted(set(has_dll)):
        print('XXXXXXXXXX', func, chop_dll(func))

        # Get remapped name, or the same dll-stripped name back again otherwise
        func = name_remapping.get(chop_dll(func), chop_dll(func))
        if func is None:
            print('skipping deprecated function:', func)
            continue

        # Format the output
        something_outputted = False

        # Skip missing functions
        if func in missing:
            print('skipping missing function:', func)
            continue

        info = deconstruct_function_info(contents[func].split('\n'))
        print(func, info.__dict__)

        args_string = ''
        if func+'dll' in function_dict:
            args = function_dict[func+'dll']['argument_list']
            for arg in args:
                # arg is (name, type, length) or (name, type)
                docs = None
                inout = ''
                argname = arg[0].lower()
                # Nasty workaround...
                if argname == 'hunitsarray' and func+'dll' == 'ALLPROPSdll':
                    argname = 'hUnits'
                    docs = "String with units. Will also contain error messages when necessary. The string will be empty if iFlag=0."
                    inout = '[out]'
                else:
                    if argname in info.in_args:
                        inout = ' [in]'
                        docs = info.in_args[argname]
                    if argname in info.out_args:
                        inout = ' [out]'
                        docs = info.out_args[argname]
                    if docs is None:
                        badx = 'XXXXXXXXXX'
                        docs = badx
                        if func+'dll' in fallback_arguments:
                            # Get docs from fallback(s)
                            fb_names = fallback_arguments[func+'dll']
                            if not isinstance(fb_names, list):
                                fb_names = [fb_names]

                            for fb_name in fb_names:
                                fallinfo = deconstruct_function_info(contents[fb_name].split('\n'))

                                if argname in fallinfo.in_args:
                                    inout = ' [in]'
                                    docs = fallinfo.in_args[argname]
                                if argname in fallinfo.out_args:
                                    inout = ' [out]'
                                    docs = fallinfo.out_args[argname]

                                if docs != badx:
                                    break

                                # print(func, argname, docs, fallinfo.in_args)

                        elif func+'dll' in FLSH_funcs:
                            if argname.upper() in FLSH_args:
                                docs = FLSH_args[argname.upper()]
                                if argname.upper() in func[0:2] or argname.upper() in FLSH_other_input_args:
                                    inout = ' [in]'
                                else:
                                    inout = ' [out]'

                        # print(func, argname, docs, fallinfo.in_args)

                size = ''
                if len(arg) == 3 and int(arg[2]) > 0:
                    size = '(' + str(arg[2]) + ')'
                # print(argname)

                name = arg[0].strip()
                if arg[0] == 'hUnitsArray' and func+'dll' == 'ALLPROPSdll':
                    name = 'hUnits'
                args_string += ' '*4 + ':p {type:s} {name:s}{size:s}{inout:s}: {docs:s}\n'.format(name = name, type = arg[1].strip('*').strip(), size =size, inout = inout, docs= docs)

            if dll_functions:
                for arg in function_dict[func+'dll']['string_arguments']:
                    args_string += ' '*4 + ':p int ' + arg[0] + ': length of variable ``' + arg[0].replace('_length','') + '`` (default: '+str(arg[1])+')\n'
        else:
            print('Cannot find function arguments for:', func+'dll')
            continue

        flags_string = ''
        if info.in_flags or info.out_flags:
            flags_string = ' '*4 + ':Flags: \n\n'
            #if info.out_flags: raise ValueError('IMPOSSIBLE:'+str(info.out_flags))
            def spit_out_flags(flags):
                s = ''
                for flag,data in six.iteritems(flags):
                    s += ' '*8 + '``' + flag + '`` flags\n\n'
                    for k,v in six.iteritems(data):
                        s += ' '*8 + ':' + k + ': ' + v + '\n'
                    s += '\n'
                return s

            flags_string += spit_out_flags(info.in_flags)
            flags_string += spit_out_flags(info.out_flags)

        sout = ''
        # This is the definition of the function prototype
        theargs = ', '.join([a[0] if not (func+'dll'=='ALLPROPSdll' and a[0] == 'hUnitsArray') else 'hUnits' for a in function_dict[func+'dll']['argument_list']])
        # Add on the arguments at the end with the string lengths if you are documenting the DLL
        if dll_functions:
            theargs += ', ' + ', '.join([a[0] for a in function_dict[func+'dll']['string_arguments']])
        sout += '.. f:subroutine:: {func:s} ({args:s})\n\n'.format(func=func+'dll', args = theargs)

        # The block of documentation
        sout += info.doc_block#.replace('*','\*')

        # The list of arguments to the function
        sout += '\n' + args_string + '\n'

        # The list of flags to the function
        sout += '\n' + flags_string + '\n'

        if func+'dll' in High_level_functions:
            sout_high += sout
            funcs_high += '- :f:func:`' + func+'dll' + '`\n'
        else:
            sout_legacy += sout
            funcs_legacy += '- :f:func:`' + func+'dll' + '`\n'

    funcs_high += '\n\nFunction Documentation\n----------------------\n'
    funcs_legacy += '\n\nFunction Documentation\n----------------------\n'

    return (High_Level_Header.format(datetime=time.strftime("%d %b %Y %H:%M:%S", time.localtime())) + funcs_high + sout_high,
           Legacy_Header.format(datetime=time.strftime("%d %b %Y %H:%M:%S", time.localtime())) + funcs_legacy + sout_legacy)

if __name__=='__main__':
    # This path is hardcoded, change as needed
    FOR_path = 'FORTRAN'

    # Use the script in REFPROP-headers repo to generate a dictionary of function parameter data
    # from the functions defined in the PASS_FTN.FOR file
    # ------------------------------------------------------------------------------------------
    sys.path.append('../externals/REFPROP-headers')
    import generate_header
    generate_header.generate_interface_file(os.path.join(FOR_path,'PASS_FTN.FOR'), 'REFPROP.pyf')
    function_dict = generate_header.generate_function_dict('REFPROP.pyf')
    # Write to file for debugging if desired/needed:
    with open('functions.json','w') as fp: fp.write(json.dumps(function_dict, indent =2))

    # Parse the .FOR files and extract docs; write to joined.json file
    # ----------------------------------------------------------------
    objects = generate_manual_content(FOR_path, JSON_ofname = 'joined.json')

    # print(objects['ALLPROPS0'])
    # print(deconstruct_function_info(objects['ALLPROPS0'].split('\n')).__dict__)
    # sys.exit()

    # Generate the RST string
    # -----------------------
    rst_high, rst_legacy = parse_manual_contents(objects, function_dict, True)

    # Write RST bits to file
    # ----------------------
    docs_path = os.path.join('sphinx')
    for fname, rst in [('high_level.rst',rst_high),('legacy.rst',rst_legacy)]:
        rst_file = os.path.join(docs_path, fname)
        with open(rst_file, 'w') as fp:
            fp.write(rst)
        this_dir = os.path.dirname(__file__)
        with open(os.path.join(this_dir, '..', 'doc', 'DLL', fname), 'w') as fp:
            fp.write(rst)

    import subprocess
    for i in range(3):
        try:
            subprocess.check_call('activate py36 && make html', cwd='sphinx', shell = True, stdout = sys.stdout, stderr = sys.stderr)
            break
        except:
            continue
    for i in range(3):
        try:
            subprocess.call('activate py36 && make latex', cwd='sphinx', shell = True, stdout = sys.stdout, stderr = sys.stderr)
            break
        except:
            continue
    for i in range(3):
        subprocess.call('pdflatex REFPROP.tex', cwd='sphinx/_build/latex', shell = True, stdout = sys.stdout, stderr = sys.stderr)


import json
import unittest

from embedded_jubatus import Anomaly
from jubatus.anomaly.types import IdWithScore
from jubatus.common import Datum
import numpy as np

CONFIG = {
    'method': 'lof',
    'parameter': {
        'nearest_neighbor_num': 3,
        'reverse_nearest_neighbor_num': 5,
        'method': 'lsh',
        'parameter': {
            'hash_num': 512,
        }
    },
    'converter': {
        'num_filter_types': {},
        'num_filter_rules': [],
        'string_filter_types': {},
        'string_filter_rules': [],
        'num_types': {},
        'num_rules': [
            {'key': '*', 'type': 'num'}
        ],
        'string_types': {},
        'string_rules': [
            {'key': '*', 'type': 'space',
             'sample_weight': 'bin', 'global_weight': 'bin'}
        ]
    },
}

class TestAnomaly(unittest.TestCase):
    def test_invalid_configs(self):
        self.assertRaises(TypeError, Anomaly)
        self.assertRaises(ValueError, Anomaly, {})
        self.assertRaises(TypeError, Anomaly, {'method': 'hoge'})
        self.assertRaises(RuntimeError, Anomaly,
                          {'method': 'hoge', 'converter': {}})
        invalid_config = dict(CONFIG)
        invalid_config['method'] = 'hoge'
        self.assertRaises(RuntimeError, Anomaly, invalid_config)

    def test(self):
        x = Anomaly(CONFIG)
        self.assertEqual(float('inf'), x.add(Datum({'x': 0.1})).score)
        self.assertTrue(isinstance(x.add(Datum({'x': 0.101})), IdWithScore))
        x.add(Datum({'x': 0.1001}))
        x.calc_score(Datum({'x': 0.1001}))
        self.assertEqual(set(['0', '1', '2']), set(x.get_all_rows()))

        model = x.save_bytes()
        x.clear()
        self.assertEqual([], x.get_all_rows())

        x = Anomaly(CONFIG)
        x.load_bytes(model)
        self.assertEqual(set(['0', '1', '2']), set(x.get_all_rows()))
        self.assertEqual(CONFIG, json.loads(x.get_config()))

        p = x.add(Datum({'x': 0.2}))
        self.assertEqual(set(['0', '1', '2', '3']), set(x.get_all_rows()))
        self.assertEqual(p.score, x.update(p.id, Datum({'x': 0.2})))
        self.assertEqual(p.score, x.overwrite(p.id, Datum({'x': 0.2})))

        st = x.get_status()
        self.assertTrue(isinstance(st, dict))
        self.assertEqual(len(st), 1)
        self.assertEqual(list(st.keys())[0], 'embedded')
        self.assertTrue(isinstance(st['embedded'], dict))

    def test_add_bulk(self):
        x = Anomaly(CONFIG)
        data = [
            Datum({'x': 0.0999}),
            Datum({'x': 0.1}),
            Datum({'x': -0.1009}),
            Datum({'x': -0.101}),
            Datum({'x': 0.1011}),
        ]
        ret = x.add_bulk(data)
        self.assertEqual(['0', '1', '2', '3', '4'], ret)
        self.assertEqual(set(ret), set(x.get_all_rows()))

        x = Anomaly(CONFIG)
        x.fit(np.array([[d.num_values[0][1]] for d in data]))
        self.assertEqual(['0', '1', '2', '3', '4'], ret)
        self.assertEqual(set(ret), set(x.get_all_rows()))


import codecs
import io
import json
import os
from pathlib import Path
import sys
import threading
from typing import Callable, Dict, Union
import unittest

import filelock

# Test for availability of matplotlib.
# (And remove matplotlib as an iris.tests dependency.)
try:
    import matplotlib

    # Override any user settings e.g. from matplotlibrc file.
    matplotlib.rcdefaults()
    # Set backend *after* rcdefaults, as we don't want that overridden (#3846).
    matplotlib.use("agg")
    # Standardise the figure size across matplotlib versions.
    # This permits matplotlib png image comparison.
    matplotlib.rcParams["figure.figsize"] = [8.0, 6.0]
    import matplotlib.pyplot as plt
except ImportError:
    MPL_AVAILABLE = False
else:
    MPL_AVAILABLE = True

# Whether to display matplotlib output to the screen.
_DISPLAY_FIGURES = False

if MPL_AVAILABLE and "-d" in sys.argv:
    sys.argv.remove("-d")
    plt.switch_backend("tkagg")
    _DISPLAY_FIGURES = True

# Threading non re-entrant blocking lock to ensure thread-safe plotting in the
# GraphicsTestMixin.
_lock = threading.Lock()

#: Default perceptual hash size.
HASH_SIZE = 16
#: Default maximum perceptual hash hamming distance.
HAMMING_DISTANCE = 2
# Prefix for image test results (that aren't yet verified as good to add to
# reference images)
RESULT_PREFIX = "result-"
# Name of the imagerepo json and associated file lock
IMAGE_REPO_DIR = Path(__file__).parents[1] / "results"
IMAGE_REPO_PATH = IMAGE_REPO_DIR / "imagerepo.json"
IMAGE_REPO_LOCK_PATH = IMAGE_REPO_DIR / "imagerepo.lock"

__all__ = [
    "GraphicsTestMixin",
    "MPL_AVAILABLE",
    "RESULT_PREFIX",
    "check_graphic",
    "fully_qualify",
    "generate_repo_from_baselines",
    "get_phash",
    "read_repo_json",
    "repos_equal",
    "skip_plot",
    "write_repo_json",
]

def _output_dir() -> Path:
    test_output_dir = Path(__file__).parents[1] / Path(
        "result_image_comparison"
    )

    if not os.access(test_output_dir, os.W_OK):
        if not os.access(Path("."), os.W_OK):
            raise IOError(
                "Write access to a local disk is required "
                "to run image tests. Run the tests from a "
                "current working directory you have write "
                "access to to avoid this issue."
            )
        else:
            test_output_dir = Path(".") / "iris_image_test_output"

    return test_output_dir

def read_repo_json() -> Dict[str, str]:
    with open(IMAGE_REPO_PATH, "rb") as fi:
        repo: Dict[str, str] = json.load(codecs.getreader("utf-8")(fi))
    return repo

def write_repo_json(data: Dict[str, str]) -> None:
    string_data = {}
    for key, val in data.items():
        string_data[key] = str(val)
    with open(IMAGE_REPO_PATH, "wb") as fout:
        json.dump(
            string_data,
            codecs.getwriter("utf-8")(fout),
            indent=4,
            sort_keys=True,
        )

def repos_equal(repo1: Dict[str, str], repo2: Dict[str, str]) -> bool:
    if sorted(repo1.keys()) != sorted(repo2.keys()):
        return False
    for key, val in repo1.items():
        if str(val) != str(repo2[key]):
            return False
    return True

def get_phash(input: Path) -> str:
    from PIL import Image
    import imagehash

    return imagehash.phash(Image.open(input), hash_size=HASH_SIZE)

def generate_repo_from_baselines(baseline_image_dir: Path) -> Dict[str, str]:
    repo = {}
    for path in baseline_image_dir.iterdir():
        phash = get_phash(path)
        repo[path.stem] = phash
    return repo

def fully_qualify(test_id: str, repo: str) -> Dict[str, str]:
    # If the test_id isn't in the repo as it stands, look for it
    if test_id not in repo:
        test_id_candidates = [x for x in repo.keys() if x.endswith(test_id)]
        if len(test_id_candidates) == 1:
            (test_id,) = test_id_candidates
    return test_id

def check_graphic(test_id: str, results_dir: Union[str, Path]) -> None:
    """
    Check the hash of the current matplotlib figure matches the expected
    image hash for the current graphic test.

    To create missing image test results, set the IRIS_TEST_CREATE_MISSING
    environment variable before running the tests. This will result in new
    and appropriately "<hash>.png" image files being generated in the image
    output directory, and the imagerepo.json file being updated.

    """
    from imagehash import hex_to_hash

    dev_mode = os.environ.get("IRIS_TEST_CREATE_MISSING")

    #: The path where the images generated by the tests should go.
    test_output_dir = _output_dir()
    test_output_dir.mkdir(exist_ok=True)

    # The path where the image matching this test should be saved if necessary
    result_path = test_output_dir / f"{RESULT_PREFIX}{test_id}.png"

    results_dir = Path(results_dir)
    repo = read_repo_json()

    # Check if test_id is fully qualified, if it's not then try to work
    # out what it should be
    test_id = fully_qualify(test_id, repo)

    try:

        def _create_missing(phash: str) -> None:
            output_path = test_output_dir / (test_id + ".png")

            print(f"Creating image file: {output_path}")
            figure.savefig(output_path)

            msg = "Creating imagerepo entry: {} -> {}"
            print(msg.format(test_id, phash))
            # The imagerepo.json file is a critical resource, so ensure
            # thread safe read/write behaviour via platform independent
            # file locking.
            lock = filelock.FileLock(IMAGE_REPO_LOCK_PATH)
            with lock.acquire(timeout=600):
                # Read the file again in case it changed, then edit before
                # releasing lock
                repo = read_repo_json()
                repo[test_id] = phash
                write_repo_json(repo)

        # Calculate the test result perceptual image hash.
        buffer = io.BytesIO()
        figure = plt.gcf()
        figure.savefig(buffer, format="png")
        buffer.seek(0)
        phash = get_phash(buffer)

        if test_id in repo:
            expected = hex_to_hash(repo[test_id])

            # Calculate hamming distance vector for the result hash.
            distance = expected - phash

            if distance > HAMMING_DISTANCE:
                if dev_mode:
                    _create_missing(phash)
                else:
                    figure.savefig(result_path)
                    msg = (
                        "Bad phash {} with hamming distance {} " "for test {}."
                    )
                    msg = msg.format(phash, distance, test_id)
                    if _DISPLAY_FIGURES:
                        emsg = "Image comparison would have failed: {}"
                        print(emsg.format(msg))
                    else:
                        emsg = "Image comparison failed: {}"
                        raise AssertionError(emsg.format(msg))
        else:
            if dev_mode:
                _create_missing(phash)
            else:
                figure.savefig(result_path)
                emsg = "Missing image test result: {}."
                raise AssertionError(emsg.format(test_id))

        if _DISPLAY_FIGURES:
            plt.show()

    finally:
        plt.close()

class GraphicsTestMixin:
    def setUp(self) -> None:
        # Acquire threading non re-entrant blocking lock to ensure
        # thread-safe plotting.
        _lock.acquire()
        # Make sure we have no unclosed plots from previous tests before
        # generating this one.
        if MPL_AVAILABLE:
            plt.close("all")

    def tearDown(self) -> None:
        # If a plotting test bombs out it can leave the current figure
        # in an odd state, so we make sure it's been disposed of.
        if MPL_AVAILABLE:
            plt.close("all")
        # Release the non re-entrant blocking lock.
        _lock.release()

def skip_plot(fn: Callable) -> Callable:
    """
    Decorator to choose whether to run tests, based on the availability of the
    matplotlib library.

    Example usage:
        @skip_plot
        class MyPlotTests(test.GraphicsTest):
            ...

    """
    skip = unittest.skipIf(
        condition=not MPL_AVAILABLE,
        reason="Graphics tests require the matplotlib library.",
    )

    return skip(fn)


# with open('./data.txt', 'r', encoding='utf-8') as rf:
#     data = rf.readlines()
#     users = []
#     for line in data:
#         line = line.strip().split(';')
#         if len(line) == 5:
#             name, lastname = line[0].split(' ')
#             user = {
#                 'name': name,
#                 'lastname': lastname,
#                 'login': line[1],
#                 'pass': line[2],
#                 'tel': f'+{line[3]}',
#                 'accounts': []
#             }
#             users.append(user)
#         else:
#             account = {
#                 'num': int(line[0]),
#                 'balance': int(line[1]),
#                 'currency': ''
#             }

#             if line[0].startswith('8600'):
#                 account['currency'] = 'UZS'
#             elif line[0].startswith('4560'):
#                 account['currency'] = 'USD'
#             elif line[0].startswith('1234'):
#                 account['currency'] = 'EUR'

#             users[-1]['accounts'].append(account)
#     print(users)

with open('./error-data.txt', 'r', encoding='utf-8') as rf:
    with open('./error-log.txt', 'w', encoding='utf-8') as wf:
        data = rf.readlines()
        for i, line in enumerate(data, 1):
            line = line.split(';')
            if line[0].isalpha():
                try:
                    assert line[0].split(' ') == 2
                except AssertionError:
                    wf.write(f"{i}-qatorda ism yoki familiya belgilanmagan\n")

                    #  Hisob haqidagi ma'lumot  to'liq emas
            elif line[0].isnumeric():
                try:
                      assert len(line) < 2
                except AssertionError:
                    wf.write(f"{i}-qatorda hisob haqida ma'lumot to'liq emas\n")

                #  Xato hisob raqami
            elif line[0].isnumeric():
                try:
                       assert len(line[0]) == 16
                except AssertionError:
                     wf.write(f"{i}-qatorda hisob raqami 16 ta raqamdan iborat bo'lishi kerak\n !!")

            # Hisob raqami manfiy yoxud minusda
            elif line[0].isnumeric():
                try:
                     assert float(line[1]) > 0
                except AssertionError:
                     wf.write(f"{i}-qatorda hisob raqami manfiy yoxud minusda\n")

                # Hisobda telefon raqami xato berilgan
            elif len(line) == 5:
                try:
                      assert len(line[3]) >= 12 and line[3].startswith('99888') or line[3].startswith('99899') or line[3].startswith('99895') or line[3].startswith('99894') or line[3].startswith('99893') or line[3].startswith('99891') or line[3].startswith('99890')
                except AssertionError:
                     wf.write(f"{i}-qatorda telefon raqami xato kiritilgan\n")

            #  Qatorlardagi ma'lumot to'liq eas yoki ortiqcha
            elif line[0].isalpha() or line[0].isnumeric():
                try:
                    assert len(line) == 2 or len(line) == 5
                except AssertionError:
                     wf.write(f"{i}-qatorda ma'lumot to'liq emas yoki ortiqcha\n")

            #    Parol xatoligi
            elif len(line) == 5:
                try:
                      assert len(line[2]) > 8
                except AssertionError:
                     wf.write(f"{i}-qatorda kiritilgan paraol kamida 8 belgi yoki harfdan iborat bo'lishi kerak\n")
                #  Hisob raqam xatoligi
            elif line[0].isalnum():
                try:
                     assert line[0].startswith('8600') or line[0].startswith('4500') or line[0].startswith('1234')
                except AssertionError:
                     wf.write(f"{i}-qatorda hisob raqami xato berilgan\n")

        # users = [b
        #     {
        #         'name': 'Elbek',
        #         'lastname': 'Xakimbekov',
        #         'login': 'ekhakimbekov',
        #         'pass': 'password1',
        #         'tel': '+998998887766',
        #         'accounts': [
        #             {
        #                 'num': 8600789045671234,
        #                 'balance': 3120000,
        #                 'currency': 'UZS'
        #             }, {
        #                 'num': 4560334598762345,
        #                 'balance': 1000,
        #                 'currency': 'USD'
        #             }
        #         ]
        #     },
        # ]

        # print(users[0]['accounts'][0]['currency'])


import asyncio
import json
import socket
import sys
import gui
import argparse
import aiofiles
from datetime import datetime
from functools import partial
import tools
import logging
from anyio import create_task_group, ExceptionGroup
from tkinter import messagebox
from async_timeout import timeout

WATCHDOG_TIMEOUT = 60
MAX_RECONNECT_ATTEMPTS = 5
CHECK_CONN_TIMEOUT = 30

watchdog_logger = logging.getLogger('watchdog_logger')

async def save_message(text):

    async with aiofiles.open('history.txt', 'a', encoding='utf-8') as file:
        await file.write(f'[{datetime.now().strftime("%d.%m %H:%M")}] {text}')

async def write_down_account_info(account_info):
    async with aiofiles.open('account.txt', 'w', encoding='utf-8') as file:
        await file.write(account_info)

async def register(reader, writer, sending_queue, messages_queue, status_updates_queue):

    messages_queue.put_nowait('Введите ник, который бы хотели использовать')
    username = await sending_queue.get()
    writer.write(f'{username}\n'.encode())
    await writer.drain()

    response = await reader.readline()
    response_decoded = response.decode()
    logging.debug(response_decoded)
    await write_down_account_info(response_decoded)

    tools.set_username(username, status_updates_queue)
    messages_queue.put_nowait(f'Добро пожаловать, {username}!')
    messages_queue.put_nowait('Ваша информация об аккаунте была записана в account.txt!')

    writer.write('\n'.encode())
    await writer.drain()
    await reader.readline()

async def login(reader, writer, hash, sending_queue, messages_queue, status_updates_queue):

    writer.write(f'{hash}\n'.encode())
    await writer.drain()
    response = await reader.readline()
    response_decoded = response.decode()

    logging.debug(response_decoded)

    if 'null' in response_decoded:
        messagebox.showinfo('Неверный хеш!', 'Неверный хеш, дружище, отправляй ник!')
        await register(reader, writer, sending_queue, messages_queue, status_updates_queue)
        return

    writer.write('\n'.encode())
    await writer.drain()
    await reader.readline()

    username = json.loads(response_decoded)['nickname']
    tools.set_username(username, status_updates_queue)
    messages_queue.put_nowait(f'Добро пожаловать, {username}!')

async def authorize(reader, writer, sending_queue, messages_queue, status_updates_queue, watchdog_queue):

    response = await reader.readline()
    response_decoded = response.decode()
    logging.debug(response_decoded)

    messages_queue.put_nowait('Добро пожаловать в чат майнкрафтера!')
    messages_queue.put_nowait('Есть ли у вас хеш? Если да, то отправьте его, если нет - напишите "нет"')
    watchdog_queue.put_nowait('Prompt before auth')

    while True:
        message = await sending_queue.get()

        if 'нет' == message.lower():
            writer.write('\n'.encode())
            await writer.drain()
            await reader.readline()
            await register(reader, writer, sending_queue, messages_queue, status_updates_queue)
            break
        else:
            await login(reader, writer, message, sending_queue, messages_queue, status_updates_queue)
            break
    watchdog_queue.put_nowait('Authorization done')

async def read_old_messages(messages_queue):

    try:
        async with aiofiles.open('history.txt', 'r', encoding='utf-8') as file:
            data = await file.readlines()

        for line in data:
            messages_queue.put_nowait(line)

    except FileNotFoundError:
        pass

async def write_in_chat(open_writer_socket_function,
                        authorize_function,
                        sending_queue,
                        watchdog_queue,
                        status_updates_queue):

    async with open_writer_socket_function() as streamers:
        reader, writer = streamers

        while True:

            if not tools.AUTHORIZED:
                await authorize_function(reader, writer)
                tools.AUTHORIZED = True
                status_updates_queue.put_nowait(gui.SendingConnectionStateChanged.ESTABLISHED)

            else:

                message = await sending_queue.get()
                message = message.replace('\n', '')
                writer.write(f'{message}\n\n'.encode())
                watchdog_queue.put_nowait('Message sent')
                await writer.drain()
                response = await reader.readline()
                logging.debug(response.decode())

async def read_chat(open_reader_socket_function, messages_queue, status_updates_queue, watchdog_queue):

    status_updates_queue.put_nowait(gui.ReadConnectionStateChanged.ESTABLISHED)

    async with open_reader_socket_function() as streamers:
        reader = streamers[0]

        while True:

            if tools.AUTHORIZED:
                data = await reader.readline()
                data_decoded = data.decode()
                watchdog_queue.put_nowait('New message in chat')
                messages_queue.put_nowait(f'[{datetime.now().strftime("%d.%m %H:%M")}] {data_decoded}')
                await save_message(f'{data_decoded}')

            else:
                await asyncio.sleep(1)

async def watch_for_connection(watchdog_queue):

    while True:
        async with timeout(WATCHDOG_TIMEOUT) as time_out:
            try:
                msg = await watchdog_queue.get()
                watchdog_logger.debug(f'[{datetime.now().strftime("%d.%m %H:%M")}] Connection is alive. {msg}')
            finally:
                if time_out.expired:
                    watchdog_logger.debug(f'[{datetime.now().strftime("%d.%m %H:%M")}] Timeout is elapsed.')
                    raise ConnectionError

async def check_the_connection(open_writer_socket_function, messages_queue, status_updates_queue):

    attempts = 0
    while True:
        async with timeout(CHECK_CONN_TIMEOUT) as time_out:
            try:
                async with open_writer_socket_function() as streamers:

                    status_updates_queue.put_nowait(gui.SendingConnectionStateChanged.ESTABLISHED)
                    status_updates_queue.put_nowait(gui.ReadConnectionStateChanged.ESTABLISHED)

                    reader, writer = streamers
                    writer.write('\n\n'.encode())
                    await writer.drain()
                    await reader.readline()
                    await asyncio.sleep(1)

            except (socket.gaierror, OSError, ExceptionGroup):
                status_updates_queue.put_nowait(gui.SendingConnectionStateChanged.INITIATED)
                status_updates_queue.put_nowait(gui.ReadConnectionStateChanged.INITIATED)
                messages_queue.put_nowait('Соединение нарушено!')
                if attempts < MAX_RECONNECT_ATTEMPTS:
                    messages_queue.put_nowait('Попытка восстановить соединение...')
                    await asyncio.sleep(5)
                    attempts += 1
                else:
                    messages_queue.put_nowait('Невозможно установить соединение!')
                    messagebox.showerror('Ошибка!', 'Соединение с сервером нарушено!')
                    raise RuntimeError('Соединение с сервером нарушено!')
            finally:
                if time_out.expired:
                    raise ConnectionError

async def handle_connection(check_the_connection_function,
                            watch_for_connection_function,
                            read_chat_function,
                            write_in_chat_function,
                            authorize_function,
                            open_reader_socket_function,
                            open_writer_socket_function):

    await save_message('Установлено соединение!\n')

    async with create_task_group() as task_group:
        task_group.start_soon(check_the_connection_function, open_writer_socket_function)
        task_group.start_soon(read_chat_function, open_reader_socket_function)
        task_group.start_soon(write_in_chat_function, open_writer_socket_function, authorize_function)
        task_group.start_soon(watch_for_connection_function)

async def main(args):

    messages_queue = asyncio.Queue()
    sending_queue = asyncio.Queue()
    status_updates_queue = asyncio.Queue()
    watchdog_queue = asyncio.Queue()

    read_chat_function = partial(
        read_chat,
        messages_queue=messages_queue,
        watchdog_queue=watchdog_queue,
        status_updates_queue=status_updates_queue
    )
    write_in_chat_function = partial(
        write_in_chat,
        sending_queue=sending_queue,
        watchdog_queue=watchdog_queue,
        status_updates_queue=status_updates_queue
    )
    authorize_function = partial(
        authorize,
        sending_queue=sending_queue,
        messages_queue=messages_queue,
        status_updates_queue=status_updates_queue,
        watchdog_queue=watchdog_queue
    )
    open_reader_socket_function = partial(
        tools.open_socket,
        host=args.host,
        port=args.reading_port
    )
    open_writer_socket_function = partial(
        tools.open_socket,
        host=args.host,
        port=args.writing_port
    )
    watch_for_connection_function = partial(
        watch_for_connection,
        watchdog_queue=watchdog_queue
    )
    check_the_connection_function = partial(
        check_the_connection,
        messages_queue=messages_queue,
        status_updates_queue=status_updates_queue
    )

    if args.debug:
        logging.basicConfig(level=logging.DEBUG)
    watchdog_logger.setLevel(level=logging.DEBUG)

    await read_old_messages(messages_queue)

    async with create_task_group() as task_group:

        task_group.start_soon(
            gui.draw,
            messages_queue,
            sending_queue,
            status_updates_queue),

        task_group.start_soon(
            handle_connection,
            check_the_connection_function,
            watch_for_connection_function,
            read_chat_function,
            write_in_chat_function,
            authorize_function,
            open_reader_socket_function,
            open_writer_socket_function),

if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    parser.add_argument('--host', help='указать хост', default='minechat.dvmn.org')
    parser.add_argument('--writing_port', type=int, help='указать порт для чтения сообщений из чата', default=5050)
    parser.add_argument('--reading_port', type=int, help='указать порт для отправки сообщений в чат', default=5000)
    parser.add_argument('--debug', action='store_true', help='указать включен/выключен дебаг сообщений в терминал')
    args = parser.parse_args()

    try:
        asyncio.run(main(args))
    except KeyboardInterrupt:
        sys.stderr.write("Чат завершен\n")
    except gui.TkAppClosed:
        sys.stderr.write("Вы вышли из чата\n")


from tkinter import *

from tkinter import messagebox

root = Tk()

variable1 = StringVar(root)
variable2 = StringVar(root)

variable1.set("Select a language")
variable2.set("Select a language")

MORSE_CODE_DICT = { 'A':'.-', 'B':'-...',
					'C':'-.-.', 'D':'-..', 'E':'.',
					'F':'..-.', 'G':'--.', 'H':'....',
					'I':'..', 'J':'.---', 'K':'-.-',
					'L':'.-..', 'M':'--', 'N':'-.',
					'O':'---', 'P':'.--.', 'Q':'--.-',
					'R':'.-.', 'S':'...', 'T':'-',
					'U':'..-', 'V':'...-', 'W':'.--',
					'X':'-..-', 'Y':'-.--', 'Z':'--..',
					'1':'.----', '2':'..---', '3':'...--',
					'4':'....-', '5':'.....', '6':'-....',
					'7':'--...', '8':'---..', '9':'----.',
					'0':'-----', ', ':'--..--', '.':'.-.-.-',
					'?':'..--..', '/':'-..-.', '-':'-....-',
					'(':'-.--.', ')':'-.--.-'}

def clearAll() :
	language1_field.delete(1.0, END)
	language2_field.delete(1.0, END)

def convert() :

	message = language1_field.get("1.0", "end")[:-1]

	if variable1.get() == variable2.get() :

		messagebox.showerror("Can't Be same Language")
		return

	elif variable1.get() == "Eng" and variable2.get() == "Morse" :

		rslt = encrypt(message)

	elif variable1.get() == "Morse" and variable2.get() == "Eng" :

		rslt = decrypt(message)

	else :

		messagebox.showerror("please choose valid language code..")
		return

	language2_field.insert('end -1 chars', rslt)

def encrypt(message):
	cipher = ''
	for letter in message:
		if letter != ' ':
			cipher += MORSE_CODE_DICT[letter] + ' '
		else:
			cipher += ' '

	return cipher

def decrypt(message):

	message += ' '

	decipher = ''
	citext = ''
	for letter in message:

		if (letter != ' '):

			i = 0

			citext += letter

		else:
			i += 1
			if i == 2 :

				decipher += ' '
			else:
				decipher += list(MORSE_CODE_DICT.keys())[
							list(MORSE_CODE_DICT .values()).index(citext)]
				citext = ''

	return decipher

if __name__ == "__main__" :

	root.configure(background = '#0F2E4C')

	root.geometry("400x350")

	root.title("Espyer")

	spacelabel = Label(root, text = '',
							fg = 'black', bg = "#0F2E4C")

	label1 = Label(root, text = "One Language ",
				fg = 'white', bg = '#1C529E')

	label2 = Label(root, text = "From Language",
				fg = 'white', bg = '#1C529E')

	label3 = Label(root, text = "To Language ",
				fg = 'white', bg = '#1C529E')

	label4 = Label(root, text = "Converted Language ",
				fg = 'white', bg = '#1C529E')

	spacelabel.grid(row = 0, column = 1)
	label1.grid(row = 1, column = 0)
	label2.grid(row = 2, column = 0)
	label3.grid(row = 3, column = 0)
	label4.grid(row = 5, column = 0)

	language1_field = Text(root, height = 5, width = 25,
									font = "lucida 13")
	language2_field = Text(root, height = 5, width = 25,
									font = "lucida 13")

	language1_field.grid(row = 1, column = 1, padx = 10)
	language2_field.grid(row = 5, column = 1, padx = 10)

	languageCode_list = ["Eng", "Morse"]

	FromLanguage_option = OptionMenu(root, variable1, *languageCode_list)
	ToLanguage_option = OptionMenu(root, variable2, *languageCode_list)

	FromLanguage_option.grid(row = 2, column = 1, ipadx = 10)
	ToLanguage_option.grid(row = 3, column = 1, ipadx = 10)

	button1 = Button(root, text = "Convert", bg = "#F47E2C", fg = "black",
								command = convert)

	button1.grid(row = 4, column = 1)

	button2 = Button(root, text = "Clear", bg = "#F47E2C",
					fg = "black", command = clearAll)

	button2.grid(row = 6, column = 1)

	root.mainloop()


import wx
import wx.xrc

###########################################################################
## Class SetDefenseSkillsDialog
###########################################################################

class SetDefenseSkillsDialog(wx.Dialog):

    def __init__(self, parent):
        wx.Dialog.__init__(self, parent, id=wx.ID_ANY, title=u"Set Defense Skills", pos=wx.DefaultPosition,
                           size=wx.Size(699, 377), style=wx.DEFAULT_DIALOG_STYLE)

        skills_dict = parent.user_character.calc_skill_total()
        skills = ['']
        for skill, value in skills_dict.items():
            skills.append(skill)

        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        bs_sdsd_main = wx.BoxSizer(wx.VERTICAL)

        self.st_ = wx.StaticText(self, wx.ID_ANY,
                                 u"For MELEE and RANGED DEFENSE, you may use acrobatics, dodging, "
                                 u"or foresight.\n\nFor MENTAL DEFENSE you may use concentration, meditation, "
                                 u"bravery, discipline, religion, conviction, leadership, psychology, "
                                 u"or rulership.\n\nFor VITAL DEFENSE you may use resistance.\n\nSkill with a melee "
                                 u"weapon or unarmed combat applies to MELEE DEFENSE, but not ranged attacks.",
                                 wx.DefaultPosition, wx.DefaultSize, 0)
        self.st_.Wrap(-1)
        self.st_.SetMinSize(wx.Size(-1, 175))

        bs_sdsd_main.Add(self.st_, 0, wx.ALL, 5)

        bs_sdsd_def_skills = wx.BoxSizer(wx.HORIZONTAL)

        sbs_sdsd_melee = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, u"Melee Defense"), wx.VERTICAL)

        c_sdsd_meleeChoices = skills
        self.c_sdsd_melee = wx.Choice(sbs_sdsd_melee.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize,
                                      c_sdsd_meleeChoices, 0)
        self.c_sdsd_melee.SetSelection(0)
        sbs_sdsd_melee.Add(self.c_sdsd_melee, 0, wx.ALL | wx.EXPAND, 5)

        bs_sdsd_def_skills.Add(sbs_sdsd_melee, 1, wx.EXPAND, 5)

        sbs_sdsd_ranged = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, u"Ranged Defense"), wx.VERTICAL)

        c_sdsd_rangedChoices = skills
        self.c_sdsd_ranged = wx.Choice(sbs_sdsd_ranged.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize,
                                       c_sdsd_rangedChoices, 0)
        self.c_sdsd_ranged.SetSelection(0)
        sbs_sdsd_ranged.Add(self.c_sdsd_ranged, 0, wx.ALL | wx.EXPAND, 5)

        bs_sdsd_def_skills.Add(sbs_sdsd_ranged, 1, wx.EXPAND, 5)

        sbs_sdsd_mental = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, u"Mental Defense"), wx.VERTICAL)

        c_sdsd_mentalChoices = skills
        self.c_sdsd_mental = wx.Choice(sbs_sdsd_mental.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize,
                                       c_sdsd_mentalChoices, 0)
        self.c_sdsd_mental.SetSelection(0)
        sbs_sdsd_mental.Add(self.c_sdsd_mental, 0, wx.ALL | wx.EXPAND, 5)

        bs_sdsd_def_skills.Add(sbs_sdsd_mental, 1, wx.EXPAND, 5)

        sbs_sdsd_vital = wx.StaticBoxSizer(wx.StaticBox(self, wx.ID_ANY, u"Vital Defense"), wx.VERTICAL)

        c_sdsd_vitalChoices = skills
        self.c_sdsd_vital = wx.Choice(sbs_sdsd_vital.GetStaticBox(), wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize,
                                      c_sdsd_vitalChoices, 0)
        self.c_sdsd_vital.SetSelection(0)
        sbs_sdsd_vital.Add(self.c_sdsd_vital, 0, wx.ALL | wx.EXPAND, 5)

        bs_sdsd_def_skills.Add(sbs_sdsd_vital, 1, wx.EXPAND, 5)

        bs_sdsd_main.Add(bs_sdsd_def_skills, 1, wx.EXPAND, 5)

        bs_sdsd_buttons = wx.BoxSizer(wx.HORIZONTAL)

        self.b_sdsd_ok = wx.Button(self, wx.ID_ANY, u"OK", wx.DefaultPosition, wx.DefaultSize, 0)
        bs_sdsd_buttons.Add(self.b_sdsd_ok, 0, wx.ALL, 5)

        self.b_sdsd_cancel = wx.Button(self, wx.ID_ANY, u"Cancel", wx.DefaultPosition, wx.DefaultSize, 0)
        bs_sdsd_buttons.Add(self.b_sdsd_cancel, 0, wx.ALL, 5)

        bs_sdsd_main.Add(bs_sdsd_buttons, 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT, 5)

        self.SetSizer(bs_sdsd_main)
        self.Layout()

        self.Centre(wx.BOTH)

        # Connect Events
        self.b_sdsd_ok.Bind(wx.EVT_BUTTON, self.on_ok)
        self.b_sdsd_cancel.Bind(wx.EVT_BUTTON, self.on_cancel)

    def __del__(self):
        pass

        ################################################
        # Additional SetDefenseSkillsDialog init stuff #
        ################################################
        # skills_dict = parent.user_character.calc_skill_total()
        # skills = ['']
        # for skill, value in skills_dict.items():
        #     skills.append(skill)

    def on_ok(self, event):
        self.EndModal(wx.ID_OK)

    def on_cancel(self, event):
        self.EndModal(wx.ID_CANCEL)


import numpy as np

from ..common import radial_average
from ..HeightContainer import UniformTopographyInterface

def autocorrelation_1D(topography):
    r"""
    Compute the one-dimensional height-difference autocorrelation function (ACF).

    For non-periodic surfaces the ACF at distance d is given by:

       .. math::
         :nowrap:

         \begin{equation}
         \begin{split}

          \text{ACF}(d) =& \sum_{i=0}^{n-d-1} \frac{1}{n-d} \frac{1}{2} \left( h_i - h_{i+d} \right)^2 \\

                        =& \frac{1}{2(n-d)} \sum_{i=0}^{n-d-1} \left( h_i^2 + h_{i+d}^2 \right)
                         - \frac{1}{n-d} \sum_{i=0}^{n-d-1} h_i h_{i+d}
          \end{split}
          \end{equation}

    Parameters
    ----------
    topography : :obj:`Topography` or :obj:`UniformLineScan`
        Container storing the uniform topography map

    Returns
    -------
    r : array
        Distances. (Units: length)
    A : array
        Autocorrelation function. (Units: length**2)
    """
    if topography.dim == 2:
        nx, dummy_ny = topography.nb_grid_pts
        sx, dummy_sy = topography.physical_sizes
    else:
        nx, = topography.nb_grid_pts
        sx, = topography.physical_sizes

    if topography.is_periodic:
        # Compute height-height autocorrelation function from a convolution
        # using FFT. This is periodic by nature.
        surface_qy = np.fft.fft(topography.heights(), axis=0)
        C_qy = abs(surface_qy) ** 2  # pylint: disable=invalid-name
        A_xy = np.fft.ifft(C_qy, axis=0).real / nx

        # Convert height-height autocorrelation to height-difference
        # autocorrelation:
        #     <(h(x) - h(x+d))^2>/2 = <h^2(x)> - <h(x)h(x+d)>
        A_xy = A_xy[0] - A_xy

        A = A_xy[:nx // 2]
        A[1:nx // 2] += A_xy[nx - 1:(nx + 1) // 2:-1]
        A /= 2

        r = sx * np.arange(nx // 2) / nx
    else:
        p = topography.heights()

        # Compute height-height autocorrelation function. We need to zero
        # pad the FFT for the nonperiodic case in order to separate images.
        surface_qy = np.fft.fft(p, n=2 * nx - 1, axis=0)
        C_qy = abs(surface_qy) ** 2  # pylint: disable=invalid-name
        A_xy = np.fft.ifft(C_qy, axis=0).real

        # Correction to turn height-height into height-difference
        # autocorrelation:
        #     <(h(x) - h(x+d))^2>_d/2 = <h^2(x)>_d - <h(x)h(x+d)>_d
        # but we need to take care about h_rms^2=<h^2(x)>, which in the
        # nonperiodic case needs to be computed only over a subsection of
        # the surface. This is because the average < >_d now depends on d,
        # which determines the number of data points that are actually
        # included into the computation of <h(x)h(x+d)>_d. h_rms^2 needs to
        # be computed over the same data points.
        p_sq = p**2
        A0_xy = (p_sq.cumsum(axis=0)[::-1] + p_sq[::-1].cumsum(axis=0)[::-1])/2

        # Convert height-height autocorrelation to height-difference
        # autocorrelation
        A = ((A0_xy - A_xy[:nx]).T / (nx - np.arange(nx))).T

        r = sx * np.arange(nx) / nx

    if topography.dim == 2:
        return r, A.mean(axis=1)
    else:
        return r, A

def autocorrelation_2D(topography, nbins=100, return_map=False):
    """
    Compute height-difference autocorrelation function and radial average.

    Parameters
    ----------
    topography : :obj:`Topography`
        Container storing the (two-dimensional) topography map.
    nbins : int
        Number of bins for radial average. Note: Returned array can be smaller
        than this because bins without data point are discarded.
    return_map : bool, optional
        Return full 2D autocorrelation map. (Default: False)

    Returns
    -------
    r : array
        Distances. (Units: length)
    A : array
        Autocorrelation function. (Units: length**2)
    A_xy : array
        2D autocorrelation function. Only returned if return_map=True.
        (Units: length**2)
    """
    nx, ny = topography.nb_grid_pts
    sx, sy = topography.physical_sizes

    # Pixel physical_sizes
    area0 = (sx / nx) * (sy / ny)

    # Compute FFT and normalize
    if topography.is_periodic:
        surface_qk = np.fft.fft2(topography[...])
        C_qk = abs(surface_qk) ** 2  # pylint: disable=invalid-name
        A_xy = np.fft.ifft2(C_qk).real / (nx * ny)

        # Convert height-height autocorrelation to height-difference
        # autocorrelation
        A_xy = A_xy[0, 0] - A_xy

        if nbins is None:
            return A_xy

        # Radial average
        r_edges, n, r_val, A_val = radial_average(  # pylint: disable=invalid-name
            A_xy, (sx + sy) / 4, nbins, physical_sizes=(sx, sy))
    else:
        p = topography.heights()

        # Compute height-height autocorrelation function
        surface_qk = np.fft.fft2(p, s=(2 * nx - 1, 2 * ny - 1))
        C_qk = abs(surface_qk) ** 2  # pylint: disable=invalid-name
        A_xy = np.fft.ifft2(C_qk).real

        # Correction to turn height-height into height-difference autocorrelation
        p_sq = p**2
        A0_xy = (p_sq.cumsum(axis=0).cumsum(axis=1)[::-1, ::-1] + \
                 p_sq[::-1, ::-1].cumsum(axis=0).cumsum(axis=1)[::-1, ::-1])/2

        # Convert height-height autocorrelation to height-difference
        # autocorrelation
        A_xy = (A0_xy - A_xy[:nx, :ny]) / ((nx - np.arange(nx)).reshape(-1, 1) * (ny - np.arange(ny)).reshape(1, -1))

        if nbins is None:
            return A_xy

        # Radial average
        r_edges, n, r_val, A_val = radial_average(  # pylint: disable=invalid-name
            A_xy, (sx + sy) / 2, nbins, physical_sizes=(sx, sy), full=False)

    if return_map:
        return r_val[n > 0], A_val[n > 0], A_xy
    else:
        return r_val[n > 0], A_val[n > 0]

### Register analysis functions from this module

UniformTopographyInterface.register_function('autocorrelation_1D', autocorrelation_1D)
UniformTopographyInterface.register_function('autocorrelation_2D', autocorrelation_2D)


from turtle import Turtle

class StatesPointer(Turtle):
    def __init__(self):
        super().__init__()
        self.hideturtle()
        self.color("black")
        self.penup()

    def coordinated(self, state_name, position):
        self.setposition(position)
        self.write(state_name, False, align="center", font=("Courier", 8, "normal"))


import os
import bisect
import shutil
from pathlib import Path
from typing import List, Dict, Set
from torch.utils.data import ConcatDataset
from torchvision.datasets import ImageFolder

class DomainFolder(ConcatDataset):
    """A generic multi-domain data loader where the images are arranged in this way by default: ::

        root/domain1/dog/xxx.png
        root/domain1/dog/xxy.png
        root/domain1/dog/[...]/xxz.png

        root/domain1/cat/123.png
        root/domain1/cat/nsdf3.png
        root/domain1/cat/[...]/asd932_.png

        root/domain2/dog/xxx.png
        root/domain2/dog/xxy.png
        root/domain2/dog/[...]/xxz.png

        root/domain2/cat/123.png
        root/domain2/cat/nsdf3.png
        root/domain2/cat/[...]/asd932_.png

    Args:
        root (string): Root directory path.
        domains (set): Domains to be loaded this time.
        splits (set): Splits to be loaded this time, e.g. 'train', 'val', 'test'.
        transform (callable, optional): A function/transform that  takes in an PIL image
            and returns a transformed version. E.g, ``transforms.RandomCrop``
        target_transform (callable, optional): A function/transform that takes in the
            target and transforms it.
        download (bool, optional): If true, downloads the dataset from the internet and
            puts it in root directory. If dataset is already downloaded, it is not
            downloaded again.
    """

    root: str
    domains: List
    all_domains: Dict
    domain_to_idx: Dict
    splits: List
    all_splits: Dict
    classes: List
    class_to_idx: Dict
    dataset_size: Dict

    def __init__(self, root: str, domains: Set, splits: Set, transform=None, target_transform=None, download=False):

        self.root = os.path.abspath(os.path.expanduser(root))
        self.domains = sorted(domains)
        # keep train val test order
        self.splits = [split for split in ['train', 'val', 'test'] if split in splits]

        self.check_valid_args()

        if download:
            print('process data...')
            self.download_data()
            print('Down!')

        dataset = []
        for domain in self.domains:
            for split in self.splits:
                data = ImageFolder(root=os.path.join(self.root, self.all_domains[domain], self.all_splits[split]),
                                   transform=transform,
                                   target_transform=target_transform)
                if len(data) != self.dataset_size[domain][split]:
                    raise ValueError(f'The size of {self.__class__.__name__}.{domain}.{split} is incorrect, '
                                     f'maybe some images lost, please set download to "True" to '
                                     f'reprocess the dataset.')
                dataset.append(data)

        self.classes = dataset[0].classes
        self.class_to_idx = dataset[0].class_to_idx
        self.domain_to_idx = {domain_name: i for i, domain_name in enumerate(self.domains)}

        super(DomainFolder, self).__init__(dataset)

        self.check_valid_dataset()

    def download_data(self):
        raise NotImplementedError

    def __getitem__(self, idx):
        return super(DomainFolder, self).__getitem__(idx) + self._get_domain(idx)

    def _get_domain(self, idx):
        if idx < 0:
            if -idx > len(self):
                raise ValueError("absolute value of index should not exceed dataset length")
            idx = len(self) + idx
        return (self.domain_to_idx[self.domains[bisect.bisect_right(self.cumulative_sizes, idx) // len(self.splits)]],)

    def check_valid_args(self):
        for split in self.splits:
            assert split in self.all_splits
        for domain in self.domains:
            assert domain in self.all_domains

    def check_valid_dataset(self):
        for data in self.datasets:
            assert self.classes == data.classes
            assert self.class_to_idx == data.class_to_idx

    def _parse_split(self, split, split_file, raw_folder, domain_folder):
        with open(split_file, 'r') as f:
            lines = f.readlines()
            for line in lines:
                line = line.strip()
                image_path = line.split(' ')[0]
                raw_path = Path(raw_folder, image_path)
                dist_path = Path(domain_folder, self.all_splits[split], image_path.split('/')[1])
                image_name = image_path.split('/')[2]
                Path(dist_path).mkdir(exist_ok=True, parents=True)
                shutil.move(raw_path, Path(dist_path, image_name))

    @property
    def num_classes(self):
        return len(self.classes)


### pyspark_logr_prediction
from pyspark.ml import PipelineModel

test_df = read("FreddieMac_Spark.PySpark_TestingData")
# load logr pipeline model
lr_pipeline_model = PipelineModel.load("/incorta/IncortaAnalytics/Tenants/ebs_cloud/incorta.ml/models"+ "/logr-pipeline-model2")

# predict
predictions = lr_pipeline_model.transform(test_df) # can work
df_output = predictions.select("seq_num", "label", "predictedLabel", "probability")
df_output.show(5)
save(df_output)

### check performance
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc, classification_report, confusion_matrix
from pyspark.ml.evaluation import MulticlassClassificationEvaluator, BinaryClassificationEvaluator
from pyspark.mllib.evaluation import BinaryClassificationMetrics
# Accuracy
evaluator = MulticlassClassificationEvaluator(labelCol="indexedLabel", predictionCol="prediction", metricName="accuracy")
accuracy = evaluator.evaluate(predictions)
print("Accuracy = %f" % accuracy)

# AUC
lr_eval = BinaryClassificationEvaluator(rawPredictionCol="probability", labelCol="indexedLabel")
lr_AUC  = lr_eval.evaluate(predictions)
print("AUC = %.2f" % lr_AUC)

# confusion matrix
# method 1
y_true = predictions.select(['label']).collect()
y_pred = predictions.select(['predictedLabel']).collect()
print("Confusion matrix:")
print(classification_report(y_true, y_pred))

# method 2
y_true = predictions.select("label")
y_true = y_true.toPandas()
y_pred = predictions.select("predictedLabel")
y_pred = y_pred.toPandas()
cnf_matrix = confusion_matrix(y_true, y_pred,labels=['delinquent', 'not_delinquent'])
cnf_matrix

# method 3
cm_lr_result = predictions.crosstab("predictedLabel", "label")
cm_lr_result = cm_lr_result.toPandas()
cm_lr_result

TP = float(cm_lr_result.iat[0,1])
FP = float(cm_lr_result.iat[0,2])
TN = float(cm_lr_result.iat[1,2])
FN = float(cm_lr_result.iat[1,1])
Accuracy = (TP+TN)/(TP+FP+TN+FN)
Recall = TP/(TP+FN)
Specificity = TN/(TN+FP)
Precision = TP/(TP+FP)
F1 = (2*Precision*Recall) / (Precision+Recall)

print ("Accuracy = %0.2f" %Accuracy )
print ("Recall = %0.2f" %Recall )
print ("Specificity = %0.2f" %Specificity )
print ("Precision = %0.2f" %Precision )
print("F1 score = %0.2f" %F1)

# ROC Grafik
# Create ROC grafik from lr_result
PredAndLabels           = predictions.select("probability", "indexedLabel")
PredAndLabels_collect   = PredAndLabels.collect()
PredAndLabels_list      = [(float(i[0][0]), 1.0-float(i[1])) for i in PredAndLabels_collect]
PredAndLabels           = sc.parallelize(PredAndLabels_list)
metrics = BinaryClassificationMetrics(PredAndLabels)
# Visualization ROC curve
FPR = dict()                     # FPR: False Positive Rate
tpr = dict()                     # TPR: True Positive Rate
roc_auc = dict()

y_test = [i[1] for i in PredAndLabels_list]
y_score = [i[0] for i in PredAndLabels_list]

fpr, tpr, _ = roc_curve(y_test, y_score)
roc_auc = auc(fpr, tpr)

plt.figure(figsize=(5,4))
plt.plot(fpr, tpr, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('ROC Curve - Logistic Regression')
plt.legend(loc="lower right")
plt.show()


import logging
import zlib

import requests

from .utils import bson_utils as json_util, utils

MAX_PULL_TIME = 1800
SLEEP_PULL_TIME = 5
REQUEST_CONNECT_TIMEOUT = 20
REQUEST_READ_TIMEOUT = 180

class RiverySession(object):
    """
    Support class to work with the Rivery API
    """

    CONNECTION_TYPES = set()

    def __init__(self, *args, **kwargs):
        self.session = requests.session()
        self.access_token = kwargs.get('token') or kwargs.get('access_token')
        print(f'Host: {kwargs.get("host")}')
        self.account_id = None
        self.env_id = None
        self.host = kwargs.get("host") + "/api"

    def __repr__(self):
        return f"<RiverySession host:{self.host}>"

    def __str__(self):
        return f"<RiverySession host:{self.host}>"

    @property
    def headers(self):
        return {"Authorization": f'Bearer {self.access_token}'}

    def connect(self):
        """ Make a connection test """
        url = '/me'
        resp = self.handle_request(url=url)
        self.account_id = resp.get('account_id')
        self.env_id = resp.get('environment_id')

    @property
    def account(self):
        """ Set the account id in cli for the session, as come from the token """
        return self.account_id

    @property
    def environment_id(self):
        return self.env_id

    def send_request(self, url, method=None, params=None, headers=None, data=None, **kwargs):
        logging.debug("Send request started")
        logging.debug(f"sending {method} request to {url} with params {params}, headers: {headers} and data: {data}")
        headers.update(self.headers)
        try:
            timeout = (REQUEST_CONNECT_TIMEOUT, REQUEST_READ_TIMEOUT)
            if data:
                data = zlib.compress(json_util.dumps(data).encode("utf-8")) if headers.get("Content-Encoding",
                                                                                "") == "gzip" else \
                    json_util.dumps(data)
            if method.lower() == "post":
                response = self.session.post(url=url, params=params, timeout=timeout, data=data, headers=headers)
                return response

            if method.lower() == "get":
                response = self.session.get(url=url, params=params, headers=headers, timeout=timeout)
                return response

            if method.lower() == "delete":
                response = self.session.delete(url=url, params=params, data=data, headers=headers, timeout=timeout)
                return response

            if method.lower() == "patch":
                response = self.session.patch(url=url, data=data, params=params, headers=headers, timeout=timeout)
                return response

            if method.lower() == "put":
                response = self.session.put(url=url, data=data, params=params, headers=headers, timeout=timeout)
                return response

        except Exception as e:
            logging.error("Got an error from the API with: {}".format(str(e)))
            raise e

    def handle_request(self, url, method='get', params=None, headers=None, **kwargs):
        if headers is None:
            headers = {}
        logging.debug('handle_request started')

        resp = self.send_request(url=self.host + url, method=method, params=params, headers=headers, **kwargs)
        if resp.ok:
            if kwargs.get("return_full_response", False):
                return resp
            else:
                try:
                    return json_util.loads(resp.content)
                except Exception as e:
                    raise requests.HTTPError("Failed")

        elif not resp.ok and resp.content:
            try:
                error_msg = json_util.loads(resp.content)
            except Exception as e:
                error_msg = resp.content
                pass
            logging.error("Error from Rivery API: {}-{}".format(resp.status_code, error_msg))
            if isinstance(error_msg, dict):
                error_msg = error_msg.get("message", "")
            if 400 <= resp.status_code < 500:
                raise Exception(
                    "Permissions Error in Rivery API "
                    "Please check your credentials and permissions. API Error: {}".format(error_msg))
            elif resp.status_code >= 500:
                raise requests.HTTPError("Internal server error, "
                                         "see following error and try again later. API Error: {}".format(error_msg))
            else:
                raise Exception(
                    "Unknown error from Rivery API")
        else:
            logging.error("Received an error from Rivery API")
            raise Exception("Received an error from Rivery API")

    def list_rivers(self, **params):
        """ List the rivers """
        url_ = '/rivers'
        river_id = params.pop('river_id', None)
        if river_id:
            url_ = f'/rivers/{river_id}'
        return self.handle_request(url=url_, method='get', params=params)

    def get_river(self, **kwargs):
        """ Get specific river data """
        url = '/rivers/list'
        data = {"_id": kwargs.get('river_id') or kwargs.get('_id')}
        method = 'post'
        return self.handle_request(url=url, data=data, method=method)

    def get_connection(self, **kwargs):
        """ Get specific connection. required `_id` as the connection id"""
        url = f'/connections/{kwargs.get("_id")}'
        method = 'get'
        return self.handle_request(url=url, method=method)

    def list_connections(self, **kwargs):
        """ Get list of the availabe connection in this environment/account.
            The function can get "connection_type" parameter, which will filter
            the connections returns by connection type.
        """
        connection_type = kwargs.get('connection_type')
        url = "/connections/list"
        method = 'get'

        if not self.CONNECTION_TYPES:
            self.list_connection_types()

        if connection_type:
            if connection_type not in self.CONNECTION_TYPES:
                raise AssertionError(f'Invalid Connection Type: {connection_type}')

            url = f'/connections/{connection_type}'

        return self.handle_request(url=url, method=method)

    def list_connection_types(self):
        """ list the connection types, and populates the CONNECTION_TYPES parameter"""
        url = '/connection_types'
        resp = self.handle_request(url=url)
        self.CONNECTION_TYPES = {
            c.get('connection_type') for c in resp
        }
        return resp

    def get_connection_type_properties(self, connection_type):
        if connection_type not in self.CONNECTION_TYPES:
            return {}

        url = f'/connection_types/{connection_type}'
        return self.handle_request(url=url)

    def save_river(self, **kwargs):
        """ Save a new river, or update one
            :param create_new: Force new river with the specification of the data.
            :param river_definition: The River's definition
            :param files_to_upload: A list of files to upload to S3 (code scripts for Logic steps)
        """
        data = kwargs.get('data', {})

        payload = {"river_definitions": data.get("river_definitions"),
                   "tasks_definitions": data.get("tasks_definitions")}
        url = "/rivers/modify"
        if kwargs.get("create_new", False) or not data.get('cross_id'):
            logging.debug('Creating New River: {}({})'.format(
                data.get('river_definitions', {}).get('river_name'), data.get('cross_id')))
            method = "put"
        else:
            method = "patch"
            logging.debug('Checking out if the river {}({}) exists in the account and environment'.format(
                data.get('river_definitions', {}).get('river_name'), data.get('cross_id')
            ))
            exists = self.handle_request(url='/rivers/list', data={"_id": data.get('cross_id')},
                                         method='post')
            if not exists:
                logging.debug('river {}({}) does not exist. Create it. '.format(
                    data.get('river_definitions', {}).get('river_name'), data.get('cross_id')
                ))
                method = 'put'
            else:
                data['_id'] = exists.get('_id')
                data['cross_id'] = exists.get('cross_id')
                if not data.get('cross_id'):
                    raise RuntimeError('Please provide cross_id and cross_id to update river')
                existing_tasks = exists.get('tasks_definitions', [])
                for idx_, t in enumerate(payload.get('tasks_definitions', [])):
                    task_ = existing_tasks[idx_:idx_ + 1]
                    if task_:
                        payload['tasks_definitions'][idx_] = utils.recursive_update(task_[0], t)
                    else:
                        payload['tasks_definitions'][idx_] = t

                # Check if the river already exist by the id or not
            payload.update({"cross_id": data.get("cross_id"),
                            "_id": data.get("_id")})

        files_to_upload = kwargs.get('files_to_upload')
        if files_to_upload:
            logging.debug("Uploading all code script to S3")
            for file in files_to_upload:
                for file_name, full_file_path in file.items():
                    self.upload_file_to_pre_signed_url(python_file_name=file_name, full_file_path=full_file_path)

        logging.debug(
            'Saving River {}({}). Creating New? {}'.format(data.get('river_definitions', {}).get('river_name'),
                                                           data.get('cross_id'),
                                                           True if method == 'put' else False))
        return self.handle_request(url=url, method=method, data=payload)

    def save_connection(self, **kwargs):
        """ Save a connection in Rivery """
        create_new = kwargs.pop('create_new', True)
        if create_new:
            self.create_connection(**kwargs)
        else:
            self.create_connection(**kwargs)

    def save_river_group(self, **kwargs):
        """ Create new river group """
        data = kwargs.get("data")
        url = "/river_groups"
        method = "put"
        return self.handle_request(url=url, method=method, data=data)

    def update_river_group(self, **kwargs):
        """ Update a river group """
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/river_groups"
        method = "patch"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def create_connection(self, **kwargs):
        """ Save new connection """
        data = kwargs.get("data")
        url = "/connections/create/data"
        method = "put"
        return self.handle_request(url=url, method=method, data=data)

    def update_connection(self, **kwargs):
        """ Update connection """
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/connections"
        method = "patch"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def delete_connection(self, **kwargs):
        """ Delete Connection """
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/connections"
        method = "delete"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def update_variable(self, **kwargs):
        """ Update Variable in the system """
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/environments/update_variable"
        method = "patch"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def pull_request(self, **kwargs):
        """ Run pull request mechanism """
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/pull/" + kwargs.get("url", "")
        method = "put" or kwargs.get("method", "put")
        return self.handle_request(url=url, method=method, data=data, params=params)

    def check_pull_request(self, **kwargs):
        """ Check pull request response """
        data = {}
        params = {"id": kwargs.get("id")}
        url = "/pull"
        method = "get"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def snapshot_versions_by_deploy(self, **kwargs):
        data = kwargs.get("data")
        params = kwargs.get("params")
        path_params = kwargs.get("path_params", [])
        url = ("/rivers/versions/snapshot/" if kwargs.get("is_river", True) else "/river_groups/versions/snapshot/") + \
              "/".join(path_params)
        method = "post"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def delete_river(self, **kwargs):
        """ Delete a river"""
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/rivers/modify"
        method = "delete"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def delete_group(self, **kwargs):
        """ Delete a group """
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/river_groups"
        method = "delete"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def restore_snapshot(self, **kwargs):
        """ restore snnapshot """
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/rivers/restore"
        method = "post"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def restore_snapshot_river_groups(self, **kwargs):
        data = kwargs.get("data")
        params = kwargs.get("params")
        url = "/river_groups/version/restore"
        method = "post"
        return self.handle_request(url=url, method=method, data=data, params=params)

    def cancel_run(self, **kwargs):
        """ Cancel specific run """
        data = kwargs.get("data")
        url = "/run/cancel"
        method = "post"
        return self.handle_request(url=url, method=method, data=data)

    def run_river(self, **kwargs):
        river_id = kwargs.get('river_id')
        url = '/run'
        method = 'post'
        data = {"river_id": river_id}
        return self.handle_request(url=url, method=method, data=data)

    def check_run(self, **kwargs):
        run_id = kwargs.get('run_id')
        url = '/check_run'
        method = 'get'
        param = {"run_id": run_id}
        return self.handle_request(url=url, method=method, params=param)

    def fetch_run_logs(self, **kwargs):
        return_full_response = kwargs.get('return_full_response')
        run_id = kwargs.get('run_id')
        url = '/activities/runs/logs'
        method = 'get'
        param = {"id": run_id}

        # Add query id if exists
        query_id = kwargs.get('query_id')
        if query_id:
            param["queryId"] = query_id

        response = self.handle_request(url=url, method=method, params=param,
                                       return_full_response=return_full_response)
        return response

    @staticmethod
    def _dumps(obj, **kwargs):
        """ Dumping an object to json using the json utils """
        return json_util.dumps(obj, **kwargs)

    @staticmethod
    def _dump(f_obj, obj, **kwargs):
        """ Dumping to file using json utils"""
        f_obj.write(json_util.dumps(obj, **kwargs))

    @staticmethod
    def _loads(stream, **kwargs):
        """ Loads a stream to json using json utils"""
        return json_util.loads(stream, **kwargs)

    @staticmethod
    def _load(f_obj, **kwargs):
        """Load from file using json util"""
        stream = f_obj.read()
        if stream:
            obj = json_util.loads(stream, **kwargs)
        else:
            obj = {}
        return obj

    def object_hook(self, dct):
        """ Update ObjectId Object Hook for requesting and responding """
        newdct = {}
        for k, v in dct.items():
            if (isinstance(v, str) or isinstance(v, bytes)) and len(v) == 12:
                newdct[k] = json_util.convert_oid(v)
            else:
                newdct[k] = v
        return newdct

    def download_file_by_file_id(self, file_id, file_path):
        """ Downloading the file from Rivery """
        # Get the actual path from project.yaml

        logging.debug(f'Downloading python script to: {file_path}')
        url_ = f'/logicode/download_file/{file_id}'

        try:
            downloaded_file = self.handle_request(url=url_, method='get', return_full_response=True)

            with open(file_path, "wb") as file:
                file.write(downloaded_file.content)
        except Exception as e:
            raise Exception(f'Failed to download python script to: {file_path}. Error: {e}')

    def get_file_presigned_url(self, file_name):
        """ Downloading the file from Rivery """

        url_ = f'/files/upload_presigned/file'
        data = {"file_name": file_name}

        return self.handle_request(url=url_, method='post', data=data)

    def upload_file_to_pre_signed_url(self, python_file_name: str, full_file_path: str) -> str:
        """ Uploading a file to a presigned url """

        response = self.get_file_presigned_url(python_file_name)
        presigned_url = response.get('presigned_url')
        if not presigned_url:
            raise Exception("Internal error. Please contact support.")

        logging.debug(f"Uploading file: {full_file_path} to URL: {presigned_url}")
        try:
            file = open(full_file_path, 'rb').read()
            requests.put(presigned_url, files={python_file_name: file})
        except Exception as e:
            raise Exception(f"Internal error while uploading python script. Please contact support. Error: {e}")

        cross_id = response.get('cross_id')
        return cross_id