import pygame
from lib import utils
import config
from platform import PlatformManager

class GameObject(object):
    def __init__(self, pos, screenwidth, screenheight, displacement):
        self.rotation_vector = 0
        self.rotation = 0
        self.speed = 0
        self.position = pos
        self.displacement = displacement
        self.resize(screenwidth, screenheight)
        self.screenwidth = screenwidth
        self.screenheight = screenheight
        self.is_dead = False

class StarObject(GameObject):
    def __init__(self, images, pos, screenwidth, screenheight, displacement):
        self.images = []
        for image in images:
            self.images.append(pygame.image.load(config.IMAGE_ROOT + image))
        self.image_offset = 0
        self.framems = 80
        self.imagems = 0
        self.width = self.images[0].get_size()[0]
        self.height = self.images[0].get_size()[1]
        super(StarObject, self).__init__(pos, screenwidth, screenheight, displacement)

    def isdead(self):
        return self.is_dead

    def move(self, newpos, dt):
        #animate by switching images
        x,y = newpos
        if x < self.width / 2:
            x = self.width / 2
        if x > config.GAME_WIDTH - (self.width / 2):
            x = config.GAME_WIDTH - (self.width / 2)
        if y <  self.displacement - self.height:
            self.is_dead = True
        # if we are moving left, then start rotating left.
        # if we are moving right, start rotating right.
        if (self.position[0] < x): # we are moving right
            self.rotation_vector -= 0.01 * dt
        elif (self.position[0] > x): # we're moving left
            self.rotation_vector += 0.01 * dt
        else:
            #move vector back toward 0.
            if self.rotation_vector > 0:
                self.rotation_vector = max(0, self.rotation_vector - 0.05 * dt)
            else:
                self.rotation_vector = min(0, self.rotation_vector + 0.05 * dt)
        self.position = (x, y)
        return self.position

    def update(self, surf, displacement, dt):
        self.rotation += (dt / 5.0 * self.rotation_vector)
        self.imagems += dt
        while self.imagems > self.framems:
            self.image_offset = (self.image_offset + 1) % len(self.images)
            self.imagems -= self.framems
            self.resize(surf.get_size()[0], surf.get_size()[1])

        self.displacement = displacement
        self.rotated_image = utils.rot_center(self.resized_image, self.rotation)
        drawpos = self.getpos(surf.get_size())
        #self.rotated.center = self.resized_image.get_rect().center
        surf.blit(self.rotated_image, drawpos)

    def get_bottomleft(self):
        return self.position[0] - self.width / 2, self.position[1]
    def get_bottomright(self):
        return self.position[0] + self.width / 2, self.position[1]

    def resize(self, screenwidth, screenheight):
        heightratio = float(screenwidth) / config.GAME_HEIGHT
        widthratio = float(screenheight) / config.GAME_WIDTH
        img = self.images[self.image_offset]
        self.resized_image = utils.aspect_scale(img, (img.get_size()[0] * widthratio, img.get_size()[1] * heightratio))
        self.resized_image.convert()

    def getpos(self, screensize):
        #bottom of image is y, center of bottom of image is x.
        drawpos = utils.get_screen_coords(self.position, screensize, self.displacement)
        drawpos = drawpos[0] - self.resized_image.get_size()[0]/2, drawpos[1] - self.resized_image.get_size()[1]
        return drawpos

    def getscreenrect(self, screensize):
        drawpos = self.getpos(screensize)
        return pygame.rect.Rect(drawpos[0], drawpos[1], self.resized_image.get_size()[0], self.resized_image.get_size()[1]).inflate(30, 30)

class PlatformObject(GameObject):
    def __init__(self, manager, is_dark, pos, unitwidth, screenwidth, screenheight, displacement):
        self.is_dark = is_dark
        #TODO: set width and height and load image
        self.platform_manager = manager
        self.image = self.platform_manager.getplatformimage(unitwidth, self.is_dark)
        self.width = self.image.get_size()[0]
        self.height = self.image.get_size()[1]
        self.unitwidth = unitwidth
        super(PlatformObject, self).__init__(pos, screenwidth, screenheight, displacement)

    def is_star_colliding(self, bottomleft, bottomright):
        #only collide with a light platform.
        if not self.is_dark:
            #TODO: make this collide better
            if self.position[1] - 30 < bottomleft[1] < self.position[1] + 30 and \
                bottomright[0] >= self.position[0] and \
                bottomleft[0] <= self.position[0] + self.width:
                return True
        return False

    #TODO: implement this
    def is_onscreen(self, displacement):
        return True

    def toggle_dark(self):
        self.is_dark = not self.is_dark
        self.image = self.platform_manager.getplatformimage(self.unitwidth, self.is_dark)
        self.resize(self.screenwidth, self.screenheight)

    def update(self, surf, displacement, dt):
        self.displacement = displacement
        drawpos = self.getpos(surf.get_size())
        surf.blit(self.resized_image, drawpos)

    def resize(self, screenwidth, screenheight):
        heightratio = float(screenwidth) / config.GAME_HEIGHT
        widthratio = float(screenheight) / config.GAME_WIDTH
        self.resized_image = utils.aspect_scale(self.image, (self.image.get_size()[0] * widthratio, self.image.get_size()[1] * heightratio))
        self.resized_image.convert_alpha()
        self.screenwidth = screenwidth
        self.screenheight = screenheight

    def get_top(self):
        return self.position[1]

    def getpos(self, screensize):
        drawpos = utils.get_screen_coords(self.position, screensize, self.displacement)
        return drawpos

    def getscreenrect(self, screensize):
        drawpos = self.getpos(screensize)
        return pygame.rect.Rect(drawpos[0], drawpos[1], self.resized_image.get_size()[0], self.resized_image.get_size()[1]).inflate(30, 30)


import logging
from resilient_circuits import ResilientComponent, function, handler, StatusMessage, FunctionResult, FunctionError
from resilient_lib import validate_fields, RequestsCommon, ResultPayload
from fn_cisco_enforcement.lib.enforcement_common import SECTION_NAME, HEADERS, callback

# Deletes a domain using the Cisco api. The apikey is refernced in the app.config under [fn_cisco_enforcement]
class FunctionComponent(ResilientComponent):
    """Component that implements Resilient function 'delete_domain"""

    def __init__(self, opts):
        """constructor provides access to the configuration options"""
        super(FunctionComponent, self).__init__(opts)
        self.opts = opts
        self.options = opts.get(SECTION_NAME, {})
        self.log = logging.getLogger(__name__)

        self._init()

    @handler("reload")
    def _reload(self, event, opts):
        """Configuration options have changed, save new values"""
        self.opts = opts
        self.options = opts.get(SECTION_NAME, {})

        self._init()

    def _init(self):
        validate_fields(['api_token'], self.options)

        """get the api token for cisco access"""
        self.apikey = self.options.get('api_token')

    @function("cisco_delete_domain")
    def _delete_domain_function(self, event, *args, **kwargs):
        """Function: This is a function implementation that uses the Cisco API to delete a domain from the shared customer’s domain list."""
        try:
            validate_fields(['cisco_domain'], kwargs)

            # Get the function parameters:
            cisco_domain = kwargs.get("cisco_domain")  # text

            self.log.info(u'Deleting {} from list'.format(cisco_domain))
            rp = ResultPayload(SECTION_NAME, **kwargs)

            url = '/'.join((self.options['url'], 'domains', '{}?customerKey={}'))
            url = url.format(cisco_domain.strip(), self.apikey)
            self.log.debug(url)

            rc = RequestsCommon(self.opts, self.options)
            content, msg = rc.execute_call_v2("delete", url, callback=callback)
            if msg:
                yield StatusMessage(msg)
            else:
                yield StatusMessage(u"Delete domain for '{}' was successful".format(cisco_domain))

            # Return the results
            results = rp.done(False if msg else True, None if msg else content, msg)
            # backward compatibility
            results['value'] = None if msg else content
            yield FunctionResult(results)
        except Exception as err:
            self.log.error(err)
            yield FunctionError()


