from graphics import *
from PartialOrderings import *
import random
import copy
import math
import time

class Pt:
    '''Class for points in the plane'''

    def __init__(self, x, y):
        '''Create a point at (x,y)'''

        self.x = float(x)
        self.y = float(y)

    def display(self, win, color="black", size=3):
        '''Display the point on a window'''

        #Y coordinate flipped as graphics origin is top left corner
        point = Point(self.x, win.height - self.y)
        cir = Circle(point)
        cir.setFill(color)
        cir.draw(win)
        return cir

    def clone(self):
        '''Returns a copy of the point'''

        return Pt(self.x, self.y)

    def __repr__(self):
        return "(" + str(self.x) + ", " + str(self.y) + ")"

class LineSegment:
    '''Class for directed line segments in the plane'''

    epsilon = 1e-2

    def __init__(self, pt1, pt2):
        '''Create a directed line segement from pt1 to pt2'''

        self.pt1 = pt1;
        self.pt2 = pt2;

    def signedArea(self, pt):
        '''Returns signed area of pt1, pt2, pt'''

        pt1 = self.pt1
        pt2 = self.pt2
        return (pt2.x - pt1.x) * (pt.y - pt1.y) - (pt2.y - pt1.y) * (pt.x - pt1.x)

    def contains(self, pt):
        '''Returns whether a pt lies on the segment'''

        minx = min(self.pt1.x, self.pt2.x)
        maxx = max(self.pt1.x, self.pt2.x)
        if (pt.x >= minx and pt.x <= maxx):
            return abs(self.signedArea(pt)) <= self.epsilon
        return False;

    def orientation(self, pt):
        '''Returns an int indicating whether pt is above or below the segment'''

        value = self.signedArea(pt)
        if (abs(value) <= self.epsilon):
            return 0
        elif (value < 0):
            return -1
        else:
            return 1

    def display(self, win, width=2):
        '''Display the directed segment on a window'''

        #Y coordinate flipped as graphics origin is top left corner
        p1 = Point(self.pt1.x, win.height - self.pt1.y)
        p2 = Point(self.pt2.x, win.height - self.pt2.y)
        line = Line(p1, p2)
        line.setWidth(width)
        line.setArrow("last")
        line.draw(win)
        return line

    def intersect(self, otherLine):
        '''Returns whether or not two directed segments intersect'''

        selfminx = min(self.pt1.x, self.pt2.x)
        selfmaxx = max(self.pt1.x, self.pt2.x)
        otherminx = min(otherLine.pt1.x, otherLine.pt2.x)
        othermaxx = max(otherLine.pt1.x, otherLine.pt2.x)
        selfOrient1 = self.orientation(otherLine.pt1)
        selfOrient2 = self.orientation(otherLine.pt2)
        otherOrient1 = otherLine.orientation(self.pt1)
        otherOrient2 = otherLine.orientation(self.pt2)
        if selfOrient1 != selfOrient2 and otherOrient1 != otherOrient2:
            return True;
        if (selfOrient1 == 0 and otherLine.pt1.x >= selfminx and otherLine.pt1.x <= selfmaxx):
            return True
        if (selfOrient2 == 0 and otherLine.pt2.x >= selfminx and otherLine.pt2.x <= selfmaxx):
            return True
        if (otherOrient1 == 0 and self.pt1.x >= otherminx and self.pt1.x <= othermaxx):
            return True
        if (otherOrient2 == 0 and self.pt2.x >= otherminx and self.pt2.x <= othermaxx):
            return True
        return False;

    def __repr__(self):
        return self.pt1.__repr__() + " to " + self.pt2.__repr__()

def generatePoints(x,y,n):
    '''generates and returns n random non-degenerate points in [0,x) x [0,y)'''

    points = []
    lines = []
    while (len(points) < n):
        point = Pt(random.uniform(0,x), random.uniform(0,y))
        valid = True;

        #Check it has a unique y coordinate
        if point.y in [p.y for p in points]:
            valid = False
        else:
            #Check that the points are not colinear
            for line in lines:
                if line.contains(point):
                    valid = False;
                    break;
        if (valid):
            for pt in points:
                lines.append(LineSegment(pt, point))
            points.append(point)
    return points

def display(points, lines, win):
    '''displays a set of points and directed segments'''

    for point in points:
        point.display(win)
    for line in lines:
        line.display(win)

def pathStringDP(points, string, solved={}):
    '''Dynamic Programming Solver for path string problem

        Takes cases on where the top point can be in the sequence

        NOTE: Can be made to generate all possible path strings by including
        a blacklist of edges for case III but this would significantly hinder
        performance as we may have to solve an previous subcase as many as
        2^n times as we'd need to recalculate each path for the various blacklists

        Arguments:
            points: a non degenerate set of n > 1 points, sorted by height
            string: a string of length n-1 from {U,D}*

        Returns:
            Many paths satisfying the path string on the point set

    '''

    solved[string] = []

    if len(string) == 1:
        if string[0] == "U":
            solved[string].append([LineSegment(points[0], points[1])])
        else:
            solved[string].append([LineSegment(points[1], points[0])])
        return

    #Case I: Paths that start at the top point
    if string[0] == "D":

        #Find all paths for n - 1 points (all but the top pt) satsifying string[1:]
        partial = string[1:]
        if (partial not in solved):
            pathStringDP(points[:len(points) - 1], partial, solved)
        partialsolutions = solved[partial]

        #Try appending the top point to all subsolutions
        for partialsol in partialsolutions:
            partialsolution = copy.copy(partialsol)
            startingpoint = partialsolution[0].pt1

            #Ensure that the path starting at top point doesn't intersect itself
            newLine = LineSegment(points[len(points) - 1], startingpoint)
            valid = True
            for i in range(1, len(partialsolution)):
                if (partialsolution[i].intersect(newLine)):
                    valid = False
                    break;

            #If no intersections add to solution dictionary
            if (valid):
                partialsolution.insert(0, newLine)
                solved[string].append(partialsolution)

    #Case II: Paths that end at the top point
    if string[len(string) - 1] == "U":

        #Find all paths for n - 1 points (all but the top pt) satsifying string[:len(string)-1]
        partial = string[:len(string) - 1]
        if (partial not in solved):
            pathStringDP(points[:len(points) - 1], partial, solved)
        partialsolutions = solved[partial]

        #Try appending the top point to all subsolutions
        for partialsol in partialsolutions:
            partialsolution = copy.copy(partialsol)

            #Ensure that the path starting at top point doesn't intersect itself
            endpoint = partialsolution[len(partialsolution) - 1].pt2
            newLine = LineSegment(endpoint, points[len(points) - 1])
            valid = True
            for i in range(len(partialsolution) - 1):
                if (partialsolution[i].intersect(newLine)):
                    valid = False
                    break;

            #If no intersections add to solution dictionary
            if (valid):
                partialsolution.append(newLine)
                solved[string].append(partialsolution)

    #Case III: Paths where the top point is not an end point
    #NOTE: Must be at an "UD" in the string
    for i in range(0, len(string) - 1):

        #Find all occurences of "UD"
        if string[i] == "U":
            if string[i + 1] == "D":

                #Have to consider appending top point to solutions to two path strings
                partial1 = string[:i] + "U" + string[i + 2:]
                partial2 = string[:i] + "D" + string[i + 2:]

                #Find all paths for n - 1 points (all but the top pt) satsifying partial1
                if partial1 not in solved:
                    pathStringDP(points[:len(points) - 1], partial1, solved)
                partialSolutions = solved[partial1]

                #Try adding the top point
                for partialsol in partialSolutions:
                    partialSolution = copy.copy(partialsol)
                    #Remove edge corresponding to partial1[i]
                    oldLine = partialSolution.pop(i);

                    #Check if adding top point causes path to intersect itself
                    newLine1 = LineSegment(oldLine.pt1, points[-1])
                    newLine2 = LineSegment(points[-1], oldLine.pt2)
                    valid = True;
                    for j in range(i - 1):
                        if (newLine1.intersect(partialSolution[j]) or
                            newLine2.intersect(partialSolution[j])):
                            valid = False;
                            break;
                    if valid and i > 0 and partialSolution[i-1].intersect(newLine2):
                        valid = False
                    if valid and i < len(partialSolution) and partialSolution[i].intersect(newLine1):
                        valid = False
                    if valid:
                        for j in range(i + 1, len(partialSolution)):
                            if (newLine1.intersect(partialSolution[j]) or
                                newLine2.intersect(partialSolution[j])):
                                valid = False;
                                break;

                    #If no intersections add to solution dictionary
                    if valid:
                        partialSolution.insert(i, newLine1)
                        partialSolution.insert(i + 1, newLine2)
                        solved[string].append(partialSolution)

                #Find all paths for n - 1 points (all but the top pt) satsifying partial2
                if partial2 not in solved:
                    pathStringDP(points[:len(points) - 1], partial2, solved)
                partialSolutions = solved[partial2]

                #Try adding the top point
                for partialsol in partialSolutions:
                    partialSolution = copy.copy(partialsol)

                    #Remove edge corresponding to partial2[i]
                    oldLine = partialSolution.pop(i);

                    #Check if adding top point causes path to intersect itself
                    newLine1 = LineSegment(oldLine.pt1, points[-1])
                    newLine2 = LineSegment(points[-1], oldLine.pt2)
                    valid = True;
                    for j in range(i - 1):
                        if (newLine1.intersect(partialSolution[j]) or
                            newLine2.intersect(partialSolution[j])):
                            valid = False;
                            break;
                    if valid and i > 0 and partialSolution[i-1].intersect(newLine2):
                        valid = False
                    if valid and i < len(partialSolution) and partialSolution[i].intersect(newLine1):
                        valid = False
                    if valid:
                        for j in range(i + 1, len(partialSolution)):
                            if (newLine1.intersect(partialSolution[j]) or
                                newLine2.intersect(partialSolution[j])):
                                valid = False;
                                break;

                    #If no intersections add to solution dictionary
                    if valid:
                        partialSolution.insert(i, newLine1)
                        partialSolution.insert(i + 1, newLine2)
                        solved[string].append(partialSolution)
                i += 1
                return solved

def pathStringDPWrapper(points, string, solved={}, inOrder=False):
    '''A wrapper for the pathStringDP method'''
    if not inOrder:
        points.sort(key=lambda p: p.y)
    sols = pathStringDP(points, string, solved)
    return sols

def randomPathString(n):
    '''Randomly generate a path string of length n'''

    string = ""
    for i in range(n):
        if random.uniform(0,1) > .5:
            string += "U"
        else:
            string += "D"
    return string