import tensorflow as tf
import numpy as np
import os
img_width = 224
img_height = 224

def get_file(file_dir):
    images = []
    temp = []
    for root, sub_folders, files in os.walk(file_dir):
        for name in files:
            images.append(os.path.join(root, name))
        for name in sub_folders:
            temp.append(os.path.join(root, name))
    labels = []
    for one_folder in temp:
        n_img = len(os.listdir(one_folder))
        letter = one_folder.split('\\')[-1]
        if letter == 'cat':
            labels = np.append(labels, n_img * [0])
        else:
            labels = np.append(labels, n_img * [1])
    # shuffle
    temp = np.array([images, labels])
    temp = temp.transpose()
    np.random.shuffle(temp)
    image_list = list(temp[:, 0])
    label_list = list(temp[:, 1])
    label_list = [int(float(i)) for i in label_list]

    return image_list, label_list

def get_batch(image_list, label_list,img_width,img_height,batch_size,capacity):
    image = tf.cast(image_list,tf.string)
    label = tf.cast(label_list,tf.int32)

    input_queue = tf.train.slice_input_producer([image,label])

    label = input_queue[1]
    image_contents = tf.read_file(input_queue[0])
    image = tf.image.decode_jpeg(image_contents,channels=3)

    image = tf.image.resize_image_with_crop_or_pad(image,img_width,img_height)
    # image = tf.image.per_image_standardization(image) #将图片标准化
    image_batch,label_batch = tf.train.batch([image,label],batch_size=batch_size,num_threads=64,capacity=capacity)
    label_batch = tf.reshape(label_batch,[batch_size])

    return image_batch,label_batch

imdir = '/home/xiajun/dev/alg_verify/FasterRCNN_Instrument/images'
namelist = os.listdir(imdir)
image_list = []
label_list = []
for name in namelist:
    imagefile = os.path.join(imdir, name)
    image_list.append(imagefile)
    label_list.append(0)

image_batch, label_batch = get_batch(image_list, label_list, img_width, img_height, 25, 50)
x_imgs = tf.placeholder(tf.float32, [None, img_width, img_height, 3])
y_imgs = tf.placeholder(tf.int32, [None, 2])

sess = tf.Session()
sess.run(tf.global_variables_initializer())
# vgg.load_weights('../vgg16_weights_and_classes/vgg16_weights.npz',sess)
# saver = vgg.saver()

coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord,sess=sess)

import time
import cv2
start_time = time.time()

for i in range(100):
    image, label = sess.run([image_batch, label_batch])
    count = 0
    for im in image:
        cv2.imwrite(str(count) + '.jpg', im)
        count += 1
    # labels = onehot(label)

    # sess.run(optimizer, feed_dict={x_imgs: image, y_imgs: labels})
    # loss_record = sess.run(loss, feed_dict={x_imgs: image, y_imgs: labels})
    print("now the loss is %f " % loss_record)
    end_time = time.time()
    print('time: ', (end_time - start_time))
    start_time = end_time
    print("----------epoch %d is finished---------------" % i)

saver.save(sess,".\\vgg_finetuning_model\\")
print("Optimization Finished!")
coord.request_stop()
coord.join(threads)

print('debug')


from django.urls import path

from . import views

app_name = 'books'

urlpatterns = [
    path('', views.ManageBookView.as_view(), name='manage_book'),
    path('add/', views.AddBookView.as_view(), name='add_book'),
    path('edit/<int:pk>', views.EditBookView.as_view(), name='edit_book'),
    path('delete/<int:pk>', views.deleteBook, name='delete_book'),
]


import argparse
from pathlib import Path
from hydra import initialize_config_dir, compose

def parse_args():
    parser = argparse.ArgumentParser("Classifire")
    parser.add_argument("--data_source", type=str)
    parser.add_argument(
        "--log_dir", type=str, default="logs/experiments/runs/default/2022-11-01_16-54-20"
    )
    return parser.parse_args()

def main():
    from src.predict_pipline import predict

    args = parse_args()
    data_source = Path(args.data_source)
    log_dir = Path(args.log_dir)
    with initialize_config_dir(
        version_base="1.1", config_dir=str(log_dir.joinpath("config").absolute()), job_name="app"
    ):
        cfg = compose(
            config_name="config",
            return_hydra_config=True,
            overrides=["original_work_dir=${hydra.runtime.cwd}"],
        )
        predict(config=cfg, log_dir=log_dir, data_source=data_source)

if __name__ == "__main__":
    main()


from django import forms
from .models import Recipe

class RecipeForm(forms.ModelForm):
    class Meta:
        model = Recipe
        fields = (
                    'title', 'source', 'contributor',
                    'serves', 'prep_time', 'cook_time',
                    'ingredient_list', 'ingredient_list', 'instructions',
                    'meal_type', 'dish_type'
                    )

class UrlRecipeForm(forms.Form):
    url = forms.CharField(label = 'url', max_length = 200)
    contributor = forms.CharField(label = 'your name', max_length = 50)


import torch
import torch.nn as nn
import torch.nn.functional as F

from typing import Callable, Tuple, Union, List

# TODO: Need better system for determining what nodes are illegal to add
# example usage get_illegal_set(tree:SyntaxNode) -> set{'var','const',...}

class SyntaxNode(object):
    # stored op properties in class attribute
    n_args = {
        "+": 2,
        "-": 2,
        "*": 2,
        "/": 2,
        #"^": 2,
        "sin": 1,
        "cos": 1,
        "exp": 1,
        "log": 1,
        "var": 0,
        "const": 0,
        "start": 1,
        "none": 0}

    op_list = {
        "+": torch.add,
        "-": torch.subtract,
        "*": torch.multiply,
        "/": torch.divide,
        #"^": torch.pow,
        "sin": torch.sin,
        "cos": torch.cos,
        "exp": torch.exp,
        "log": torch.log,
        "var": None,
        "const": torch.rand,
        "start": lambda x: x,
        "none": None}

    illegal = {
        '+': set(),
        '-': set(),
        '*': set(),
        '/': {'/'},
        #'^': ['exp', 'log'],
        'sin': {'sin', 'cos', 'exp', 'log'},
        'cos': {'sin', 'cos', 'exp', 'log'},
        'exp': {'sin', 'cos', 'exp', 'log'},
        'log': {'sin', 'cos', 'exp', 'log'},
        'var': set(),
        'const': set(),
        'start': {'var','const'},
        'none': set()}

    # TODO: Probably a better way to track parameters, potentially a memory leak
    parameters = {}

    instance_counter = 0

    def __init__(self, op: str, parent:'SyntaxNode' = None, data:torch.tensor = None):
        self.left = None
        self.right = None
        self.tree_idx = None
        self.parent = parent
        self.data = data
        assert op in SyntaxNode.op_list.keys()
        self.value = op
        self.illegal = SyntaxNode.illegal[self.value]

        # operation, number of arguments
        self.op = SyntaxNode.op_list[op]
        self.n_args = SyntaxNode.n_args[op]

        # update parameters
        if self.value == 'start':
            SyntaxNode.instance_counter += 1
            self.tree_idx = SyntaxNode.instance_counter
            SyntaxNode.parameters[self.tree_idx] = []
        elif self.value == 'const':
            self.tree_idx = self.parent.tree_idx
            self.op = self.op(1, requires_grad =True)
            SyntaxNode.parameters[self.tree_idx].append(self.op)
        else:
            self.tree_idx = self.parent.tree_idx

    def __bool__(self):
        return True

    def __del__(self):
        if self.value == 'start':
            if self.tree_idx in SyntaxNode.parameters.keys():
                #print(f'deleting {self.tree_idx} from param keys: {SyntaxNode.parameters.keys()}')
                del SyntaxNode.parameters[self.tree_idx]

    def get_embedding(self, type_idx: int) -> torch.tensor:
        return F.one_hot(torch.tensor(type_idx), len(SyntaxNode.op_list.keys())).view(1, -1).float()

    def add_node(self, node:'SyntaxNode') -> bool:
        if self.n_args != 0:
            if self.left == None:
                self.left = node
                return True
            elif (self.n_args != 1) and (self.right == None):
                self.right = node
                return True
            else:
                return False
        else:
            return False

    def from_preorder(self, node_list: list) -> list:
        if self.n_args == 2:
            self.left = SyntaxNode(node_list.pop(0), self)
            node_list = self.left.from_preorder(node_list)
            self.right = SyntaxNode(node_list.pop(0), self)
            return self.right.from_preorder(node_list)
        elif self.n_args == 1:
            self.left = SyntaxNode(node_list.pop(0), self)
            return self.left.from_preorder(node_list)
        else:
            return node_list

    def get_function(self, X: torch.Tensor) -> Callable:
        if self.n_args == 1:
            return self.op(self.left.get_function(X))
        elif self.n_args == 2:
            return self.op(self.left.get_function(X),
                           self.right.get_function(X))
        else:
            if (self.op != None):
                return self.op
            else:
                return X

    def get_preorder(self) -> list:
        traversal = [self.value]
        if self.left != None:
            traversal += self.left.get_preorder()
        if self.right != None:
            traversal += self.right.get_preorder()
        return traversal

    def get_leaf_nodes(self) -> list:
        leaf_list = []
        if self.left is None and self.right is None:
            leaf_list.append(self)
        else:
            leaf_list += self.left.get_leaf_nodes()
            if self.right is not None:
                leaf_list += self.right.get_leaf_nodes()
        return leaf_list

    def get_last(self):
        if self.n_args == 2:
            if self.left != None:
                res = self.left.get_last()
                if res:
                    return res
            else:
                return self
            if self.right != None:
                res = self.right.get_last()
                if res:
                    return res
                else:
                    return False
            else:
                return self
        elif self.n_args == 1:
            if self.left != None:
                return self.left.get_last()
            else:
                return self
        else:
            return False

    def get_parent_state(self) -> torch.tensor:
        parent = self.get_last()
        return parent.data

    def get_sibling_token(self) -> torch.tensor:
        parent = self.get_last()
        if parent.n_args == 2:
            if parent.left == None:
                return self.get_embedding(list(SyntaxNode.op_list.keys()).index('none'))
            else:
                return self.get_embedding(list(SyntaxNode.op_list.keys()).index(parent.left.value))
        else:
            return self.get_embedding(list(SyntaxNode.op_list.keys()).index('none'))

    def get_sibling(self):
        parent = self.get_last()
        if parent.n_args == 2:
            if parent.left == None:
                return None
            else:
                return parent.left
        else:
            return None

    def append(self, node_type:str, data:torch.tensor = None) -> bool:
        last_parent = self.get_last()
        return last_parent.add_node(SyntaxNode(node_type, parent=last_parent, data=data))

def __get_tree_depth(root:SyntaxNode) -> int:
    if root == None:
        return 0
    left_depth = __get_tree_depth(root.left)
    right_depth = __get_tree_depth(root.right)
    return 1 + max(left_depth, right_depth)

def get_tree_depth(root:SyntaxNode) -> int:
    return __get_tree_depth(root) - 2

def tree_from_preorder(preorder:list) -> SyntaxNode:
    root = SyntaxNode(preorder.pop(0))
    root.from_preorder(preorder)
    return root

def get_expression(root:SyntaxNode) -> str:
    # TODO: Fix this implementation, doesn't work properly with incomplete expressions
    if root.value != 'start':
        if root.left == None and root.right == None:
            if (root.value != 'const') and (root.value != 'var'):
                return root.value
            elif root.value == 'var':
                return 'x'
            else:
                return str(round(root.op.item(),3))
        elif root.right == None:
            return root.value + '(' + get_expression(root.left) + ')'
        else:
            return '('+ get_expression(root.left) + root.value + get_expression(root.right) + ')'
    else:
        return get_expression(root.left)

def get_expression_refactor(root:SyntaxNode) -> str:
    if root != None:
        if root.n_args == 2:
            return '( {} {} {} )'.format(get_expression_refactor(root.left), root.value, get_expression_refactor(root.right))
        elif root.n_args == 1:
            return root.value + f'( {get_expression_refactor(root.left)} )'
        else:
            if root.value == 'var':
                return 'x'
            elif root.value == 'const':
                return str(round(root.op.item(),3))
            else:
                return '?'
    else:
        return '?'

def tree_complete(root: SyntaxNode) -> bool:
    ''' Test to see if tree is complete'''
    if root.n_args == 2:
        if root.left == None:
            return False
        elif root.right == None:
            return False
        else:
            return tree_complete(root.left) and tree_complete(root.right)
    elif root.n_args == 1:
        if root.left == None:
            return False
        else:
            return tree_complete(root.left)
    else:
        return True

def get_node_depth(node: SyntaxNode, counter = 0) -> int:
    if node.value != 'start':
        return get_node_depth(node.parent, counter+1)
    else:
        return counter

def child_of(node: SyntaxNode, nodetypes: set) -> bool:
    if node.value == 'start':
        return False
    elif node.value in nodetypes:
        return True
    else:
        return child_of(node.parent, nodetypes)

def get_illegal_set(root: SyntaxNode) -> set:
    parent = root.get_last()
    sibling = root.get_sibling()
    # copying the set is important, otherwise we modify the illegal sets for
    # each node globally
    illegal_nodes = SyntaxNode.illegal[parent.value].copy()
    if parent.value in {'+', '-', '/'}:
        if sibling != None:
            if sibling.value in {'const', 'var'}:
                illegal_nodes.add(sibling.value)
    if parent.value == '*':
        if sibling != None:
            if sibling.value in {'const', 'log', 'exp'}:
                illegal_nodes.add(sibling.value)
    if child_of(parent, {'sin', 'cos', 'log', 'exp'}):
        illegal_nodes |= {'sin', 'cos', 'log', 'exp'}
        if parent.value in {'sin', 'cos', 'log', 'exp'}:
            illegal_nodes.add('const')
    return illegal_nodes