def generateAllPathStrings(n, filename, points=None):
    '''Generates n points and then solves all path strings and writes to the
    results to a file'''

    f = open(filename, 'a')

    if points == None:
        points = generatePoints(1000, 1000, n)

    points.sort(key=lambda p: p.y)
    solved = {}
    for i in range(int(math.pow(2, n - 1))):
        if (i % 20 == 0):
            print(i)
        string = "{0:b}".format(i)
        string = "0" * (n - 1 - len(string)) + string
        string = string.replace("0", "U")
        string = string.replace("1", "D")
        f.write(string + ", " + str(len(pathStringDPWrapper(points, string, \
            solved, True)[string])) + "\n")
    f.close()

def bunchOfTrials(n, numPoints, filename):
    '''Initializes n points sets and solves them for all path strings and
    writes the results to a file'''

    f = open(filename, 'a')
    pointSets = []
    solvedSets = []
    output, successful = hullJumpingRecursive(tempPoints, p, tempString)

    #Initialize point sets and solved dictionaries
    for i in range(n):
        points = generatePoints(1000, 1000, numPoints)
        points.sort(key=lambda p: p.y)
        pointSets.append(points)
        solvedSets.append({})

    #Solve all path strings for each points set
    for i in range(int(math.pow(2, numPoints - 1))):
        print(i)
        string = "{0:b}".format(i)
        string = "0" * (numPoints - 1 - len(string)) + string
        string = string.replace("0", "U")
        string = string.replace("1", "D")
        arr = []
        for i in range(len(pointSets)):
            solved = pathStringDPWrapper(pointSets[i], string, solvedSets[i], True)
            arr.append(len(solved[string]))

            #If there is no solution display the point set
            if (len(solved[string]) == 0):
                win = GraphWin("Path String", 1000,1000)
                print(string)
                display(pointSet[i], [], win)
                input()

        f.write(string + ", " + str(max(arr)) + ", " + str(partialOrderings(string, {})) + "\n")
    f.close()

def nonIntersectingPaths(n):
    '''Gives lower bound for the number of non intersecting paths on n points'''

    total = 0
    points = generatePoints(1000, 1000, n)
    points.sort(key=lambda p: p.y)
    solved = {}
    for i in range(int(math.pow(2, n - 1))):
        string = "{0:b}".format(i)
        string = "0" * (n - 1 - len(string)) + string
        string = string.replace("0", "U")
        string = string.replace("1", "D")
        total += len(pathStringDPWrapper(points, string, solved,True)[string])
    return total

def generateConvexPoints(n, r=100):
    '''Generates points in convex position (more specifically on a circle)'''

    thetas = []
    points = []
    while len(points) < n:

        #Make sure that two points don't have the same y coordinate
        theta = random.uniform(-math.pi, math.pi)
        if theta not in thetas and -theta not in thetas:
            points.append(Pt(r*math.cos(theta), r*math.sin(theta)))
            thetas.append(theta)
    return points

def convexHull(points,sortedByY=False):
    '''Grahm Scan convex hull algorithm'''

    if (len(points) < 4):
        return points
    bottom = points[0]
    if not sortedByY:
        for i in range(1,len(points)):
            if points[i].y < bottom.y:
                bottom = points[i]
    points.remove(bottom)
    points.sort(key=lambda p: -1 * (p.x - bottom.x)/(p.y - bottom.y))
    points.append(bottom)
    stack = [bottom, points[0]]
    for cur in range(1, len(points)):
        stack.append(points[cur])
        p3 = stack.pop()
        p2 = stack.pop()
        p1 = stack.pop()
        signedArea = (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x)
        while signedArea <= 0:
            p2 = p1
            p1 = stack.pop()
            signedArea = (p2.x - p1.x)*(p3.y - p1.y) - (p2.y - p1.y)*(p3.x - p1.x)
        stack.append(p1)
        stack.append(p2)
        stack.append(p3)
    stack.pop()
    return stack

def jarvisMarchSinglePass(points, point):
    '''A single iteration of Jarvis march'''

    nextPoint = point
    nextSegment = LineSegment(point, point)
    prevPoint = point
    prevSegment = LineSegment(point, point)
    for p in points:
        if (nextPoint == point or nextSegment.signedArea(p) > 0):
            nextPoint = p
            nextSegment.pt2 = p
        if (prevPoint == point or prevSegment.signedArea(p) < 0):
            prevPoint = p
            prevSegment.pt2 = p
    return [nextPoint, prevPoint]

def hullJumping(points, string, hull=None):
    '''A wrapper for the hull jumping algorithm'''

    if hull == None:
        hull = convexHull(points)
    found = False
    output = []

    #Start the recursive hull jumping algorithm from each point in the hull
    for point in hull:
        out, success = hullJumpingRecursive(copy.copy(points),point,string)
        if success:
            found = True
            for o in out:
                o.append(point)
                output.append(o)

    return output

def hullJumpingRecursive(points, point, string):
    '''A recursive implementation for the hull jumping algorithm'''

    if (len(string) == 1):
        points.remove(point)
        if string[0] == "U" and points[0].y < point.y:
            return [[points[0]]], True
        if string[0] == "D" and points[0].y > point.y:
            return [[points[0]]], True
        return [[]], False

    #Find previous point and next point on the convex hull
    p1, p2 = jarvisMarchSinglePass(points, point)

    #Determine what new points will be on the convex hull after removing the current point
    p3, p4 = jarvisMarchSinglePass(points, p1)
    if p3.x == point.x and p3.y == point.y:
        p3 = p4
    p4 = p1
    points.remove(point)
    nextPoints = [p1]
    while p4.x != p2.x and p4.y != p2.y:
        p5, p6 = jarvisMarchSinglePass(points, p4)
        if p5.x == p3.x and p5.y == p3.y:
            p5 = p6
        p3 = p4
        p4 = p5
        nextPoints.append(p4)

    out = []
    success = False

    #Try jumping to a point in the next hull
    if (string[0] == "U"):
        for p in nextPoints:
            if p.y > point.y:
                tempPoints = copy.copy(points)
                tempString = string[1:]
                output, successful = hullJumpingRecursive(tempPoints, p, tempString)
                if successful:
                    for arr in output:
                        arr.append(p)
                        out.append(arr)
                    success = True
    else:
        for p in nextPoints:
            if p.y < point.y:
                tempPoints = copy.copy(points)
                tempString = string[1:]
                output, successful = hullJumpingRecursive(tempPoints, p, tempString)
                if successful:
                    for arr in output:
                        arr.append(p)
                        out.append(arr)
                    success = True
    return out, success

print(hullJumping(generatePoints(1000,1000,5), "UDUU"))
print(pathStringDPWrapper(generatePoints(1000,1000,5), "UDUU"))


# -*- coding: utf-8 -*-

from odoo import models, fields, api
from odoo.addons import decimal_precision as dp
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT

class ModificarOtrosTalleres(models.TransientModel):
    _name = 'modificar.otros.talleres.wizard'

    line_ids = fields.One2many("modificar.otros.talleres.wizard.line",'wizard_id', 'Modificar otros talleres')
    reparacion_id = fields.Many2one("ordenes.de.reparacion",'Orden de reparación')
    currency_id = fields.Many2one("res.currency", string="Currency", readonly=True, default=lambda self: self.env.user.company_id.currency_id)
    company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env['res.company']._company_default_get('ordenes.de.reparacion'))

    @api.multi
    def action_create(self):
        po_exist = {}
        purchase_obj = self.env['purchase.order']
        po_line_obj = self.env['purchase.order.line'].sudo()
        otros_talleres_obj = self.env['otros.talleres.ordenes.de.reparacion']
        for line in self.line_ids:
            partner = line.proveedor_id
            if not partner:
                continue
            po = po_exist.get(partner)
            if not po:
                vals = self._prepare_purchase_order(partner)
                po = purchase_obj.sudo().create(vals)
                po_exist.update({partner: po})
            poline_vals = self._prepare_purchase_order_line(line,po)
            po_line_obj.create(poline_vals)
            otros_talleres_obj.create({
                                       'product_id':line.product_id.id,
                                       'name': line.name,
                                       'proveedor_id' : line.proveedor_id.id,
                                       'product_uom_qty' : line.product_uom_qty,
                                       'product_uom' : line.product_uom.id,
                                       'price_unit' : line.price_unit,
                                       'costo_proveedor' : line.costo_proveedor,
                                       'tax_id' : [(6,0,line.tax_id.ids)],
                                       'reparacion_id' : self.reparacion_id.id,
                                       'pct_percent': line.pct_percent,
                                       })

        return True

    @api.multi
    def _prepare_purchase_order_line(self, line, po):
        #product_uom = line.product_uom
        product_qty = line.product_uom_qty
        product = line.product_id
        partner = po.partner_id
        #procurement_uom_po_qty = product_uom._compute_quantity(product_qty, product.uom_po_id)
        seller = product._select_seller(
            partner_id=partner,
            quantity=product_qty,
            date=po.date_order and po.date_order.date(),
            uom_id=product.uom_po_id)

        taxes = product.supplier_taxes_id
        fpos = po.fiscal_position_id
        taxes_id = fpos.map_tax(taxes, product, seller.name) if fpos else taxes
        if taxes_id:
            taxes_id = taxes_id.filtered(lambda x: x.company_id.id == po.company_id.id)

        product_lang = product.with_context({'lang': partner.lang, 'partner_id': partner.id,})
        name = product_lang.display_name
        if product_lang.description_purchase:
            name += '\n' + product_lang.description_purchase

        date_planned = self.env['purchase.order.line']._get_date_planned(seller, po=po).strftime(DEFAULT_SERVER_DATETIME_FORMAT)

        return {
            'name': name,
            'product_qty': product_qty,
            'product_id': product.id,
            'product_uom': product.uom_po_id.id,
            'price_unit': line.costo_proveedor,
            'date_planned': date_planned,
            'taxes_id': [(6, 0, taxes_id.ids)],
            'order_id': po.id,
        }

    def _prepare_purchase_order(self,  partner):
        purchase_date = fields.Datetime.now()
        company = self.company_id
        fpos = self.env['account.fiscal.position'].with_context(force_company=company.id).get_fiscal_position(partner.id)
        return {
            'partner_id': partner.id,
            'picking_type_id': self.reparacion_id.warehouse_id.in_type_id.id,
            'operating_unit_id': self.reparacion_id.operating_unit_id.id,
            'company_id': company.id,
            'currency_id': partner.with_context(force_company=company.id).property_purchase_currency_id.id or self.env.user.company_id.currency_id.id,
            'origin': self.reparacion_id.name,
            'payment_term_id': partner.with_context(force_company=company.id).property_supplier_payment_term_id.id,
            'date_order': purchase_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
            'fiscal_position_id': fpos,
            'ordenes_id' : self.reparacion_id.id,
        }

class ModificarOtrosTalleresWizardLine(models.TransientModel):
    _name = 'modificar.otros.talleres.wizard.line'

    @api.depends('product_uom_qty', 'price_unit', 'tax_id')
    def _compute_amount(self):
        """
        Compute the amounts of line.
        """
        for line in self:
            price = line.price_unit
            taxes = line.tax_id.compute_all(price, line.wizard_id.currency_id, line.product_uom_qty, product=line.product_id)
            line.update({
                #'price_tax': sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])),
                #'price_total': taxes['total_included'],
                'price_subtotal': taxes['total_excluded'],
            })

    wizard_id = fields.Many2one("modificar.otros.talleres.wizard",'Wizard')
    product_id = fields.Many2one("product.product",'Producto')
    name = fields.Text(string='Description', required=True)
    proveedor_id = fields.Many2one("res.partner",'Proveedor',domain=[('supplier','=',True)])
    product_uom_qty = fields.Float(string='Cantidad', digits=dp.get_precision('Product Unit of Measure'), required=True, default=1.0)
    product_uom = fields.Many2one('uom.uom', string='Unit of Measure')
    price_unit = fields.Float('Precio unitario', required=True, digits=dp.get_precision('Product Price'), default=0.0)
    costo_proveedor = fields.Float('Costo provedor', digits=dp.get_precision('Product Price'), default=0.0)
    tax_id = fields.Many2many('account.tax', string='Impuestos', domain=['|', ('active', '=', False), ('active', '=', True)])
    currency_id = fields.Many2one(related='wizard_id.currency_id', depends=['wizard_id'], store=True, string='Currency', readonly=True)
    price_subtotal = fields.Monetary(compute='_compute_amount', string='Subtotal', readonly=True, store=True)
    pct_percent = fields.Float('PCT(%)')

    @api.onchange('pct_percent', 'costo_proveedor')
    def onchange_pct_costo(self):
        if self.pct_percent and self.costo_proveedor:
            self.price_unit = self.costo_proveedor * (1+self.pct_percent/100)

    @api.multi
    @api.onchange('product_id')
    def product_id_change(self):
        if not self.product_id:
            return {'domain': {'product_uom': []}}

        vals = {}
        domain = {'product_uom': [('category_id', '=', self.product_id.uom_id.category_id.id)]}
        if not self.product_uom or (self.product_id.uom_id.id != self.product_uom.id):
            vals['product_uom'] = self.product_id.uom_id
            vals['product_uom_qty'] = self.product_uom_qty or 1.0

        pricelist = self.proveedor_id.property_product_pricelist
        product = self.product_id.with_context(
            lang=self.proveedor_id.lang,
            partner=self.proveedor_id,
            quantity=vals.get('product_uom_qty') or self.product_uom_qty,
            pricelist = pricelist.id,
            uom=self.product_uom.id
        )

        result = {'domain': domain}

        name = product.get_product_multiline_description_sale()

        vals.update(name=name)

        fpos = self.proveedor_id.property_account_position_id
        # If company_id is set, always filter taxes by the company
        taxes = self.product_id.taxes_id.filtered(lambda r: not self.wizard_id.company_id or r.company_id == self.wizard_id.company_id)
        self.tax_id = fpos.map_tax(taxes, self.product_id, self.reparacion_id.partner_id) if fpos else taxes

        if pricelist and self.proveedor_id:
            vals['price_unit'] = self.env['account.tax']._fix_tax_included_price_company(product.price, product.taxes_id, self.tax_id, self.wizard_id.company_id)
        self.update(vals)
        return result

#     product_id = fields.Many2one("product.product",'Description')
#     name = fields.Char("Description")
#     product_uom_qty = fields.Float(string='Cantidad', digits=dp.get_precision('Product Unit of Measure'))
#     product_uom_qty_new = fields.Float(string='Nueva Cantidad', digits=dp.get_precision('Product Unit of Measure'), default=1.0)
#     refacciones_line_id = fields.Many2one("refacciones.ordenes.de.reparacion",'Refacciones Line')


import numpy as np
from geopy import Nominatim
from geopy.extra.rate_limiter import RateLimiter
import pandas as pd
import os,glob
import time
import configparser

print('process Started')

path_fig = configparser.ConfigParser()
path_fig.read('test_us.ini')
excel_path =  path_fig.get('test','excel_path')
input_path =  path_fig.get('test','input_path')
output_path =  path_fig.get('test','output_path')

#split dataset into chuncks
df = pd.read_excel(excel_path)
ss = np.array_split(df, 175)

for test in range(len(ss)):
	ss[test].to_csv(f'{input_path}uscitysplit{test}.csv')
# print('wait 1.30 min')
time.sleep(10)

# function for finding location coordinates
def process_operation(df,i):
    i = i
    df['CSM'] = df[df.columns[0:2]].apply(lambda x: ','.join(x.dropna().astype(str)),axis=1)
    geolocator = Nominatim(user_agent="my_request")

    #applying the rate limiter wrapper
    geocode = RateLimiter(geolocator.geocode, min_delay_seconds=1)

    #Applying the method to pandas DataFrame
    df['location'] = df['CSM'].apply(geocode)
    df['Lat'] = df['location'].apply(lambda x: x.latitude if x else None)
    df['Lon'] = df['location'].apply(lambda x: x.longitude if x else None)
    df.to_csv(f'{output_path}uscity_corr_{i}.csv')
    print(f'saved as csv uscity_corr_{i}.csv successfully')
    print('process completed',df.shape)

# read all splited csv and apply with function
all_files = glob.glob(os.path.join(input_path, "*.csv"))

all_files.sort()

for i in range(len(all_files)):
    print(f'processing with {all_files[i]}')
    df = pd.read_csv(f'{all_files[i]}')
    df.drop(['Unnamed: 0'], axis=1,inplace=True)
    # print(df)
    try:
        process_operation(df,i)
    except:
        time.sleep(500)
        process_operation(df,i)

#   Merge all files generated coordinates csv
merge_all_files = glob.glob(os.path.join(output_path, "*.csv"))
df_final = pd.concat((pd.read_csv(f) for f in merge_all_files), ignore_index=True)
df_final.drop(['Unnamed: 0', 'location','CSM',], axis=1,inplace=True)
df_final.to_csv('US-City_Coordinates_testrun.csv')

print('process Completed')


from model.banco import Banco
from model.cliente import Cliente
from model.conta import ContaCorrente, ContaPoupanca

banco = Banco()

cliente1 = Cliente('Leonardo',37)
cliente2 = Cliente('Jessica',29)
cliente3 = Cliente('Paulo',29)

conta1 = ContaPoupanca(1111,254136, 100)
conta2 = ContaCorrente(2222,985415, 300)
conta3 = ContaPoupanca(1212,685471, 150)

cliente1.inserir_conta(conta1)
cliente2.inserir_conta(conta2)
cliente3.inserir_conta(conta3)

banco.inserir_cliente(cliente1)
banco.inserir_conta(conta1)

banco.inserir_cliente(cliente2)
banco.inserir_conta(conta2)

if banco.autenticar(cliente1):
    cliente1.conta.depositar(40)
    cliente1.conta.sacar(20)
else:
    print('Cliente não autorizado')

print('#'*20)
if banco.autenticar(cliente2):
    cliente2.conta.depositar(40)
    cliente2.conta.sacar(20)
else:
    print('Cliente não autorizado')
print('#'*20)


from flask import Flask
from flask.ext.cors import CORS
from flask_graphql import GraphQL

from schema import schema, orm

app = Flask(__name__, static_url_path='/static/')
app.debug = True

from graphql.core.execution import Executor, SynchronousExecutionMiddleware

class PonyMiddleware(object):
    @staticmethod
    def run_resolve_fn(resolver, original_resolver):
        with orm.db_session:
            return SynchronousExecutionMiddleware.run_resolve_fn(resolver, original_resolver)

    @staticmethod
    def execution_result(executor):
        with orm.db_session:
            return SynchronousExecutionMiddleware.execution_result(executor)

executor = Executor([PonyMiddleware()])
graphql = GraphQL(app, schema=schema, executor=executor)

CORS(app)

with orm.db_session:
    app.run()


import contextlib
import pyodbc
import subprocess

# Populate the names of the API DB, the database server, and the current ICTVonline database.
apiDB = "ICTV_API"
dbServer = "ICTVDEV"
taxonomyDB = "ICTVonline39"

# Export taxonomy JSON files for non-species and species taxa in every MSL release.
def exportTaxonomyJSON(apiDB_, dbServer_, taxonomyDB_, treeID_):

    # Validate parameters
    if apiDB_ in (None, '') or not apiDB_.strip():
        raise Exception("The apiDB parameter is invalid")

    if dbServer_ in (None, '') or not dbServer_.strip():
        raise Exception("The dbServer parameter is invalid")

    if taxonomyDB_ in (None, '') or not taxonomyDB_.strip():
        raise Exception("The taxonomyDB parameter is invalid")

    # The database connection string
    dbConnectionString = ("Driver={SQL Server Native Client 11.0};"
        f"Server={dbServer_};"
        f"Database={apiDB_};"
        "Trusted_Connection=yes;")

    # SQL to drop existing and create new taxonomy views for this taxonomy database.
    viewsSQL = f"EXEC dbo.createIctvOnlineViews @ictvOnlineDbName = '{taxonomyDB_}' "

    treeConstraint = ""
    treeLimit = ""

    # If a tree ID was provided, we will limit the tree ID query to one result.
    if treeID_ not in (None, ''):
        treeConstraint = f"AND tree_id = {treeID_} "
        treeLimit = "TOP 1 "

    # SQL to retrieve tree ID(s) in the taxonomy database's taxonomy "table of contents" table.
    treeSQL = f"""
        SELECT {treeLimit}tree_id
        FROM v_taxonomy_toc
        WHERE msl_release_num IS NOT NULL
        {treeConstraint}
        ORDER BY tree_id ASC
    """

    # Open the database connection
    with contextlib.closing(pyodbc.connect(dbConnectionString)) as dbConnection:

        # Create views for this taxonomy database.
        viewCursor = dbConnection.cursor()
        viewCursor.execute(viewsSQL)

        # Get all tree IDs in the taxonomy database.
        treeCursor = dbConnection.cursor()

        # Create views for this taxonomy database.
        # Iterate over all tree IDs that are returned.
        for row in treeCursor.execute(treeSQL):

            # Get the tree ID as a string.
            treeID = str(row.tree_id)

            # Get the year from the tree ID.
            year = treeID[0:4]
            formattedYear = year if treeID[4] == "0" else f"{year}.{treeID[4]}"

            # Create the command line text to run sqlcmd for non-species taxa.
            nonSpeciesCMD = (f"sqlcmd -S {dbServer_} "
                f"-Q \"EXEC [{apiDB_}].dbo.exportNonSpeciesTaxonomyJSON @treeID = {treeID}\" "
                f"-o \"JSON\\nonSpecies_{formattedYear}.json\" "
                "-y 0 ")

            # Run the command
            subprocess.run(nonSpeciesCMD, shell=True)

             # Create the command line text to run sqlcmd for species taxa.
            speciesCMD = (f"sqlcmd -S {dbServer_} "
                f"-Q \"EXEC [{apiDB_}].dbo.exportSpeciesTaxonomyJSON @treeID = {treeID}\" "
                f"-o \"JSON\\species_{formattedYear}.json\" "
                "-y 0 ")

            # Run the command
            subprocess.run(speciesCMD, shell=True)