if __name__ == '__main__':
    print('reconstruction test:')
    root2 = SyntaxNode("start")
    assert root2.from_preorder(['exp','+','*','const','var','const']) == []
    print(get_expression(root2))

    print('Last node test:')
    print('const + exp(?)')
    preorder = ['start','+','const','exp']
    tree = SyntaxNode(preorder.pop(0))
    _ = [tree.append(node) for node in preorder]
    print(tree.get_last().op)

    print("Non-empty list test:")
    root3 = SyntaxNode("start")
    l = root3.from_preorder(['exp','+','*','const','var','const'])
    print("l:", l)
    print("root3:", get_expression(root3))

    print("Leaf nodes test:")
    leafs = root3.get_leaf_nodes()
    for l in leafs:
        print(l.value, l.n_args)

    print("Parameter Tracking Test:")
    root2.__del__()
    root3.__del__()
    tree.__del__()
    root4 = SyntaxNode("start")
    root4.from_preorder(['+','*','const','var','const'])
    print(SyntaxNode.parameters)
    print(SyntaxNode.parameters.keys())

    print("Fit test")
    root4.__del__()
    root = SyntaxNode('start')
    root.from_preorder(['exp', '+','*','const','var','const'])
    print("Initial Expression:")
    print(get_expression(root))
    print("Target Expression: exp(2.5*x + 6.34)")
    #_ = [param.cuda() for param in SyntaxNode.parameters[root.tree_idx]]
    func_optim = torch.optim.Adam(SyntaxNode.parameters[root.tree_idx], .1)
    def func(x):
        return torch.exp(2.5*x + 6.34)
    X = torch.rand((1,20)) #.cuda()
    y = func(X)
    for step in range(1000):
        func_optim.zero_grad()
        y_hat = root.get_function(X)
        func_loss = torch.mean((y_hat - y)**2)
        func_loss.backward()
        if step % 100 == 0:
            print(func_loss.item())
        func_optim.step()
    print("Fit Expression:")
    print(get_expression(root))

    print("Append Test:")
    root.__del__()
    root = SyntaxNode('start')
    root.append('exp')
    root.append('+')
    root.append('*')
    root.append('const')
    root.append('var')
    root.append('const')
    print(get_expression(root))

    print("Complete tree test")
    root.__del__()
    root = SyntaxNode('start')
    root.append('-')
    root.append('log')
    root.append('const')
    leafs = root.get_leaf_nodes()
    for l in leafs:
        print(l.value, l.n_args)
    print(get_expression(root))
    print(tree_complete(root))

    print("Illegal set test:")
    root.__del__()
    root = SyntaxNode('start')
    preorder = ['exp', '+', '*', 'var', 'const']
    for op in preorder:
        root.append(op)
        print(get_expression_refactor(root))
        print(get_illegal_set(root))

    print("Child of Test:")
    root.__del__()
    root = SyntaxNode('start')
    root.append('exp')
    root.append('+')
    root.append('*')
    root.append('const')
    root.append('var')
    print(root.get_last().value)
    print(root.get_last().parent.value)
    print(child_of(root.get_last(), {'exp'}))

    root.__del__()
    root = SyntaxNode('start')
    root.append('+')
    print(root.get_last().value)
    print(get_illegal_set(root))

    print("Tree depth test:")
    root.__del__()
    root = SyntaxNode('start')
    root.from_preorder(['exp', '+', '*', 'const', 'var', 'const'])
    print(get_tree_depth(root))


# Built-in modules.
import json

# Third-party modules.
import requests
import numpy
import cv2

# My modules.
import const

class FaceApiClient:

    FACE_API_BASE_URL = 'https://japaneast.api.cognitive.microsoft.com/face/v1.0'  # noqa: E501

    @classmethod
    def detect_mat(cls, mat: numpy.ndarray) -> dict:

        # mat をバイナリに変換します。
        encode_succeeded, buffer = cv2.imencode('.png', mat)
        bytes_image = buffer.tobytes()

        # detection を行います。
        return cls.detect(bytes_image)

    @classmethod
    def detect(cls, bytes_image: bytes) -> dict:

        url = f'{cls.FACE_API_BASE_URL}/detect'
        params = {
            'recognitionModel': 'recognition_02',
        }
        headers = {
            'Content-Type': 'application/octet-stream',
            'Ocp-Apim-Subscription-Key':
                const.AZURE_COGNITIVE_SERVICES_SUBSCRIPTION_KEY,
        }
        response = requests.post(url=url,
                                 params=params,
                                 headers=headers,
                                 data=bytes_image)
        return response.json()

    @classmethod
    def identify(cls, person_group_id: str, face_ids: list) -> dict:

        url = f'{cls.FACE_API_BASE_URL}/identify'
        headers = {
            'Content-Type': 'application/json',
            'Ocp-Apim-Subscription-Key':
                const.AZURE_COGNITIVE_SERVICES_SUBSCRIPTION_KEY,
        }
        # NOTE: payload は積載物って意味。
        payload = {
            'personGroupId': person_group_id,
            'faceIds': face_ids,
            'maxNumOfCandidatesReturned': 1,
            'confidenceThreshold': .65,
        }
        response = requests.post(url=url,
                                 headers=headers,
                                 data=json.dumps(payload))
        return response.json()


"""
Given an array of integers nums containing n + 1 integers where each integer is in the range [1, n] inclusive.

There is only one repeated number in nums, return this repeated number.
"""
from typing import List

class Solution:
    """
    Using hash to track elements

    Runtime: 60 ms, faster than 91.09% of Python3
    Memory Usage: 18.3 MB, less than 16.38% of Python3

    Time and Space complexity: O(n)
    """

    def findDuplicate(self, nums: List[int]) -> int:
        seen = set()
        for n in nums:
            if n in seen:
                return n
            seen.add(n)

class Solution2:
    """
    Some sort of bitwise magic

    Runtime: 80 ms, faster than 27.16% of Python3
    Memory Usage: 16.6 MB, less than 78.03% of Python3

     O(n) time and O(1) space
    """

    def findDuplicate(self, nums: List[int]) -> int:
        bit_mask = 1
        for n in nums:
            if bit_mask >> n & 1:
                return n
            bit_mask |= 1 << n

if __name__ == '__main__':
    solutions = [Solution(), Solution2()]
    tc = (
        ([1, 3, 4, 2, 2], 2),
        ([3, 1, 3, 4, 2], 3),
        ([1, 1], 1),
        ([1, 1, 2], 1),
        ([2, 2, 2, 2, 2], 2),
    )
    for s in solutions:
        for inp, exp in tc:
            res = s.findDuplicate(inp)
            assert res == exp, f"{s.__class__.__name__}: for input {inp} expected {exp}, got {res}"


import penman
import re
from penman.graph import Graph
def get_deep_amr(amr):
    t = penman.parse(amr)
    var, branches = t.node
    branches = branches[1:]
    if len(branches) == 1 and len(branches[0][1]) ==1:
        return 2
    if len(branches) == 0:
        return 1
    deep = 0
    for branche in branches:
        role, target = branche
        try:
            sub_amr = penman.format(target)
            deep = max(deep, get_deep_amr(sub_amr) + 1)
        except:
            deep = max(deep, 2)
    return deep

def get_given_deep_amr(amr, Deepth=3):
    indent=3
    amr = penman.decode(amr)
    lines = penman.encode(amr, indent=indent)
    lines = lines.split('\n')
    instances = amr.instances()
    v2name = {}
    for ins in instances:
        v2name[ins[0]] = ins[-1]
    need_lines = []
    deeps = []
    miss_nodes = []
    for line in lines:
        if ':' in line:
            blank = line.split(':')[0]
        else:
            blank = ''
        deep_line = len(blank) // indent
        if deep_line <= Deepth:
            need_lines.append(line)
            deeps.append(deep_line)
        else:
            node = re.findall('\(<.*/', line)
            if len(node):
                node = node[0][1:-1].strip()
                miss_nodes.append(node)
    for idx in range(len(need_lines)):
        now_line = need_lines[idx]
        now_deep = deeps[idx]

        if idx + 1 < len(need_lines):
            next_line = need_lines[idx+1]
            next_deep = deeps[idx+1]
            if now_line.endswith(')') or next_deep > now_deep:
                continue
            if next_deep == now_deep:
                if ' (' in now_line:
                    need_lines[idx] = need_lines[idx] + ' )'
            elif next_deep < now_deep:
                if ' (' in now_line:
                    add_deep = now_deep - next_deep +1
                else:
                    add_deep = now_deep - next_deep
                need_lines[idx] += ')' * add_deep
        else:
            if not now_line.endswith(')'):
                need_lines[idx] += ')' * (now_deep + 1)

    final_lines = []
    for line in need_lines:
        try:
            pointer = re.findall('<pointer-\d+>', line)[0]
        except:
            pointer = "<pointer-never>"
        if pointer in miss_nodes:
            line = line.replace(pointer, '( {} / {} )'.format(pointer, v2name[pointer]))
        final_lines.append(line)

    res_amr = '\n'.join(final_lines)
    return res_amr

def get_all_sub_triples(triples_res, node, all_triples, have_add):
    for triple in all_triples:
        if triple in triples_res:
            continue
        src, rel, tgt = triple
        if src == node:
            triples_res.add(triple)
            if tgt not in have_add and rel != ':instance':
                get_all_sub_triples(triples_res, tgt, all_triples, have_add)
                have_add.add(tgt)

def get_sub_amrs(amr, DEEP=4):
    g = penman.decode(amr)
    all_vars = set()
    for triples in g.triples:
        src, rel, tgt = triples
        if rel == ':instance':
            all_vars.add(src)
    all_amr = []
    for var in all_vars:
        triples_res = set()
        have_add = set()
        get_all_sub_triples(triples_res, var, g.triples, have_add)
        sub_amr  = penman.encode(Graph(triples_res), top=var)
        if get_deep_amr(sub_amr) >= DEEP:
            all_amr.append(sub_amr)
    return all_amr

if __name__ == '__main__':
    amr = """
    (u / underscore-01
    :ARG0 (e / experience-01
             :ARG0 (p / person
                      :wiki "Wang_Shi_(entrepreneur)"
                      :name (n / name
                               :op1 "Wang"
                               :op2 "Shi"))
             :ARG1 (c / condemn-01
                      :ARG0 (p2 / public)
                      :ARG1 p))
    :ARG1 (r / relation-03
             :ARG0 (c3 / class
                       :mod (r2 / rich)
                       :part-of (s / society
                                   :mod (c5 / country
                                            :wiki "China"
                                            :name (n2 / name
                                                      :op1 "China"))))
             :ARG2 (c4 / class
                       :mod (p3 / poor)
                       :part-of s)
             :ARG1-of (t / tense-03))
    :degree (e2 / extent
                :mod (c2 / certain)))
     """
    print(get_given_deep_amr(amr, 4))
    # assert False
    lines = open('../data/amrs/train.txt').readlines()
    amr = ""
    from tqdm import tqdm
    for line in tqdm(lines):
        if "# ::" in line:
            continue
        if line != '\n':
            amr = amr + " " + line
        else:
            if amr == "":
                continue
            for dp in range(1, get_deep_amr(amr)):
                sub_amr = get_given_deep_amr(amr, dp)
                if get_deep_amr(sub_amr) != dp + 1:
                    import ipdb; ipdb.set_trace()
            amr = ""


from datetime import datetime
from datetime import date

# returns todays date
datetime.today()

today = datetime.today()
# datetime object- important because you cant mix these objects
type(today)

todaydate = date.today()
todaydate

# note that when using date, the object type is a date and note a datetime
type(todaydate)

todaydate.month
todaydate.year
todaydate.day

# assigning the date to a variable
christmas = date(2022, 12, 5)

# can see that the type is automatically a timedelta
christmas - todaydate

# using the days attribute of the datetime class returns an integer
(christmas - todaydate).days

if christmas != today:
    print(f'its not christmas yet! there are still {(christmas - todaydate).days} days left')
else:
    print('yay its christmas')


from scraper.utils import read_excel_file
from scraper.items import ScraperItem
from scraper import PROJECT_ROOT_DIR

from urllib.parse import urlencode

import scrapy
import json
import re

class HeadersMiddleware:
    def process_request(self, request, spider):
        headers = {
            "authority": "www.amazon.ae",
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
            "cache-control": "max-age=0",
            "device-memory": "8",
            "downlink": "7.65",
            "dpr": "2",
            "ect": "4g",
            "rtt": "150",
            "sec-ch-device-memory": "8",
            "sec-ch-dpr": "2",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-viewport-width": "865",
            "sec-fetch-dest": "document",
            "sec-fetch-mode": "navigate",
            "sec-fetch-site": "none",
            "sec-fetch-user": "?1",
            "upgrade-insecure-requests": "1",
            "viewport-width": "865",
        }

        request.headers.update(headers)

class AmazonSpider(scrapy.Spider):
    name = "amazon.ae"
    allowed_domains = ["amazon.ae"]
    custom_settings = {
        "CONCURRENT_REQUESTS": 1,
        "DOWNLOAD_DELAY": 10,
        "DOWNLOADER_MIDDLEWARES": {
            "scraper.middlewares.UserAgentMiddleware": 1000,
            HeadersMiddleware: 1100,
        },
    }

    BASE_URL = "https://www.amazon.ae/stores/page/9978F790-7843-44F0-834F-92C086AC4A19/search"
    BASE_URL_PARAMS = {
        "ref_": "ast_bln",
        "terms": "",
    }

    def start_requests(self):
        params = self.BASE_URL_PARAMS.copy()
        df = read_excel_file(filepath=f"{PROJECT_ROOT_DIR}/products.xlsx")
        for item in df[["Product Number", "Product Name EN"]].values.tolist():
            product_number, product_name = item
            params["terms"] = product_number
            print(f"{self.BASE_URL}?{urlencode(params)}",'--=========================')
            yield scrapy.Request(
                url=f"{self.BASE_URL}?{urlencode(params)}",
                callback=self.parse,
                meta={
                    "_product_number": product_number,
                    "_product_name": product_name,
                },
            )

    def parse(self, response):
        products = re.findall(r"products\":(\[.+\"version\":\"2.0\"}]),", response.text)
        products = products[0] if products else "[]"
        products = json.loads(products)

        product = products[0] if products else {}
        buy_options = product.get("buyingOptions")
        buy_option = buy_options[0].get("price", {}) if buy_options else {}

        try:
            discount_price = buy_option.get("priceToPay", {}).get("moneyValueOrRange", {}).get("value", {}).get("amount", 0)
            price = buy_option.get("basisPrice", {}).get("moneyValueOrRange", {}).get("value", {}).get("amount", 0)

            yield ScraperItem(
                product_number=response.meta["_product_number"],
                product_name=response.meta["_product_name"],
                discount_price=discount_price,
                price=price,
            )

        except AttributeError:
            pass


import imp
from celery import shared_task
import requests
import json
from .models import CompanyNew, TicketInterest
from datetime import datetime, timedelta
import pytz
from django.core.mail import send_mail
from email_sender.settings import EMAIL_HOST_USER

@shared_task(name="send_daily")
def send_daily():
    print('started')
    today = datetime.now().replace(hour=0, minute=0,second=0,microsecond=0)
    CompanyNew.objects.filter(datetime_created__lt=today).delete()

    tickets = list(TicketInterest.objects.exclude(users_subscribed=None).prefetch_related('users_subscribed'))
    group_by_tickets={

    }
    news=list(CompanyNew.objects.all())
    for nnew in news:
        if nnew.related in tickets:
            group_by_tickets[nnew.related]=group_by_tickets[nnew.related] if nnew.related in group_by_tickets else []
            group_by_tickets[nnew.related].append(nnew.summary)
    for gt in group_by_tickets:
        users_subscr = list(gt.users_subscribed.all())
        emails = [us.email for us in users_subscr]
        content =group_by_tickets[gt]
        send_mail(
            json.dumps(content[:5]),
            'Summary',
            EMAIL_HOST_USER,
            emails,
            fail_silently=False,
        )