if __name__ == '__main__':

    exportTaxonomyJSON(apiDB, dbServer, taxonomyDB, None)


"""
Stochastic versions of standard multi-layer perceptrons (MLPs) for use in
the Q-SAVI algorithm. Implemented by subclassing the standard Haiku module.
"""

from functools import partial
from typing import Callable, List, Optional, Sequence, Tuple, Union

import haiku as hk
import jax
import jax.numpy as jnp
import jax.random as random
import numpy as np
from jax import jit

# ------------------ STOCHASTIC LINEAR LAYER ------------------ #

class DenseStochastic(hk.Module):
    """
    Stochastic fully connected layer with parameters sampled from a Gaussian
    variational distribution parameterised by means and log-varainces.
    """

    def __init__(
        self,
        output_size: int,
        init_logvar_minval: float,
        init_logvar_maxval: float,
        with_bias: bool = True,
        w_init: Optional[hk.initializers.Initializer] = None,
        b_init: Optional[hk.initializers.Initializer] = None,
        name: Optional[str] = None,
    ):
        """
        Initialise the stochastic fully connected layer.

        Args:
            output_size: output dimension.
            init_logvar_minval: lower bound of the range from which to
                log-uniformly sample the log-variance initialization.
            init_logvar_maxval: upper bound of the range from which to
                log-uniformly sample the log-variance initialization.
            with_bias: whether to include a bias term.
            w_init: initializer for the weight matrix.
            b_init: initializer for the bias vector.
            name: name of the module.

        Returns:
            None.

        """

        super(DenseStochastic, self).__init__(name=name)

        self.output_size = output_size
        self.w_init = w_init
        self.b_init = b_init
        self.init_logvar_minval = init_logvar_minval
        self.init_logvar_maxval = init_logvar_maxval

    def __call__(
        self,
        inputs: jnp.ndarray,
        rng_key: jnp.ndarray,
        stochastic=True,
    ) -> jnp.ndarray:
        """
        Forward pass of the stochastic fully connected layer.

        Args:
            inputs: input data.
            rng_key: random number generator key.
            stochastic: whether to sample from the variational distribution
                over parameters or only use their means.

        Returns:
            outputs: output data.

        """

        input_size = inputs.shape[-1]
        input_dtype = inputs.dtype

        # if no initialiser is specified, use the default Haiku initialiser

        if self.w_init is None:
            stddev = 1 / np.sqrt(input_size)
            self.w_init = hk.initializers.TruncatedNormal(stddev=stddev, mean=0)

        if self.b_init is None:
            self.b_init = hk.initializers.Constant(0)

        # get parameter means and log-variances
        w_mu = hk.get_parameter(
            "w_mu",
            shape=[input_size, self.output_size],
            dtype=input_dtype,
            init=self.w_init,
        )

        b_mu = hk.get_parameter(
            "b_mu", shape=[self.output_size], dtype=input_dtype, init=self.b_init
        )

        w_logvar = hk.get_parameter(
            "w_logvar",
            shape=[input_size, self.output_size],
            dtype=input_dtype,
            init=uniform_mod(self.init_logvar_minval, self.init_logvar_maxval),
        )

        b_logvar = hk.get_parameter(
            "b_logvar",
            shape=[self.output_size],
            dtype=input_dtype,
            init=uniform_mod(
                self.init_logvar_minval,
                self.init_logvar_maxval,
            ),
        )

        key_1, key_2 = jax.random.split(rng_key)
        W = gaussian_sample(w_mu, w_logvar, stochastic, key_1)
        b = gaussian_sample(b_mu, b_logvar, stochastic, key_2)

        return jnp.dot(inputs, W) + b

# ------------------ DEFINE STOCHASTIC MLP ------------------ #

class MLP(hk.Module):
    """
    MLP class to construct a sequence of stochastic fully connected layers
    with ReLU activations and a linear output layer.
    """

    def __init__(
        self,
        output_dim: int,
        num_layers: int,
        embed_dim: int,
        init_logvar_minval: float = -10.0,
        init_logvar_maxval: float = -8.0,
    ):
        """
        Initialise the MLP.

        Args:
            output_dim: output dimension.
            num_layers: number of layers.
            embed_dim: embedding dimension.
            init_logvar_minval: lower bound of the range from which to
                log-uniformly sample the log-variance initialization.
            init_logvar_maxval: upper bound of the range from which to
                log-uniformly sample the log-variance initialization.

        Returns:
            None.

        """

        super().__init__()

        self.activation_fn = jax.nn.relu

        self.layers = []
        for _ in range(num_layers - 1):
            self.layers.append(
                DenseStochastic(
                    output_size=embed_dim,
                    init_logvar_minval=init_logvar_minval,
                    init_logvar_maxval=init_logvar_maxval,
                )
            )

        # FINAL LAYER
        self.layers.append(
            DenseStochastic(
                output_size=output_dim,
                init_logvar_minval=init_logvar_minval,
                init_logvar_maxval=init_logvar_maxval,
                name="linear_final",
            )
        )

    def __call__(
        self, inputs: jnp.ndarray, rng_key: jnp.ndarray, stochastic: bool = True
    ) -> jnp.ndarray:
        """
        Forward pass of the MLP.

        Args:
            inputs: input data.
            rng_key: random number generator key.
            stochastic: whether to sample from the variational distribution
                over parameters or only use their means.

        Returns:
            outputs: output data.

        """

        rng_keys = random.split(rng_key, len(self.layers))

        out = inputs

        for l in range(len(self.layers) - 1):
            out = self.layers[l](out, rng_keys[l], stochastic)
            out = self.activation_fn(out)

        out = self.layers[-1](out, rng_keys[-1], stochastic)

        return out

class BayesianMLP:
    """
    Wrapper class that uses Haiku to transform the MLP defined above into
    a set of pure functions, which it exposes as a range of different methods.
    """

    def __init__(
        self,
        output_dim: int,
        num_layers: int,
        embed_dim: int,
        init_logvar_minval: float = -10.0,
        init_logvar_maxval: float = -8.0,
    ):
        """
        Initialise the Bayesian MLP.

        Args:
            output_dim: output dimension.
            num_layers: number of layers.
            embed_dim: embedding dimension.
            init_logvar_minval: lower bound of the range from which to
                log-uniformly sample the log-variance initialization.
            init_logvar_maxval: upper bound of the range from which to
                log-uniformly sample the log-variance initialization.

        Returns:
            None.

        """

        self.output_dim = output_dim
        self.num_layers = num_layers
        self.embed_dim = embed_dim
        self.init_logvar_minval = init_logvar_minval
        self.init_logvar_maxval = init_logvar_maxval

        forward_fn = lambda inputs, rng_key, stochastic=True: MLP(
            output_dim=self.output_dim,
            num_layers=self.num_layers,
            embed_dim=self.embed_dim,
            init_logvar_minval=self.init_logvar_minval,
            init_logvar_maxval=self.init_logvar_maxval,
        )(inputs, rng_key, stochastic)

        self.forward = hk.transform_with_state(forward_fn)

    @property
    def apply_fn(self) -> Callable:
        return self.forward.apply

    @partial(jit, static_argnums=(0))
    def predict_f(
        self,
        params: hk.Params,
        state: hk.State,
        inputs: jnp.ndarray,
        rng_key: jnp.ndarray,
    ) -> jnp.ndarray:
        """
        Draw a sample from the parameter distribution of the MLP and use it
        to predict the labels at a batch of input points.

        Args:
            params: model parameters.
            state: model state.
            inputs: a batch of input.
            rng_key: JAX random key.

        Returns:
            outputs: output data.

        """

        return self.forward.apply(
            params,
            state,
            rng_key,
            inputs,
            rng_key,
        )[0]

    def predict_f_multisample(
        self,
        params: hk.Params,
        state: hk.State,
        inputs: jnp.ndarray,
        rng_key: jnp.ndarray,
        n_samples: int,
    ) -> Tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray]:
        """
        Draw multiple Monte-Carlo samples from the parameter distribution of
        the MLP and use them to predict the labels at a batch of input points.

        Args:
            params: model parameters.
            state: model state.
            inputs: a batch of input.
            rng_key: JAX random key.
            n_samples: number of MC samples.

        Returns:
            n_samples samples of logits, of shape
            (n_samples, inputs.shape[0], output_dimension).
            mean of logits, of shape (inputs.shape[0], output_dimension).
            variance of logits, of shape (inputs.shape[0], output_dimension).

        """

        pred_fn = lambda rng_key: self.predict_f(params, state, inputs, rng_key)

        return mc_sampling(
            fn=pred_fn,
            n_samples=n_samples,
            rng_key=rng_key,
        )

    @partial(jit, static_argnums=(0, 5))
    def predict_f_multisample_jitted(
        self,
        params,
        state,
        inputs,
        rng_key,
        n_samples: int,
    ):
        """
        Jitted version of predict_f_multisample for use in the training loop.

        Args:
            params: model parameters.
            state: model state.
            inputs: a batch of input.
            rng_key: JAX random key.
            n_samples: number of MC samples.

        Returns:
            n_samples samples of logits, of shape
            (n_samples, inputs.shape[0], output_dimension).
            mean of logits, of shape (inputs.shape[0], output_dimension).
            variance of logits, of shape (inputs.shape[0], output_dimension).

        """

        rng_keys = jax.random.split(rng_key, n_samples)
        _predict_multisample_fn = lambda rng_key: self.predict_f(
            params,
            state,
            inputs,
            rng_key,
        )
        predict_multisample_fn = jax.vmap(
            _predict_multisample_fn, in_axes=0, out_axes=0
        )

        preds_samples = predict_multisample_fn(rng_keys)
        preds_mean = preds_samples.mean(axis=0)
        preds_var = preds_samples.std(axis=0) ** 2

        return preds_samples, preds_mean, preds_var

# ------------------ UTILITY FUNCTIONS ------------------ #

def uniform_mod(min_val: float, max_val: float) -> Callable:
    """
    Returns a weight initializer for uniform sampling from the given range.
    Used to log-uniformly sample the log-variance of the weights.

    Args:
        min_val: lower bound of the range.
        max_val: upper bound of the range.

    Returns:
        weight initializer.

    """

    def _uniform_mod(shape, dtype):
        rng_key, _ = random.split(random.PRNGKey(0))
        return jax.random.uniform(
            rng_key, shape=shape, dtype=dtype, minval=min_val, maxval=max_val
        )

    return _uniform_mod

def mc_sampling(
    fn: Callable, n_samples: int, rng_key: jnp.ndarray
) -> Tuple[jnp.ndarray, jnp.ndarray, jnp.ndarray]:

    """
    Performs Monte Carlo sampling of the variational distribution of the parameters
    and returns the samples themselves, as well as their mean and variance.

    Args:
        fn: a deterministic function that accepts in a random key
        n_samples: number of MC samples.
        rng_key: random key.

    Returns:
        n_samples samples of logits, of shape
        (n_samples, inputs.shape[0], output_dimension).
        mean of logits, of shape (inputs.shape[0], output_dimension).
        variance of logits, of shape (inputs.shape[0], output_dimension).

    """

    list_of_pred_samples = []
    for _ in range(n_samples):
        rng_key, subkey = jax.random.split(rng_key)
        output = fn(subkey)
        list_of_pred_samples.append(jnp.expand_dims(output, 0))
    preds_samples = jnp.concatenate(list_of_pred_samples, 0)
    preds_mean = preds_samples.mean(axis=0)
    preds_var = preds_samples.std(axis=0) ** 2
    return preds_samples, preds_mean, preds_var

def gaussian_sample(
    mu: jnp.ndarray, rho: jnp.ndarray, stochastic: bool, rng_key: jnp.ndarray
) -> jnp.ndarray:

    """
    Samples from a Gaussian distribution with mean mu and log-variance rho.

    Args:
        mu: mean of the distribution.
        rho: log-variance of the distribution.
        stochastic: whether to sample stochastically or deterministically.
        rng_key: random key.

    Returns:
        a sample from the Gaussian distribution.

    """

    if stochastic:
        jnp_eps = random.normal(rng_key, mu.shape)
        z = mu + jnp.exp((0.5 * rho).astype(jnp.float32)) * jnp_eps
    else:
        z = mu
    return z


import cv2
import sys
sys.path.append("game/")
import wrapped_flappy_bird as game
import random
import numpy as np
from TFBrain import TFBrain
from TFBrain import Experience
from tqdm import tqdm

# Preprocess raw image to 80*80 image

def preprocess(img):
    img = cv2.resize(img, (80,80))
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    ret, img = cv2.threshold(img,1,255,cv2.THRESH_BINARY)
    img = np.reshape(img, (80,80,1))
    return img

def init_state(observation):
    state = np.stack((observation, observation, observation, observation), axis = 2)
    return state

def proceed_state(state, next_observation):
    next_state = np.append(state[:,:,1:], next_observation, axis = 2)
    return next_state

def learn_flappybird():
    brain_config = {
        'network_type': 'cnn',
        'learning': True,
        'num_actions': 2,
        'experience_size': 50000,
        'gamma': 0.99,
        'observe_age': 1000,
        'explore_age': 300000,
        'explore_burin': 1000,
        'epsilon_min': 0.0,
        'epsilon_test_time': 0.0,
        'batch_size': 32,
        'lookback_window': 3
    }

    brain = TFBrain(brain_config)
    brain.show_configs()

    bird_env = game.GameState()
    frame_per_action = 1

    action = np.array([1,0])
    observation, reward, chain_end = bird_env.frame_step(action)
    observation = preprocess(observation)
    observation = np.reshape(observation, (observation.shape[0], observation.shape[1]))
    state = init_state(observation)

    i = 0
    while 1!= 0:
        if i % frame_per_action == 0:
            action = brain.decide(state, determistic=False)
        else:
            # Do nothing
            action = np.array([1,0])
        i += 1
        next_observation, reward, chain_end = bird_env.frame_step(action)
        next_observation = preprocess(next_observation)
        next_state = proceed_state(state, next_observation)
        experience = Experience(state, action, reward, next_state, chain_end)
        brain.learn(experience)
        state = next_state

def play_flappybird():
    brain_config = {
        'network_type': 'cnn',
        'learning': False,
        'num_actions': 2,
        'lookback_window': 3
    }

    brain = TFBrain(brain_config)
    brain.show_configs()

    bird_env = game.GameState()
    frame_per_action = 1

    action = np.array([1,0])
    observation, reward, chain_end = bird_env.frame_step(action)
    observation = preprocess(observation)
    observation = np.reshape(observation, (observation.shape[0], observation.shape[1]))
    state = init_state(observation)

    i = 0
    while 1!= 0:
        if i % frame_per_action == 0:
            action = brain.decide(state, determistic=True)
        else:
            # Do nothing
            action = np.array([1,0])
        i += 1
        next_observation, reward, chain_end = bird_env.frame_step(action)
        next_observation = preprocess(next_observation)
        next_state = proceed_state(state, next_observation)
        experience = Experience(state, action, reward, next_state, chain_end)
        state = next_state

def main():
    learn_flappybird()
    # play_flappybird()

if __name__ == '__main__':
    main()


# This is an example of how modules should be formatted. It has no actual function

# SOME INFO

# All code should be put in the `script_main` function which is executed by the wraith
# in a separate thread. Any code outside of this function will be executed in the command
# executor thread which can delay or block other commands to be ran by the same thread.

# The `script_main` function will have 2 arguments passed to it; the wraith object and
# the full command line respectively. It is up to the module to process this command line
# such as by splitting it into separate arguments. The first word of the command line will
# always be the command itself. For example, "echo hello there" will be the command line
# of a command called "echo" with the arguments "hello there".

# These modules run in threads started by the wraith and by default, have access to every
# library used by the wraith. Additional libraries can be imported here but this is not
# recommended as the commands will then be unable to run if the wraith is frozen (PyInstaller, etc.)

# Warning: Comments are not stripped by the panel so the less comments the better as
# less data needs to be sent.

# END OF INFO

# The following is an example of the `sh` command:

def script_main(wraith, cmdname):
	try:
		sh_to_run = " ".join(cmdname.split(" ")[1:])
		wraith.putresult("SUCCESS", subprocess.run(sh_to_run, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.DEVNULL, timeout=5, shell=True).stdout.decode('utf-8'))
	except Exception as e:
		wraith.putresult("ERROR - {}".format(e), "Error while executing `{}`".format(cmdname))


import sys
import os
import uuid

current = os.path.dirname(os.path.realpath(__file__))
parent = os.path.dirname(current)
sys.path.append(parent)
from FileDownload import Downloader
import random, string
import tabula

def nameFormatter(teststring):
    if type(teststring) is str:
        firstname, lastname = teststring.strip().lower().split()
        return firstname.strip(), lastname.strip()