import pygame
from pygame.locals import *
import random
from copy import deepcopy

class GameOfLife:

    def __init__(self, width=640, height=480, cell_size=10, speed=10):
        self.width = width
        self.height = height
        self.cell_size = cell_size

        # Устанавливаем размер окна
        self.screen_size = width, height
        # Создание нового окна
        self.screen = pygame.display.set_mode(self.screen_size)

        # Вычисляем количество ячеек по вертикали и горизонтали
        self.cell_width = self.width // self.cell_size
        self.cell_height = self.height // self.cell_size

        # Скорость протекания игры
        self.speed = speed

    def draw_grid(self):
        """ Отрисовать сетку """
        for x in range(0, self.width, self.cell_size):
            pygame.draw.line(self.screen, pygame.Color('black'),
                             (x, 0), (x, self.height))
        for y in range(0, self.height, self.cell_size):
            pygame.draw.line(self.screen, pygame.Color('black'),
                             (0, y), (self.width, y))

    def run(self):
        """ Запустить игру """
        pygame.init()
        clock = pygame.time.Clock()
        pygame.display.set_caption('Game of Life')
        self.screen.fill(pygame.Color('white'))

        self.clist = self.cell_list(randomize=True)

        running = True
        while running:
            for event in pygame.event.get():
                if event.type == QUIT:
                    running = False

            self.draw_cell_list(self.clist)
            self.clist = self.update_cell_list(self.clist)
            self.draw_grid()

            pygame.display.flip()
            clock.tick(self.speed)
        pygame.quit()

    def cell_list(self, randomize=True):
        self.clist = []
        for i in range(self.cell_height):
            empty = []
            for j in range(self.cell_width):
                empty.append(random.randint(0, 1))
            self.clist.append(empty)
        if not randomize:
            for i in range(self.cell_height):
                for j in range(self.cell_width):
                    self.clist[i][j] = 0
        return self.clist

    def draw_cell_list(self, clist):
        for i in range(self.height // self.cell_size):
            for j in range(self.width // self.cell_size):
                if clist[i][j] == 1:
                    pygame.draw.rect(self.screen, pygame.Color('green'),
                                     (i*self.cell_size+1, j*self.cell_size+1,
                                     self.cell_size - 1, self.cell_size - 1))
                else:
                    pygame.draw.rect(self.screen, pygame.Color('white'),
                                     (i * self.cell_size+1, j*self.cell_size+1,
                                     self.cell_size - 1, self.cell_size - 1))

    def get_neighbours(self, cell):
        neighbours = []
        for i in range(-1, 2):
            for j in range(-1, 2):
                if (i or j) & (0 <= cell[0] + i < self.cell_height)\
                & (0 <= cell[1] + j < self.cell_width):
                    neighbours.append(self.clist[cell[0] + i][cell[1] + j])
        return neighbours

    def update_cell_list(self, cell_list):
        new_list = deepcopy(cell_list)
        for i in range(self.cell_height):
            for j in range(self.cell_width):
                if cell_list[i][j]:
                    if sum(self.get_neighbours((i, j))) in (2, 3):
                        new_list[i][j] = 1
                    else:
                        new_list[i][j] = 0
                else:
                    if sum(self.get_neighbours((i, j))) == 3:
                        new_list[i][j] = 1
                    else:
                        new_list[i][j] = 0
        self.clist = new_list
        return new_list

if __name__ == '__main__':
    game = GameOfLife(601, 601, 20)
    game.run()


# -*- encoding: utf-8 -*-
import odoo.addons.decimal_precision as dp
from dateutil.relativedelta import relativedelta
from odoo import models, fields, api, exceptions, _
from datetime import date, datetime
from odoo.exceptions import Warning

class WizardStatusCuotas(models.TransientModel):
    _name = 'loan.wizard.generar.cuotas'
    _description = 'Asistente de Status de Cuotas'
    _rec_name = 'prestamo_id'

    def _get_prestamo(self):
        contexto = self._context
        if 'active_id' in contexto:
            loan_obj = self.env["loan.management.loan"].browse(contexto['active_id'])
            return loan_obj

    # Información General
    date_generation = fields.Date(string="Fecha de Generación", required=True, default=fields.Date.today)
    prestamo_id = fields.Many2one("loan.management.loan", "Prestamo", default=_get_prestamo)
    lista_prestamos = fields.Many2one("loan.management.loan", "Prestamo Numero")
    @api.multi
    def generar_status_cuotas(self, prestamo_id):
        date_generation = fields.Date.today()
        if self.date_generation:
            date_generation = self.date_generation
        # WR:llave para uno o todos los que cumplen el search, se aumenta el campo de seleccion por prestamo
        # print "prestamo_id=%s " % self.lista_prestamos.id
        # print "si entro con dato prestamo_id   ",prestamo_id
        if prestamo_id:
            # print "voy por uno"
            prestamos_obj = self.env["loan.management.loan"].search([('id', '=', self.lista_prestamos.id)])
        if self.lista_prestamos.id in (False, None):
            # print "voy por todos..."
            prestamos_obj = self.env["loan.management.loan"].search([('state', '=', 'progreso')])
        for prestamo in prestamos_obj:
            for cuota in prestamo.cuota_ids:
                if date_generation > cuota.fecha_pago and not cuota.state == 'pagada' and not cuota.saldo_pendiente == 0.0:
                    fecha_run = (datetime.strptime(date_generation, '%Y-%m-%d'))
                    fecha_cuota = (datetime.strptime(cuota.fecha_pago, '%Y-%m-%d'))
                    diferencia_fecha = (fecha_run - fecha_cuota).days #relativedelta(day=fecha_cuota.day, months=fecha_cuota.month)
                    mora = 0.0
                    if round(cuota.saldo_pendiente, 10) >= round(cuota.monto_cuota, 10):
                        #print "Cuota de prestamo igual a saldo"
                        mora = ((cuota.monto_cuota * (prestamo.mora_id.tasa_mora / 100)) / 30) * diferencia_fecha
                        cuota.saldo_pendiente = cuota.monto_cuota + mora
                        cuota.mora = cuota.saldo_pendiente - cuota.monto_cuota
                    else:
                        mora = ((cuota.saldo_pendiente * (prestamo.mora_id.tasa_mora / 100)) / 30) * diferencia_fecha
                        cuota.saldo_pendiente = cuota.saldo_pendiente + mora
                        cuota.mora = mora
                    cuota.write({'state': 'morosa'})
                if date_generation == cuota.fecha_pago and not cuota.state == 'pagada' and not cuota.saldo_pendiente == 0.0:
                    cuota.write({'state': 'vigente'})
                    cuota.mora = 0.0
                    # evitar sobre escribir cuando se ha pagado parcial en estado no vigente WHRC
                    if round(cuota.saldo_pendiente,2) == round(cuota.monto_cuota,2):
                        cuota.saldo_pendiente = cuota.monto_cuota

class WizardGeneratePlanCuotas(models.TransientModel):
    """DCLS"""
    _name = 'loan.wizard.generar.plan.cuotas'
    _description = 'Asistente Generar Plan Cuotas'

    @api.multi
    def generate_plan_cuotas(self):
        context = dict(self._context or {})
        active_ids = context.get('active_ids', []) or []

        for record in self.env['loan.management.loan'].browse(active_ids):
            if record.state not in ('cotizacion'):
                raise UserError(_("Selected loan(s) cannot be confirmed as they are not in 'Aprobado' state."))

            record.get_generar_cuotas()
        return {'type': 'ir.actions.act_window_close'}

class WizardAprobarPlan(models.TransientModel):
    """DCLS"""
    _name = 'loan.wizard.approve'
    _description = 'Asistente Aprobar Plan Cuotas'

    @api.multi
    def generate_approve(self):
        context = dict(self._context or {})
        active_ids = context.get('active_ids', []) or []

        for record in self.env['loan.management.loan'].browse(active_ids):
            if record.state not in ('progress','desembolso'):
                raise UserError(_("Selected loan(s) cannot be confirmed."))

            record.action_aprobar()
        return {'type': 'ir.actions.act_window_close'}

class WizardGenerarContabilidad(models.TransientModel):
    """DCLS"""
    _name = 'loan.wizard.generate.accounting'
    _description = 'Asistente Generar Contabilidad'

    @api.multi
    def generate_accounting(self):
        context = dict(self._context or {})
        active_ids = context.get('active_ids', []) or []

        for record in self.env['loan.management.loan'].browse(active_ids):
            if record.state not in ('aprobado','desembolso'):
                raise UserError(_("Selected loan(s) cannot be confirmed."))

            record.generar_contabilidad()
        return {'type': 'ir.actions.act_window_close'}


"""empty message

Revision ID: 3c25fb1c4812
Revises: 887b0d8b4601
Create Date: 2017-01-13 15:20:32.507212

"""

# revision identifiers, used by Alembic.
revision = '3c25fb1c4812'
down_revision = '887b0d8b4601'

from alembic import op
import sqlalchemy as sa

def upgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.add_column('bank_agent', sa.Column('year', sa.Integer(), nullable=True))
    op.add_column('financial', sa.Column('year', sa.Integer(), nullable=True))
    op.add_column('population', sa.Column('year', sa.Integer(), nullable=True))
    op.add_column('telco_agent', sa.Column('year', sa.Integer(), nullable=True))
    ### end Alembic commands ###

def downgrade():
    ### commands auto generated by Alembic - please adjust! ###
    op.drop_column('telco_agent', 'year')
    op.drop_column('population', 'year')
    op.drop_column('financial', 'year')
    op.drop_column('bank_agent', 'year')
    ### end Alembic commands ###


import csv

from django.core.management.base import BaseCommand

from autharch_sharc.editor.models import SharcIIIF

class Command(BaseCommand):
    help = "Import iiif_urls in csv."
    verbose = 1  # show logging on screen

    min_row_length = 5
    iif_created = 0
    events_updated = 0
    event_links = {}

    # def add_arguments(self, parser) -> None:
    #     # csv file to parse
    #     parser.add_argument("csvfile", type=argparse.FileType("r"))

    def parse_iiif_row(self, csv_line, column_format, last_rcin, department="") -> str:
        """Parse the various sheets of the manifests,
        looking for IIIF uris.
        column_format is a dict of which columns contain primary/secondary
        uris, as well as metadata if present
        """
        # check for event id
        if len(csv_line) > 0:
            # Date, Creator, Title, RCIN, Blurb
            """
            iiif_uri = models.CharField(blank=True, null=True, max_length=512)
            rcin = models.CharField(blank=True, null=True, max_length=256)
            images_available = models.TextField(blank=True, null=True)
            department = models.CharField(blank=True, null=True, max_length=256)
            """
            # todo will populate this once format of sheet is more clear

            if "iiif_uri" in column_format:
                rcin = csv_line[0]
                if "images_available" in column_format:
                    try:
                        images_available = csv_line[column_format["images_available"]]
                    except IndexError:
                        images_available = ""
                else:
                    images_available = ""
                if len(rcin) == 0 and len(last_rcin) > 0:
                    # Use RCIN from previous line
                    rcin = last_rcin
                if len(rcin) > 0:
                    for uri_column in column_format["iiif_uri"]:
                        iiif_uri = csv_line[uri_column]

                        if len(iiif_uri) > 0 and (
                            "http" in iiif_uri or "www" in iiif_uri
                        ):
                            if "http" not in iiif_uri:
                                # Add https at the front to make the link work
                                iiif_uri = "https://" + iiif_uri
                            # if len(rcin) == 0:
                            #     # get the end of the uri
                            #     # use first column as the rcin
                            #     rcin_pattern = re.compile(r"https://.*/(.*)/\n*$")
                            #     result = rcin_pattern.search(iiif_uri)
                            #     if result:
                            #
                            #         rcin = result.group(1)

                            if (
                                len(iiif_uri) > 0
                                and "https" in iiif_uri
                                and len(rcin) > 0
                            ):
                                try:
                                    order = 1
                                    # check if this rcin has been uploaded already
                                    # incrememnt order
                                    previous_uris = SharcIIIF.objects.filter(
                                        rcin=rcin
                                    ).order_by("order")
                                    if previous_uris.count() > 0:
                                        last = previous_uris.last()
                                        order = last.order + 1
                                    if (
                                        SharcIIIF.objects.filter(
                                            rcin=rcin,
                                            iiif_uri=iiif_uri.strip(),
                                        ).count()
                                        == 0
                                    ):
                                        (
                                            event,
                                            created,
                                        ) = SharcIIIF.objects.get_or_create(
                                            rcin=rcin,
                                            iiif_uri=iiif_uri.strip(),
                                            images_available=images_available,
                                            department=department,
                                            order=order,
                                        )
                                        if created:
                                            self.iif_created += 1
                                        else:
                                            self.events_updated += 1
                                        print(
                                            "{}:{}:{}\n".format(rcin, iiif_uri, order)
                                        )
                                except ValueError:
                                    pass
                    return rcin
        return ""

    def parse_iiif_sheet(self, filename, column_format, department) -> None:
        with open(filename, "r") as csv_file:
            csvfile = csv.reader(csv_file, delimiter=",")
            print("{}\n".format(department))
            last_rcin = ""
            for csv_line in csvfile:
                last_rcin = self.parse_iiif_row(
                    csv_line, column_format, last_rcin, department
                )

    def handle(self, *args, **options):
        # Reset objects
        # SharcIIIF.objects.all().delete()
        # import sheets
        totals = {}
        # EH commented out as they are complete, final upload only
        """
        self.parse_iiif_sheet(
            "data/ShaRC_manifests_photographs.csv",
            {"images_available": 2, "iiif_uri": [3]},
            "Photographs",
        )
        totals["Photographs"] = self.iif_created
        self.iif_created = 0

        self.parse_iiif_sheet(
            "data/ShaRC_manifests_paintings.csv",
            {"images_available": 2, "iiif_uri": [3]},
            "Paintings",
        )
        totals["Paintings"] = self.iif_created
        self.iif_created = 0

        self.parse_iiif_sheet(
            "data/ShaRC_manifests_library.csv",
            {"images_available": 2, "iiif_uri": [3]},
            "Library",
        )
        totals["Library"] = self.iif_created
        self.iif_created = 0

        self.parse_iiif_sheet(
            "data/ShaRC_manifests_printroom.csv",
            {"images_available": 2, "iiif_uri": [3]},
            "Print Room",
        )
        totals["Print Room"] = self.iif_created
        self.iif_created = 0

        self.parse_iiif_sheet(
            "data/ShaRC_manifests_archives.csv",
            {"images_available": 2, "iiif_uri": [3]},
            "Archives",
        )
        totals["Archives"] = self.iif_created
        self.iif_created = 0
        self.parse_iiif_sheet(
            "data/ShaRC_manifests_decarts.csv",
            {"images_available": 2, "iiif_uri": [3]},
            "Decorative Arts",
        )
        totals["Decorative Arts"] = self.iif_created
        """
        grand_total = 0

        self.iif_created = 0
        self.parse_iiif_sheet(
            "data/SHARC_final_manifests.csv",
            {"images_available": 2, "iiif_uri": [1]},
            "Final manifests",
        )
        totals["Decorative Arts"] = self.iif_created

        self.stdout.write("Complete.\n\nUpload totals: \n")
        for key, value in totals.items():
            self.stdout.write("{} - {}\n".format(key, value))
            grand_total += value
        self.stdout.write("\n Grand total - {}".format(grand_total))


import argparse
import logging
import time

import win32api
import win32con
import win32gui
import win32process

#------------------------------------------------------------------------------------
# Win32 library functions.

def post_lang_change_request_message(hwnd, wparam, lparam):
    """ Post a WM_INPUTLANGCHANGEREQUEST message with the specified parameters. """
    win32gui.PostMessage(hwnd, win32con.WM_INPUTLANGCHANGEREQUEST, wparam, lparam)

def get_current_layout():
    """
    Get the foreground window's current keyboard layout.

    :rtype: int
    :returns: current keyboard layout (HKL DWORD)
    """
    thread_id = win32process.GetWindowThreadProcessId(
        win32gui.GetForegroundWindow()
    )[0]

    # Return the HKL as a 32-bit unsigned integer.
    return win32api.GetKeyboardLayout(thread_id) & 0xffffffff

def get_all_layouts():
    """
    Get a list of all loaded keyboard layouts.

    :rtype: list
    :returns: keyboard layouts
    """
    # Return each HKL as a 32-bit unsigned integer.
    return [hkl & 0xffffffff for hkl in win32api.GetKeyboardLayoutList()]

def set_layout(wparam, lparam, broadcast):
    """
    Set the current keyboard layout by posting a WM_INPUTLANGCHANGEREQUEST message.

    :param wparam: WM_INPUTLANGCHANGEREQUEST message WPARAM value
    :type wparam: int
    :param lparam: WM_INPUTLANGCHANGEREQUEST message LPARAM value
    :type lparam: int
    :param broadcast: whether to post the request message to all windows
    :type broadcast: bool
    """
    # Post the request message to all windows, i.e. broadcast, if specified.
    # Otherwise, only post the request message to the foreground window.
    if broadcast:
        hwnd = win32con.HWND_BROADCAST
    else:
        hwnd = win32gui.GetForegroundWindow()

    # Post the request message.
    post_lang_change_request_message(hwnd, wparam, lparam)

#------------------------------------------------------------------------------------
# CLI functions.

def _cli_get_layout(args):
    # Delay getting the keyboard layout if a non-zero delay value was specified.
    delay = args.delay
    if delay:
        time.sleep(delay)

    # Get the current HKL and print it to stdout in hexadecimal format.
    hkl = get_current_layout()
    print("0x%08x" % hkl)

    # Return the success of this command.
    return 0

def _set_layout(args, wparam, lparam):
    # Delay setting the keyboard layout if a non-zero delay value was specified.
    delay = args.delay
    if delay:
        time.sleep(delay)

    # Set the keyboard layout as specified.
    set_layout(wparam, lparam, args.all_windows)

    # Return the success of this command.
    return 0

def _cli_set_layout(args):
    return _set_layout(args, 0, args.hkl)

def _cli_prev_layout(args):
    inputlangchange_backward = 0x0004
    return _set_layout(args, inputlangchange_backward, 0)

def _cli_next_layout(args):
    inputlangchange_forward = 0x0002
    return _set_layout(args, inputlangchange_forward, 0)

def _cli_list_layouts(args):
    # pylint: disable=W0613
    # Get and print each HKL to stdout in hexadecimal format.
    for hkl in get_all_layouts():
        print("0x%08x" % hkl)
    return 0

#------------------------------------------------------------------------------------
# argparse functions.

def _hexadecimal_or_int(string):
    try:
        return int(string)
    except ValueError:
        return int(string, 16)

def _build_argument(*args, **kwargs):
    return args, kwargs

def _add_arguments(parser, *arguments):
    for (args, kwargs) in arguments:
        parser.add_argument(*args, **kwargs)

def _get_cli_arguments():
    # Use argparse to parse command-line arguments.
    parser = argparse.ArgumentParser(
        description="Utility command-line program for working with Windows keyboard "
                    "layouts."
    )
    subparsers = parser.add_subparsers(dest='command')
    subparsers.required = True

    # Build commonly used arguments.
    delay_argument = _build_argument(
        "-d", "--delay", default=0, type=float,
        help="Time in seconds to delay before getting/setting the keyboard "
        "layout."
    )
    all_windows_argument = _build_argument(
        "-a", "--all-windows", default=False, action="store_true",
        help="Change the keyboard layout for all windows instead of only the "
        "current foreground window. This may be useful on OS versions below "
        "Windows 8."
    )

    # Create the parser for the "get-layout" command.
    parser_get_layout = subparsers.add_parser(
        "get-layout",
        help="Print the current keyboard layout (HKL) of the foreground "
        "window. This value is used as an argument for other commands."
    )
    _add_arguments(parser_get_layout, delay_argument)

    # Create the parser for the "set-layout" command.
    parser_set_layout = subparsers.add_parser(
        "set-layout",
        help="Set the current keyboard layout."
    )
    hkl_argument = _build_argument(
        "hkl", type=_hexadecimal_or_int,
        help="An input locale identifier (HKL) corresponding to the keyboard layout "
        "to set."
    )
    _add_arguments(parser_set_layout, hkl_argument, all_windows_argument,
                   delay_argument)

    # Create the parser for the "prev-layout" command.
    parser_prev_layout = subparsers.add_parser(
        "prev-layout",
        help="Cycle backward one keyboard layout."
    )
    _add_arguments(parser_prev_layout, all_windows_argument,
                   delay_argument)

    # Create the parser for the "next-layout" command.
    parser_next_layout = subparsers.add_parser(
        "next-layout",
        help="Cycle forward one keyboard layout."
    )
    _add_arguments(parser_next_layout, all_windows_argument,
                   delay_argument)

    # Create the parser for the "list-layouts" command.
    subparsers.add_parser(
        "list-layouts",
        help="List each input locale identifier (HKL) corresponding to the current "
        "set of input locales in the system. These identifiers can be used with the "
        "'set-layout' command."
    )

    # Parse and return the arguments.
    return parser.parse_args()

#------------------------------------------------------------------------------------
# Main function.

def _main():
    # Set up logging.
    logging.basicConfig(format="%(levelname)s: %(message)s")
    log = logging.getLogger()

    # Parse arguments.
    args = _get_cli_arguments()

    def not_implemented(_):
        log.error("Command '%s' is not implemented.", args.command)
        return 1

    # Call the relevant CLI function and exit using the result.
    command_map = {
        "get-layout": _cli_get_layout,
        "set-layout": _cli_set_layout,
        "prev-layout": _cli_prev_layout,
        "next-layout": _cli_next_layout,
        "list-layouts": _cli_list_layouts,
    }
    func = command_map.get(args.command, not_implemented)
    return_code = func(args)
    exit(return_code)

if __name__ == '__main__':
    _main()