def main(data):
    print("<<<<<<<<<<<<<<<<<<<<<<<<<<In GuardianRCM>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")

    if data["RcmEobClaimMaster"][0].get("url") and data["RcmEobClaimMaster"][0].get("ClaimNumber") != "" and \
            data["RcmEobClaimMaster"][0].get("Patient") != "" and data["RcmEobClaimMaster"][0].get(
        "DateOfService") != "" and data["RcmEobClaimMaster"][0].get("SubmittedCharges") != "":
        data['RcmEobClaimDetail'] = []
        file_path = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10)) + ".pdf"
        # file_path = "3GAXV3KCM2.pdf"
        # print(file_path)
        input_file = data["RcmEobClaimMaster"][0]["url"].replace("%20", " ")
        print("input_file>>>>>>>>>>>>>>", input_file)
        Downloader('Revenue Cycle Management', file_path, input_file)
        dict_list = tabula.read_pdf(file_path, pages='all')
        # print("dict_list>>>>>>>>>>>>>>>>>>>>>>>",dict_list)

        PatientName = data["RcmEobClaimMaster"][0].get("Patient")
        firstname, lastname = PatientName.lower().split()

        # lst = []
        # for ind, tab in enumerate(dict_list):
        #     if any('Claim Number' and PatientName in col for col in tab.columns):
        #         new_columns_name = {}
        #         for i in range(len(tab.columns)):
        #             old_name = tab.columns[i]
        #             new_name = f'columns{i + 1}'
        #             new_columns_name[old_name] = new_name
        #             tab = tab.rename(columns=new_columns_name)
        #         lst.append(tab.to_dict('records'))

        lst = []
        for ind, tab in enumerate(dict_list):
            if any('Claim Number' in col for col in tab.columns):
                if len(tab) > 0 and len(tab.columns) > 1:
                    checkParam = tab.iloc[0][0]
                    if "Patient Name" in checkParam:
                        if nameFormatter(PatientName) == nameFormatter(checkParam.split("Patient Name")[-1]):
                            new_columns_name = {}
                            for i in range(len(tab.columns)):
                                old_name = tab.columns[i]
                                new_name = f'columns{i + 1}'
                                new_columns_name[old_name] = new_name
                                tab = tab.rename(columns=new_columns_name)
                            lst.append(tab.to_dict('records'))
        # print("lst>>>>>>>>>>>>>>>>>>>>>>",lst)
        temp_lst = []
        for i in range(len(lst)):
            for obj in lst[i]:
                if type(obj.get('columns1')) != float:
                    temp_lst.append(obj)
        # print("temp_lst>>>>>>>>>>>>>>>>>>>>>>", temp_lst)
        filtered_lst = []
        for i in range(len(temp_lst)):
            if not temp_lst[i]['columns1'].startswith('Patient Name') and not temp_lst[i]['columns1'].startswith(
                    'Planholder') and not temp_lst[i]['columns1'].startswith('Line Submitted') and not temp_lst[i][
                'columns1'].startswith('No.'):
                filtered_lst.append(temp_lst[i])
        # print("filtered_lst>>>>>>>>>>",filtered_lst)
        new_lst = []
        new_dict = {}
        for obj in filtered_lst:

            columns3 = str(obj.get('columns3')).replace('nan', '').split()
            columns4 = str(obj.get('columns4')).replace('nan', '').split()

            if 'columns6' in obj:
                columns6 = str(obj.get('columns6')).split()
                columns4 = obj.get('columns4').split()
                if len(columns6) == 3 and len(columns4) == 3:
                    new_dict = {
                        'SubmittedADACodesDescription': obj.get("columns1"),
                        'AltCode': obj.get("columns2"),
                        'ToothNo': obj.get("columns3"),
                        'DateOfService': columns4[0],
                        'SubmittedCharge': columns4[1],
                        'ConsideredCharge': columns4[2],
                        'CoveredCharge': obj.get("columns5"),
                        'DeductibleAmount': columns6[0],
                        'CoveragePercent': columns6[1],
                        'BenefitAmount': columns6[2]
                    }
                elif len(columns6) == 2 and len(columns4) == 3:
                    new_dict = {
                        'SubmittedADACodesDescription': obj.get("columns1"),
                        'AltCode': obj.get("columns2"),
                        'ToothNo': obj.get("columns3"),
                        'DateOfService': columns4[0],
                        'SubmittedCharge': columns4[1],
                        'ConsideredCharge': columns4[2],
                        'CoveredCharge': obj.get("columns5"),
                        'DeductibleAmount': "",
                        'CoveragePercent': columns6[0],
                        'BenefitAmount': columns6[1]
                    }
                elif len(columns6) == 1 and len(columns4) == 4:
                    new_dict = {
                        'SubmittedADACodesDescription': obj.get("columns1"),
                        'AltCode': obj.get("columns2"),
                        'ToothNo': obj.get("columns3"),
                        'DateOfService': columns4[0],
                        'SubmittedCharge': columns4[1],
                        'ConsideredCharge': columns4[2],
                        'CoveredCharge': columns4[3],
                        'DeductibleAmount': "",
                        'CoveragePercent': obj.get("columns5"),
                        'BenefitAmount': str(obj.get("columns6"))
                    }
                elif len(columns4) == 3:
                    columns4 = obj.get('columns4').split()
                    new_dict = {
                        'SubmittedADACodesDescription': obj.get("columns1"),
                        'AltCode': obj.get("columns2"),
                        'ToothNo': obj.get("columns3"),
                        'DateOfService': columns4[0],
                        'SubmittedCharge': columns4[1],
                        'ConsideredCharge': columns4[2],
                        'CoveredCharge': obj.get("columns5"),
                        'DeductibleAmount': obj.get("columns6"),
                        'CoveragePercent': obj.get("columns7"),
                        'BenefitAmount': str(obj.get("columns9"))
                    }
            elif len(columns3) == 3:
                columns2 = obj.get('columns2').split()
                columns4 = obj.get('columns4').split()
                new_dict = {
                    'SubmittedADACodesDescription': obj["columns1"],
                    'AltCode': "",
                    'ToothNo': columns2[0],
                    'DateOfService': columns2[1],
                    'SubmittedCharge': columns3[0],
                    'ConsideredCharge': columns3[1],
                    'CoveredCharge': columns3[2],
                    'DeductibleAmount': "",
                    'CoveragePercent': columns4[0],
                    'BenefitAmount': str(columns4[1])
                }
            elif len(columns4) == 4:
                columns5 = obj.get('columns5').split()
                new_dict = {
                    'SubmittedADACodesDescription': obj.get("columns1"),
                    'AltCode': "",
                    'ToothNo': obj.get('columns3'),
                    'DateOfService': columns4[0],
                    'SubmittedCharge': columns4[1],
                    'ConsideredCharge': columns4[2],
                    'CoveredCharge': columns4[3],
                    'DeductibleAmount': "",
                    'CoveragePercent': columns5[0],
                    'BenefitAmount': str(columns5[1])
                }

            else:
                columns3 = obj.get('columns3').split()
                columns4 = obj.get('columns4').split()
                new_dict = {
                    'SubmittedADACodesDescription': obj["columns1"],
                    'AltCode': "",
                    'ToothNo': obj.get("columns2"),
                    'DateOfService': columns3[0],
                    'SubmittedCharge': columns3[1],
                    'ConsideredCharge': columns3[2],
                    'CoveredCharge': columns3[3],
                    'DeductibleAmount': "",
                    'CoveragePercent': columns4[0],
                    'BenefitAmount': columns4[1]
                }
            if str(new_dict.get('AltCode')) == 'nan':
                new_dict['AltCode'] = str(new_dict.get('AltCode')).replace('nan', '')
            if str(new_dict.get('ToothNo')) == 'nan':
                new_dict['ToothNo'] = str(new_dict.get('ToothNo')).replace('nan', '')
            new_lst.append(new_dict)
        for i in new_lst:
            data['RcmEobClaimDetail'].append(i)

        ADACodes = ""
        Description = ""
        for i in range(len(data['RcmEobClaimDetail'])):
            for key, values in data['RcmEobClaimDetail'][i].items():
                if key == "SubmittedADACodesDescription":
                    cdtcodes_type_of_service = values
                    ADACodes, Description = cdtcodes_type_of_service.split("/", 1)
            data['RcmEobClaimDetail'][i]["ADACodes"] = ADACodes
            data['RcmEobClaimDetail'][i]["Description"] = Description
            del data['RcmEobClaimDetail'][i]["SubmittedADACodesDescription"]

        for obj in data['RcmEobClaimDetail']:
            ads_code = obj["ADACodes"].split()
            if len(ads_code) == 2:
                obj["ADACodes"] = ads_code[1]
        for obj in data["RcmEobClaimDetail"]:
            obj["RecordID"] = str(uuid.uuid4())
    else:
        data['RcmEobClaimDetail'] = []
        if data["RcmEobClaimMaster"][0].get("url"):
            data["RcmEobClaimMaster"][0]["url"] = ""

    if data.get("RcmEobClaimMaster"):
        for obj in data["RcmEobClaimMaster"]:
            obj["RecordID"] = str(uuid.uuid4())

    return data


from PIL import Image, ImageDraw
from matplotlib import pyplot as plt
import numpy as np
from scipy.spatial import cKDTree
from scipy.spatial import Voronoi
from skimage.draw import polygon
import random

def voronoi(points, size):
    # Add points at edges to eliminate infinite ridges
    edge_points = size*np.array([[-1, -1], [-1, 2], [2, -1], [2, 2]])
    new_points = np.vstack([points, edge_points])

    # Calculate Voronoi tessellation
    vor = Voronoi(new_points)
    return vor

width = height = size = 3600
n = 384

x = np.random.randint(0, width, (n,)) #随机采样n个点
y = np.random.randint(0, height, (n,))

points = np.vstack([x, y]).T #x和y依次组成n个点[[x, y],...]

cyan = (12, 236, 221)
yellow = (255, 243, 56)
pink = (196, 0, 255)
magenta = (255, 103, 231)

new_points = points.copy()

for k in range(100):
    vor = voronoi(new_points, size)

    im = Image.new('RGB', (width, height), (255, 255, 255))
    draw = ImageDraw.Draw(im)

    for i, point in enumerate(new_points):
        circle_size = np.array([20, 20])
        p1 = point - circle_size/2
        p2 = point + circle_size/2
        draw.ellipse((*p1, *p2), fill=(0, 0, 255))

    new_points = []

    for i, region in enumerate(vor.regions):
        if len(region) == 0 or -1 in region: continue
        poly = np.array([vor.vertices[i] for i in region])

        for i in range(len(poly)):
            draw.line((*poly[-i], *poly[-i-1]), fill=(50, 50 ,50), width=5)

        center = poly.mean(axis=0)
        new_points.append(center)

        circle_size = np.array([20, 20])
        p1 = center - circle_size/2
        p2 = center + circle_size/2
        draw.ellipse((*p1, *p2), fill=(255, 0, 0))

    new_points = np.array(new_points).clip(0, size)

    im = im.crop((200, 1000, 3400, 2600))
    im = im.resize((800, 400), resample=Image.ANTIALIAS)
    im.save(f"figure_4/out_{k}.png")


# 클래스(class): 함수나 변수들을 모아 놓은 집합체
# 인스턴스(instance): 클래스에 의해 생성된 객체, 인스턴스 각자 자신의 값을 가지고 있다.

numbers1 = []
numbers2 = list(range(10))

characters = list('Harry')
print(characters)

numbers1 == list  # 같지 않음

# 클래스 만들기
# 클래스와 인스턴스를 이용하면 데이터와 코드를 사람이 이해하기 쉽게 포장할 수 있다.

class Human():
    """person"""

def speak(person):
    print('{}이 {}로 말을 합니다.'.format(person.name, person.language))

person1 = Human()
person2 = Human()

person1.language = '한국어'
person2.language = 'English'

print(person1.language)
print(person2.language)

person1.name = '손흥민'
person2.name = 'Harry Kane'

Human.speak = speak
person1.speak()
person2.speak()


a=int(input())
l=[]
testL=[]
for i in range(a):
    word=input()
    tmp=list(word)
    tmp.sort()
    if tmp not in testL:
        testL.append(tmp)
        l.append(word)
print(len(l))


from django.test import TestCase

# Create your tests here.
def get_img_url(str):
    index = str.find(r'',index) + 2]
        pattern = r'src=\"[^\"]+\"'
        import re
        res = re.search(pattern, img_html, re.M)
        begin, end = res.span()
        return img_html[begin + 5:end - 1]

if __name__ == '__main__':
   str = r''
   print( get_img_url(str))

   # import re
   # print(str.find(r'>', str.find(r'<img')))
   # print(str[str.find(r'', str.find(r'<img'))])


import keras
from keras.models import Sequential
from keras.layers import Dense, Embedding, LSTM

# Define the model
model = Sequential()
model.add(Embedding(input_dim=vocab_size, output_dim=embedding_dim, input_length=max_length))
model.add(LSTM(units=32))
model.add(Dense(units=vocab_size, activation='softmax'))

# Compile the model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# Fit the model to the training data
model.fit(X_train, y_train, epochs=10, batch_size=32)

# Define a set of predefined responses
responses = ['Hello!', 'How are you?', 'I am an AI.', 'I am here to assist you.']

# Generate a response to a user input
def generate_response(user_input):
  # Preprocess the input
  input_seq = preprocess_input(user_input)
  # Predict the next word in the sequence
  next_word_idx = model.predict(input_seq)[0]
  # Convert the predicted word index to the corresponding word
  next_word = idx_to_word[next_word_idx]
  # Check if the predicted word is a response
  if next_word in responses:
    return next_word
  else:
    return "I'm sorry, I don't understand what you are saying."

# Enter a loop to accept user input and generate responses
while True:
  user_input = input('> ')
  print(generate_response(user_input))


from lepton import Particle, ParticleGroup, default_system
from lepton.renderer import BillboardRenderer
from lepton.texturizer import SpriteTexturizer
from lepton.emitter import StaticEmitter
from lepton.controller import Gravity, Lifetime, Movement, Fader, ColorBlender, Growth

from math import pi

import os.path

from pyglet import image

class Explosion(object):

    def __init__(self, x, y):

        spark_tex = image.load(os.path.join(os.path.dirname(__file__), 'images/flare3.png')).get_texture()

        sparks = ParticleGroup(
            controllers=[
                Lifetime(2),
                Movement(damping=0.93),
                Fader(fade_out_start=0, fade_out_end=1.8),
            ],

            renderer=BillboardRenderer(SpriteTexturizer(spark_tex.id)))

        spark_emitter = StaticEmitter(
            template=Particle(
                position=(x,y),
                color=(1,1,1)),
            deviation=Particle(
                position=(1,1,0),
                velocity=(300,300,0),
                age=1.5),
            size=[(1,1,0), (2,2,0), (2,2,0), (2,2,0), (3,3,0), (4,4,0)])
        spark_emitter.emit(50, sparks)

        fire_tex = image.load(os.path.join(os.path.dirname(__file__), 'images/puff.png')).get_texture()

        fire = ParticleGroup(
            controllers=[
            Lifetime(4),
            Movement(damping=0.95),
            Growth(10),
            Fader(fade_in_start=0, start_alpha=0, fade_in_end=0.5, max_alpha=0.4,
                fade_out_start=1.0, fade_out_end=1.0)
            ],
            renderer=BillboardRenderer(SpriteTexturizer(fire_tex.id)))

        fire_emitter = StaticEmitter(
            template=Particle(
                position=(x, y),
                size=(10,10,0)),
            deviation=Particle(
                position=(2,2,0),
                velocity=(70,70,0),
                size=(5,5,0),
                up=(0,0,pi*2),
                rotation=(0,0,pi*0.06),
                age=.3,),
            color=[(0.5,0,0), (0.5,0.5,0.5), (0.4,0.1,0.1), (0.85,0.3,0)],
        )
        fire_emitter.emit(200, fire)


import coresyntax as S
import coretypes as T
from utility import flatten
import copy
import visitor as V
import intrinsics as I
import pltools as P
import midendsyntax as M
import codesnippets as C
import midtypes as MT
import pdb
from ..runtime import places as PL, cubox as CB, cufunction as CF
import phasetypes as PT
import cintrinsics as CI

class Iterizer(S.SyntaxRewrite):
    def __init__(self):
        pass
    def _Procedure(self, proc):
        self.currentProcedureName = proc.variables[0].id
        self.body = []
        self.currentBin = self.body
        self.tailRecursive = False
        self.rewrite_children(proc)
        if not self.tailRecursive:
            return proc
        def convertRecursion(stmt):
            if not isinstance(stmt, S.Bind):
                return stmt
            if not isinstance(stmt.id, S.Name):
                return stmt
            if stmt.id.id == C.anonymousReturnValue.id:
                arguments = proc.variables[1:]
                apply = stmt.parameters[0]
                assert apply.parameters[0].id == self.currentProcedureName
                newArguments = apply.parameters[1:]
                return [S.Bind(x, y) for x, y in zip(arguments, newArguments)]
            else:
                return stmt
        recursiveBranch = list(flatten([convertRecursion(x) for x in self.recursiveBranch]))
        recursiveBranch = filter(lambda x: isinstance(x, S.Bind), recursiveBranch)
        whileLoop = M.While(self.condition, [recursiveBranch + self.body])
        cleanup = self.nonrecursiveBranch
        proc.parameters = self.body + [whileLoop] + cleanup
        return proc

    def _Bind(self, stmt):
        self.currentBin.append(stmt)
        self.binder = stmt.id
        self.rewrite_children(stmt)
        return stmt

    def _Return(self, stmt):
        self.currentBin.append(stmt)
        return stmt

    def _Apply(self, apply):
        applyFnName = apply.parameters[0].id
        if applyFnName == self.currentProcedureName:
            self.recursionDetected = True
            if not self.binder.id == C.anonymousReturnValue.id:
                raise SyntaxError('Recursive function detected, but recursion not in tail position')
        return apply
    def _Cond(self, cond):
        self.recursionDetected = False
        self.currentBranch = []
        self.currentBin = self.currentBranch
        thenBranch = self.rewrite(cond.parameters[1])
        if self.recursionDetected:
            self.recursiveBranch = self.currentBranch
            self.tailRecursive = True
            self.condition = cond.parameters[0]
        else:
            self.nonrecursiveBranch = self.currentBranch
        self.recursionDetected = False
        self.currentBranch = []
        self.currentBin = self.currentBranch
        elseBranch = self.rewrite(cond.parameters[2])
        if self.recursionDetected:
            self.recursiveBranch = self.currentBranch
            self.tailRecursive = True
            self.condition = S.Apply(S.Name('op_not'), [cond.parameters[0]])
        else:
            self.nonrecursiveBranch = self.currentBranch
        return cond

def remove_recursion(stmt):

    iterizer = Iterizer()
    return iterizer.rewrite(stmt)

class Sequentializer(S.SyntaxRewrite):
    def __init__(self, entry_points, p_hier):
        self.entry_points = entry_points
        self.context = I.unknown
        self.p_hier = p_hier
    def _Apply(self, apply):
        self.rewrite_children(apply)
        fn = apply.function()
        if hasattr(fn, 'context'):
            apply.context = fn.context()
        else:
            apply.context = self.context
        return apply
    def _Map(self, map):
        return self._Apply(map)

    def _Procedure(self, proc):
        name = proc.variables[0]
        if name.id in self.entry_points:
            proc.context = self.p_hier[0]
        else:
            proc.context = self.p_hier[1]
        self.context = proc.context
        self.rewrite_children(proc)

        return proc

def sequentialize(stmt, entry_points, p_hier):
    sequentializer = Sequentializer(entry_points, p_hier)
    sequentialized = sequentializer.rewrite(stmt)
    return sequentialized

class Unzipper(S.SyntaxRewrite):
    """This rewrite pass finds calls to zip and removes them,
    replacing all references to the result of the zip with a tuple
    of inputs."""
    def __init__(self, entry_points):
        self.entry_points = entry_points
    def _Bind(self, binder):
        self.binder = binder
        self.rewrite_children(binder)
        return self.binder
    def _Apply(self, ast):
        fn = ast.function()

        # XXX we should probably not key on function name here
        if fn.id[0:3] != 'zip':
            return ast

        binder = self.binder
        self.binder = S.Null()
        dest = binder.binder().id
        self.env[dest] = M.Zip(*(x for x in ast.arguments()))
        return S.Null()

    def _Procedure(self, proc):
        if proc.name().id not in self.entry_points:
            return proc
        self.env = P.Environment()
        self.rewrite_children(proc)
        proc.parameters = S.stripNull(proc.parameters)
        proc = S.substituted_expression(proc, self.env)
        return proc

def unzip_transform(stmt, entry_points):
    unzipper = Unzipper(entry_points)
    unzipped = unzipper.rewrite(stmt)
    return unzipped

class VariantSelector(S.SyntaxRewrite):
    def __init__(self, globals):
        self.globals = globals
    def _Apply(self, apply):
        if apply.context is I.distributed:
            fn = apply.function()
            fn_name = str(fn)
            if fn_name in self.globals:
                global_fn = self.globals[fn_name]
                variants = global_fn.variants
                placed_variant = variants.get(PL.default_place, variants[PL.here])
                phase_fn = placed_variant.cu_phase
                fn.cu_phase = phase_fn
                if hasattr(CI, '_' + fn_name):
                    intrinsic = getattr(CI, '_' + fn_name)
                    scalar = getattr(intrinsic, 'scalar', False)
                    fn.scalar = scalar
                    return apply
                if isinstance(placed_variant, CB.CuBox):
                    fn.box = True
                elif not isinstance(placed_variant, CF.CuFunction):
                    fn.box = True

        return apply

def select_variant(stmt, globals):
    selector = VariantSelector(globals)
    return selector.rewrite(stmt)

class ScalarPlacer(S.SyntaxRewrite):
    """This rewrite rule decides whether scalar operations will be executed
    on the host, or at the place.  Since they can be executed at either place,
    we can choose."""
    def __init__(self):
        self.box_results = set()
        self.scalar_results = {}
    def _Bind(self, bind):
        destination = bind.binder()
        self.box = False
        self.scalar = False
        self.rewrite_children(bind)
        if self.box:
            self.box_results.update((str(x) for x in flatten(destination)))
        if self.scalar:
            for dest in flatten(destination):
                self.scalar_results[str(dest)] = bind.value()
        return bind
    def _Apply(self, apply):
        # Scalar intrinsics can be executed on the host or at the place
        # This rule will execute them on the host if any of the inputs to the
        # scalar intrinsic are coming from a boxed function
        # Justification for this rule is that boxed functions return their
        # results to the host, so having the host compute scalar functions
        # on the results of boxed functions makes sense.  On the other hand,
        # scalar intrinsics should be executed on the place if their inputs
        # are available on the place.
        def place_host(app):
            """This function places a scalar operation on the host.
            It also places any scalar operations which feed into this function
            on the host as well, recursively."""
            app.function().box = True
            app.function().host = True
            for x in app.arguments():
                if str(x) in self.scalar_results:
                    place_host(self.scalar_results[str(x)])

        if hasattr(apply.function(), 'box'):
            self.box = True
        scalar = hasattr(apply.function(), 'scalar') and apply.function().scalar
        if scalar:
            for x in apply.arguments():
                if str(x) in self.box_results:
                    place_host(apply)
                    self.box = True
                    break

        self.scalar = scalar
        return apply
    def _Procedure(self, proc):
        # XXX Phase analysis only works for parallel procedures - fix!
        if not hasattr(proc, 'context'):
            return proc
        if proc.context is not I.distributed:
            return proc
        self.box_results = set()
        self.rewrite_children(proc)
        return proc

class PhaseAnalyzer(S.SyntaxRewrite):
    def __init__(self, globals):
        self.globals = globals
        self.pre_box = None
    def _Closure(self, closure):
        closed = closure.closed_over()
        if self.sync:
            sync = self.sync
        else:
            sync = []
        for var in closed:
            id = var.id
            if id not in self.declarations:
                self.declarations[id] = PT.total
            elif self.declarations[id] is PT.unknown:
                self.declarations[id] = PT.total
            elif self.declarations[id] < PT.total:
                sync.append(id)
        if sync:
            self.sync = sync
        return closure
    def _Bind(self, bind):
        self.destination = bind.binder()
        self.sync = None
        self.box = False
        self.rewrite_children(bind)

        def record_sync():
            for variable in self.declarations.keys():
                if not variable in [x.id for x in flatten(self.destination)]:
                    self.declarations[variable] = PT.total

        if not self.sync and self.pre_box:
            record_sync()
            result = [M.PhaseBoundary(list(flatten(self.pre_box))), bind]
        elif self.sync:
            record_sync()
            result = [self.sync, bind]
        else:
            result = bind

        if self.box:
            self.pre_box = self.destination
        else:
            self.pre_box = None
        return result
    def _Map(self, map):
        self.rewrite_children(map)
        if self.sync:
            sync = self.sync
        else:
            sync = []
        for input in map.inputs():
            id = input.id

            if self.declarations[id] is PT.unknown:
                self.declarations[id] = PT.local
            elif self.declarations[id] < PT.local:
                sync.append(id)
        if sync:
            self.sync = M.PhaseBoundary(sync)
        self.declarations[self.destination.id] = PT.local
        return map
    def _Apply(self, apply):
        for arg in apply.arguments():
            if isinstance(arg, S.Name):
                if arg.id not in self.declarations:
                    self.declarations[arg.id] = PT.none
        def name_filter(x):
            if isinstance(x, S.Name):
                return self.declarations[x.id]
            else:
                return PT.total
        completions = [name_filter(x) for x in apply.arguments()]
        fn_name = apply.function().id
        fn_phase = apply.function().cu_phase
        input_phases, output_completion = \
            fn_phase(*completions)
        for name in flatten(self.destination):
            self.declarations[name.id] = output_completion
        sync = []

        if hasattr(apply.function(), 'box'):
            self.box = True
            for x in apply.arguments():
                # XXX Special case for dealing with zip -
                # The unzip transform pushes tuple args around the AST
                # This needs to be rethought
                # Right now it will only work for zip as argument to Box
                # functions.
                # The right thing to do is generate host code for this
                # But we need to transition the entire entry-point procedure
                # to C++ on the host in order to do this.

                if hasattr(x, '__iter__'):
                    for xi in x:
                        sync.append(xi.id)
                else:
                    sync.append(x.id)

        else:
            for x, y in zip(apply.arguments(), input_phases):
                if isinstance(x, S.Name):
                    x_phase = self.declarations[x.id]
                    if x_phase is PT.unknown:
                        self.declarations[x.id] = y
                    elif x_phase < y:
                        sync.append(x.id)
        if sync:
            self.sync = M.PhaseBoundary(sync)
        return apply
    def _Procedure(self, proc):
        # XXX Phase analysis only works for parallel procedures - fix!
        if not hasattr(proc, 'context'):
            return proc
        if proc.context is not I.distributed:
            return proc

        self.declarations = dict(((x.id, PT.total) for x in proc.formals()))
        self.rewrite_children(proc)
        proc.parameters = list(flatten(proc.parameters))
        self.declarations = None
        #Construct phase for this procedure?
        return proc

def phase_analysis(stmt, globals):
    placer = ScalarPlacer()
    placed = placer.rewrite(stmt)
    analyzer = PhaseAnalyzer(globals)
    rewritten = analyzer.rewrite(placed)
    return rewritten

class PhasePartition(S.SyntaxRewrite):
    def __init__(self, entry_points):
        self.entry_points = entry_points
    def _Procedure(self, proc):
        if proc.name().id not in self.entry_points:
            return proc
        phases = []
        current_phase = 0
        current_body = []
        for stmt in proc.body():
            if isinstance(stmt, S.Return):
                proc.return_node = stmt
            elif not isinstance(stmt, M.PhaseBoundary):
                current_body.append(stmt)
            else:
                if current_body:
                    name = S.Name(proc.name().id + "_phase" + str(current_phase))
                    phase = S.Procedure(name, [], current_body)
                    phase.context = proc.context
                    phases.append(phase)
                    current_phase += 1
                current_body = []
        name = S.Name(proc.name().id + "_phase" + str(current_phase))
        phase = S.Procedure(name, [], current_body)
        phase.context = proc.context
        phases.append(phase)
        proc.parameters = phases

        return proc

class PhaseArguments(S.SyntaxRewrite):
    def __init__(self, entry_points):
        self.entry_points = entry_points
    def _Procedure(self, proc):
        if proc.name().id not in self.entry_points:
            return proc
        calls = []
        for phase in proc.body():
            free = S.free_variables(phase)
            variables = set(free).intersection(proc.typings.keys())
            phase.variables = phase.variables + [S.Name(x) for x in variables]
        return proc

class PhaseReturns(S.SyntaxRewrite):
    def __init__(self, entry_points):
        self.entry_points = entry_points
        self.in_process = False
        self.computed = set()
    def _Procedure(self, proc):
        if proc.name().id not in self.entry_points:
            if not self.in_process:
                proc.master = False
                proc.entry_point = False
                return proc
            self.escaping = set()
            self.rewrite_children(proc)
            returns = S.Tuple(*[S.Name(x) for x in self.escaping if x not in self.computed])
            proc.parameters.append(S.Return(returns))
            for name in returns.parameters:
                self.computed.add(name.id)
            proc.returns = returns
            proc.master = False
            proc.entry_point = True
            proc.typings = self.typings
            return proc
        phase_args = set()
        for phase in proc.body():
            phase_args = phase_args.union([x.id for x in phase.formals()])
        phase_args = phase_args.union((x.id for x in flatten(proc.return_node.parameters)))

        self.phase_args = phase_args
        self.in_process = True
        self.typings = proc.typings
        self.rewrite_children(proc)
        self.in_process = False
        calls = [S.Bind(x.returns, S.Apply(x.name(), x.formals())) \
                     for x in proc.body()]
        proc.parameters = proc.parameters + calls + [proc.return_node]
        proc.master = True
        return proc
    def _Bind(self, bind):
        destinations = flatten(bind.binder())
        for destination in destinations:
            if destination.id in self.phase_args:
                self.escaping.add(destination.id)
        return bind

class UnBoxer(S.SyntaxRewrite):
    'Eliminates phases which call CuBox functions'
    def __init__(self, entry_points):
        self.entry_points = entry_points
    def _Procedure(self, proc):
        if proc.name().id not in self.entry_points:
            return proc
        new_phases = []
        replacements = {}
        host = {}
        for phase in filter(lambda x: isinstance(x, S.Procedure), proc.body()):
            first_stmt = phase.body()[0]
            if not isinstance(first_stmt, S.Bind):
                new_phases.append(phase)
                continue
            if not isinstance(first_stmt.value(), S.Apply):
                new_phases.append(phase)
                continue
            function = first_stmt.value().function()
            box = getattr(function, 'box', False)
            host = getattr(function, 'host', False)
            if not box:
                new_phases.append(phase)
                continue
            replacements[phase.name().id] = (first_stmt, host)
        for bind in filter(lambda x: isinstance(x, S.Bind), proc.body()):
            if not isinstance(bind.value(), S.Apply):
                continue
            fn_name = bind.value().function().id
            fn_host = getattr(bind.value().function(), 'host', False)
            if not fn_name in replacements:
                continue
            if fn_host:
                continue
            rep_bind, host = replacements[fn_name]
            apply = rep_bind.value()
            id = apply.function().id
            if not host:
                id += '.variants[execution_place]'

            apply.parameters[0] = S.Name(id)

            apply.parameters[0].box = True
            bind.parameters[0] = apply
            bind.id = rep_bind.id
        proc.parameters = [x for x in proc.body() if not isinstance(x, S.Procedure)]
        proc.parameters = new_phases + proc.parameters
        return proc

def phase_rewrite(stmt, entry_points):
    partitioner = PhasePartition(entry_points)
    partitioned = partitioner.rewrite(stmt)
    argumenter = PhaseArguments(entry_points)
    argumented = argumenter.rewrite(partitioned)
    returner = PhaseReturns(entry_points)
    returned = returner.rewrite(argumented)
    unboxer = UnBoxer(entry_points)
    unboxed = unboxer.rewrite(returned)
    return unboxed


from flask import request
from flask_restful import Resource
from http import HTTPStatus
from flask_jwt_extended import get_jwt_identity, jwt_required, jwt_optional

from models.space import Space
from schemas.spaceschema import SpaceSchema

from resources.user import UserResource

space_schema = SpaceSchema()
space_list_schema = SpaceSchema(many=True)

class SpaceListResource(Resource):

    @jwt_required
    def get(self): # toimii
        spaces = Space.get_all_published()

        return space_list_schema.dump(spaces).data, HTTPStatus.OK

    @jwt_required
    def post(self): # toimii
        json_data = request.get_json()
        current_user = get_jwt_identity()

        data, errors = space_schema.load(data=json_data)

        if errors:
            return {'message': "Validation errors", 'errors': errors}, HTTPStatus.BAD_REQUEST

        space = Space(**data)
        space.user_id = current_user
        space.save()

        return space_schema.dump(space).data, HTTPStatus.CREATED

class SpaceResource(Resource):

    @jwt_required # toimii
    def patch(self, space_id):
        json_data = request.get_json()

        data, errors = space_schema.load(data=json_data, partial=('name',))

        if errors:
            return {'message': 'Validation errors', 'errors': errors}, HTTPStatus.BAD_REQUEST

        space = Space.get_by_id(space_id=space_id)

        if space is None:
            return {'message': 'Workspace not found'}, HTTPStatus.NOT_FOUND

        space.name = data.get('name') or space.name

        space.save()

        return space_schema.dump(space).data, HTTPStatus.OK

    @jwt_required # toimii
    def get(self, space_id):
        space = Space.get_by_id(space_id=space_id)

        if space is None:
            return {'message': 'Workspace not found'}, HTTPStatus.NOT_FOUND

        return space_schema.dump(space).data, HTTPStatus.OK

    @jwt_required # toimii
    def delete(self, space_id):
        space = Space.get_by_id(space_id=space_id)

        if space is None:
            return {'message': 'Workspace not found'}, HTTPStatus.NOT_FOUND

        space.delete()

        return {}, HTTPStatus.NO_CONTENT