import numpy as np
import torch as th

def dictionary_of_numpy_arrays_to_tensors(sample):
    """Transforms dictionary of numpy arrays to dictionary of tensors."""
    if isinstance(sample, dict):
        return {
            key: dictionary_of_numpy_arrays_to_tensors(value)
            for key, value in sample.items()
        }
    if isinstance(sample, np.ndarray):
        if len(sample.shape) == 2:
            return th.from_numpy(sample).float().unsqueeze(0)
        else:
            return th.from_numpy(sample).float()
    return sample

class EventSequenceToVoxelGrid_Pytorch(object):
    # Source: https://github.com/uzh-rpg/rpg_e2vid/blob/master/utils/inference_utils.py#L480
    def __init__(self, num_bins, gpu=False, gpu_nr=0, normalize=True, forkserver=True):
        if forkserver:
            try:
                th.multiprocessing.set_start_method('forkserver')
            except RuntimeError:
                pass
        self.num_bins = num_bins
        self.normalize = normalize
        if gpu:
            if not th.cuda.is_available():
                print('Warning: There\'s no CUDA support on this machine!')
            else:
                self.device = th.device('cuda:' + str(gpu_nr))
        else:
            self.device = th.device('cpu')

    def __call__(self, event_sequence):
        """
        Build a voxel grid with bilinear interpolation in the time domain from a set of events.
        :param events: a [N x 4] NumPy array containing one event per row in the form: [timestamp, x, y, polarity]
        :param num_bins: number of bins in the temporal axis of the voxel grid
        :param width, height: dimensions of the voxel grid
        :param device: device to use to perform computations
        :return voxel_grid: PyTorch event tensor (on the device specified)
        """

        events = event_sequence.features.astype('float')

        width = event_sequence.image_width
        height = event_sequence.image_height

        assert (events.shape[1] == 4)
        assert (self.num_bins > 0)
        assert (width > 0)
        assert (height > 0)

        with th.no_grad():

            events_torch = th.from_numpy(events)
            # with DeviceTimer('Events -> Device (voxel grid)'):
            events_torch = events_torch.to(self.device)

            # with DeviceTimer('Voxel grid voting'):
            voxel_grid = th.zeros(self.num_bins, height, width, dtype=th.float32, device=self.device).flatten()

            # normalize the event timestamps so that they lie between 0 and num_bins
            last_stamp = events_torch[-1, 0]
            first_stamp = events_torch[0, 0]

            assert last_stamp.dtype == th.float64, 'Timestamps must be float64!'
            # assert last_stamp.item()%1 == 0, 'Timestamps should not have decimals'

            deltaT = last_stamp - first_stamp

            if deltaT == 0:
                deltaT = 1.0

            events_torch[:, 0] = (self.num_bins - 1) * (events_torch[:, 0] - first_stamp) / deltaT
            ts = events_torch[:, 0]
            xs = events_torch[:, 1].long()
            ys = events_torch[:, 2].long()
            pols = events_torch[:, 3].float()
            pols[pols == 0] = -1  # polarity should be +1 / -1

            tis = th.floor(ts)
            tis_long = tis.long()
            dts = ts - tis
            vals_left = pols * (1.0 - dts.float())
            vals_right = pols * dts.float()

            valid_indices = tis < self.num_bins
            valid_indices &= tis >= 0

            if events_torch.is_cuda:
                datatype = th.cuda.LongTensor
            else:
                datatype = th.LongTensor

            voxel_grid.index_add_(dim=0,
                                  index=(xs[valid_indices] + ys[valid_indices]
                                         * width + tis_long[valid_indices] * width * height).type(
                                      datatype),
                                  source=vals_left[valid_indices])

            valid_indices = (tis + 1) < self.num_bins
            valid_indices &= tis >= 0

            voxel_grid.index_add_(dim=0,
                                  index=(xs[valid_indices] + ys[valid_indices] * width
                                         + (tis_long[valid_indices] + 1) * width * height).type(datatype),
                                  source=vals_right[valid_indices])

            voxel_grid = voxel_grid.view(self.num_bins, height, width)

        if self.normalize:
            mask = th.nonzero(voxel_grid, as_tuple=True)
            if mask[0].size()[0] > 0:
                mean = voxel_grid[mask].mean()
                std = voxel_grid[mask].std()
                if std > 0:
                    voxel_grid[mask] = (voxel_grid[mask] - mean) / std
                else:
                    voxel_grid[mask] = voxel_grid[mask] - mean

        return voxel_grid


import os
import math
import cairo_tools as tools
from functools import wraps, partial

import cairo
from glob import glob

import view, main
from model import prefs
from utils import _T, resolve_path

# Defaults for prefs
prefs.add_default('view-toolswheel-binding',
    ['new layer',
     'open layer manager window',
     'save document as',
     'open preferences window',
     'open color manager window',
     'undo',
     'load document',
     'redo'])

# This list uses Higlander icons
prefs.add_default('view-icons-names',
    ['AddLayer_0',
     'Layer_0',
     'Save_0',
     'Prefs_0',
     'Color_0',
     'Undo_0',
     'Open_0',
     'Redo_0',

     'AddLayer_1',
     'Layer_1',
     'Save_1',
     'Prefs_1',
     'Color_1',
     'Undo_1',
     'Open_1',
     'Redo_1'])

ICONS = {}
ALL_CONTEXTS = {}
ALL_EVENT_TYPES = []
EVENT_TAG_REPEAT = 0x40000000
EVENT_TAG_ANY    = 0x80000000

def reload_icons(path):
    for name in glob(os.path.join(resolve_path(path), '*.png')):
        ICONS[os.path.splitext(os.path.basename(name))[0]] = cairo.ImageSurface.create_from_png(name)

reload_icons(prefs['view-icons-path'])

new_context = lambda name, **kwds: ALL_CONTEXTS[name](**kwds)

#===================================================================================
# Commands handling
#

ALL_COMMANDS = {}
def command(name):
    def decorator(func):
        ALL_COMMANDS[name] = func
        return func
    return decorator

#===================================================================================
# Event base classes
#

class MetaEvent(type):
    def __new__(metacl, name, bases, dct):
        cl = type.__new__(metacl, name, bases, dct)
        if dct.pop('NAME', None):
            ALL_EVENT_TYPES.append(cl)
        return cl

    def __str__(cl):
        return cl.NAME

class EventBase(object):
    __metaclass__ = MetaEvent

    repeat = False

    def __str__(self):
        return self.NAME

    @property
    def fullkey(self): pass

    @property
    def key(self):
        return self.fullkey

class SetupEvent(EventBase):
    def __str__(self):
        return 'setup'

    @property
    def fullkey(self):
        return 0x0FFFFFFF

    @classmethod
    def encode(cl, key):
        return 0x0FFFFFFF

class CleanupEvent(EventBase):
    def __str__(self):
        return 'cleanup'

    @property
    def fullkey(self):
        return 0x0FFFFFFE

    @classmethod
    def encode(cl, key):
        return 0x0FFFFFFE

#===================================================================================
# Context base classes and functions
#

def action(name):
    def decorator(func):
        func._act_name = name
        func._act_ctx = None
        return func
    return decorator

class MetaContext(type):
    def __new__(meta, clname, bases, dct):
        cl = type.__new__(meta, clname, bases, dct)
        if clname != 'Context':
            if clname != 'ModalContext':
                ALL_CONTEXTS[dct['NAME']] = cl

            cl.AVAIL_ACTIONS = {}
            cl.BINDINGS = {}

            # Inherit BINDINGS and AVAIL_ACTIONS dicts
            for base in bases:
                if hasattr(base, 'AVAIL_ACTIONS'):
                    cl.AVAIL_ACTIONS.update(base.AVAIL_ACTIONS)

            # Construct a list of all available actions for this context
            actdict = cl.AVAIL_ACTIONS
            for v in dct.itervalues():
                if hasattr(v, '_act_name'):
                    if v in actdict:
                        raise SystemError("Already defined action for context %s: %s" % (clname, v._act_name))
                    v._act_ctx = cl
                    actdict[v._act_name] = v

            cl.AVAIL_ACTION_NAMES = sorted(cl.AVAIL_ACTIONS.keys())
        return cl

    def __init__(cl, clname, bases, dct):
        type.__init__(cl, clname, bases, dct)
        cl.reset_bindings()

class Context(object):
    __metaclass__ = MetaContext

    __parent = None
    __next = None

    def __init__(self, **kwds):
        self._data = kwds
        self.__dict__.update(kwds)

    @classmethod
    def reset_bindings(cl):
        cl.BINDINGS = {0x0FFFFFFF: cl.setup, 0x0FFFFFFE: cl.cleanup}

    @classmethod
    def get_action(cls, event):
        # Search with full key (mods+key)
        name = cls.BINDINGS.get(event.fullkey)
        if not name:
            # Repeat events are not accepted
            name = cls.BINDINGS.get(EVENT_TAG_REPEAT | event.fullkey)
            if not name:
                # Search for key + 'any' mods
                name = cls.BINDINGS.get(EVENT_TAG_ANY | event.key)
                if not name:
                    name = cls.BINDINGS.get(EVENT_TAG_ANY | EVENT_TAG_REPEAT | event.key)
                    if not name:
                        return
        elif event.repeat:
            return

        if callable(name):
            return name

        try:
            return getattr(cls, name)
        except:
            return name

    def process(self, event):
        """process(event) -> eat_state, new_context

        Check if context has action to process for the given event.

        Returns 2-tuple:
            - eat_state is a boolean set to True if the system shall stop the event progression.
            - new_context is the next context to use (could be the same one).
        """

        # Check for action in context itself
        action = self.get_action(event)
        #print "[%s] Event: %s: %s" % (self, event, action)

        # If not found check parent if we're not a modal context
        if not action and not isinstance(self, ModalContext):
            ctx = self
            while not action and ctx.__parent:
                ctx = ctx.__parent
                action = ctx.get_action(event)
        else:
            ctx = self

        if action:
            ctx.__next = self
            eat = not action(ctx, event)
            if ctx.__next != self:
                return eat, ctx.__next
            return eat, self

        return False, self

    def enter_context(self, name, **kwds):
        for k, v in self._data.iteritems():
            kwds.setdefault(k, v)
        self.__next = new_context(name, **kwds)
        self.__next.__parent = self
        self.__next.process(SetupEvent())
        return self.__next

    def exit_context(self):
        self.process(CleanupEvent())
        self.__next = self.__parent
        self.__next.process(SetupEvent())
        return self.__next

    def swap_context(self, name, **kwds):
        self.process(CleanupEvent())
        self.__next = new_context(name, **kwds)
        return self.__next

    def _set_parent(self, ctx):
        self.__parent = ctx

    ## Internal actions

    def setup(self, *a): pass
    def cleanup(self, *a): pass

    # User trigged Actions
    #

    @action(_T('eat event'))
    def eat_event(self, event): pass

class ModalContext(Context):
    def on_confirm(ctx, event): pass

    # User trigged Actions
    #

    @action(_T('confirm'))
    def confirm(ctx, event):
        try:
            ctx.viewport.get_device_state(event)
            cmd = ctx.on_confirm(event)
        finally:
            newctx = ctx.exit_context()

        if cmd in ALL_COMMANDS:
            res = ALL_COMMANDS[cmd](view.app.ctx)
            if res:
                # TODO: horrible trick! change me soon!
                ctx.enter_context(res)._set_parent(newctx)

    @action(_T('cancel'))
    def cancel(ctx, event):
        ctx.exit_context()

    @action(_T('eat event'))
    def eat_event(self, event): pass

#===================================================================================
# Contexts
#

class ApplicationCtx(Context):
    NAME = 'Application'

    @action(_T('new-document'))
    def undo(self, event):
        self.app.mediator.new_document()

    @action(_T('load-document'))
    def undo(self, event):
        self.app.mediator.load_document()

class DocumentCtx(Context):
    NAME = 'Document'

    # User trigged Actions
    #

    @action(_T('save-document'))
    def save_document(self, event):
        self.app.mediator.save_document()

    @action(_T('save-as-document'))
    def save_as_document(self, event):
        self.app.mediator.save_as_document()

    @action(_T('undo'))
    def undo(self, event):
        self.docproxy.sendNotification(main.UNDO)

    @action(_T('redo'))
    def redo(self, event):
        self.docproxy.sendNotification(main.REDO)

    @action(_T('lighten brush color of 10%'))
    def color_lighten(self, event):
        self.docproxy.multiply_color(1.0, 1.0, 1.1)

    @action(_T('darken brush color of 10%'))
    def color_darken(self, event):
        self.docproxy.multiply_color(1.0, 1.0, 0.9)

    @action(_T('saturate brush color of 10%'))
    def color_saturate(self, event):
        self.docproxy.multiply_color(1.0, 1.1, 1.0)

    @action(_T('desaturate brush color of 10%'))
    def color_desaturate(self, event):
        self.docproxy.multiply_color(1.0, 0.9, 1.0)

    @action(_T('clear active layer'))
    def clear_active_layer(self, event):
        self.docproxy.clear_layer(self.docproxy.active_layer)

    @action(_T('toggle rulers visibility'))
    def toggle_rulers(self, event):
        self.window.toggle_rulers()

class ViewPortCtx(Context):
    NAME = 'Viewport'

    _rot_ruler_warn = True

    def __init__(self, **kwds):
        super(ViewPortCtx, self).__init__(**kwds)
        self._text = tools.Text()

    # Internal Actions
    #

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor()

    # User trigged Actions
    #

    @action(_T('activate'))
    def activate(self, event):
        vp = self.viewport
        vp.get_device_state(event)
        vp.show_brush_cursor()
        vp.enable_motion_events()

    @action(_T('desactivate'))
    def desactivate(self, event):
        self.viewport.show_brush_cursor(False)
        self.viewport.enable_motion_events(False)

    @action(_T('move brush cursor'))
    def move_cursor(self, event):
        self.viewport.repaint_cursor(*event.get_cursor_position())

    ## Model modifying actions

    @action(_T('start to stroke or hit handler'))
    def on_selection(self, event):
        handler = self.viewport.get_handler_at_pos(*event.get_cursor_position())
        if handler:
            if handler.kill:
                self.viewport.rem_tool(handler.tool)
            else:
                self.enter_context('Handler', handler=handler)
        else:
            self.viewport.get_device_state(event)
            self.enter_context('Brush Stroke')

    @action(_T('start to drag layer'))
    def start_drag_layer(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Drag Layer')

    @action(_T('start to rotate layer'))
    def start_rotate_layer(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Rotate Layer')

    @action(_T('pick brush color'))
    def get_brush_color(self, event):
        color = self.viewport.get_average_color(*event.get_cursor_position())
        if color:
            self.docproxy.set_brush_color_rgb(*color)

    ## Brush modifying actions

    @action(_T('interactive set max radius'))
    def interactive_radius_max(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Max Radius Interactive')

    @action(_T('interactive set both radius'))
    def interactive_radius(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Both Radius Interactive')

    @action(_T('set erase mode'))
    def set_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(0.0)

    @action(_T('unset erase mode'))
    def unset_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(1.0)

    @action(_T('pick pixel color'))
    def get_pixel_color(self, event):
        color = self.viewport.get_exact_color(*event.get_cursor_position())
        if color:
            self.docproxy.set_brush_color_rgb(*color)

    @action(_T('enter in pick color mode'))
    def enter_pick_mode(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Pick Mode')

    ## View modifying actions

    @action(_T('reset all viewport transformations'))
    def reset_view(self, event):
        vp = self.viewport
        vp.mediator.view_reset(vp, event.get_cursor_position())

    @action(_T('viewport zoom in'))
    def zoom_in(self, event):
        vp = self.viewport
        vp.mediator.view_scale_up(vp, event.get_cursor_position())

    @action(_T('viewport zoom out'))
    def zoom_out(self, event):
        vp = self.viewport
        vp.mediator.view_scale_down(vp, event.get_cursor_position())

    @action(_T('reset viewport zoom'))
    def zoom_reset(self, event):
        vp = self.viewport
        vp.mediator.view_scale_reset(vp, event.get_cursor_position())

    @action(_T('start to drag view'))
    def start_drag_view(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Drag Viewport')

    @action(_T('reset viewport translation'))
    def drag_view_reset(self, event):
        vp = self.viewport
        vp.mediator.view_translate_reset(vp)

    @action(_T('start to rotate view'))
    def start_rotate_view(self, event):
        # Check if rulers are hidden or shown
        # Rulers don't work correctly with a view rotation.
        if self.window.rulers:
            if self._rot_ruler_warn:
                self.docproxy.sendNotification(main.SHOW_WARNING_DIALOG,
                                               "View rotation is not possible when rulers are active.\n"
                                               "The next try will automatically remove them.")
                self._rot_ruler_warn = False
                return

        self.viewport.get_device_state(event)
        self.enter_context('Rotate Viewport')

    @action(_T('reset viewport rotation'))
    def rotate_view_reset(self, event):
        vp = self.viewport
        vp.mediator.view_rotate_reset(vp, event.get_cursor_position())

    @action(_T('swap viewport left-right'))
    def swap_x(self, event):
        vp = self.viewport
        vp.mediator.view_swap_x(vp, event.get_cursor_position()[0])

    @action(_T('swap viewport top-bottom'))
    def swap_y(self, event):
        vp = self.viewport
        vp.mediator.view_swap_y(vp, event.get_cursor_position()[1])

    ## Tools actions

    @action(_T('toggle line guide'))
    def toggle_line_guide(self, event):
        vp = self.viewport
        vp.mediator.toggle_guide(vp, 'line')

    @action(_T('toggle ellipse guide'))
    def toggle_ellipse_guide(self, event):
        vp = self.viewport
        vp.mediator.toggle_guide(vp, 'ellipse')

    @action(_T('show last colors used'))
    def last_colors_selector(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Last Colors Selector')

    @action(_T('show tools selector'))
    def start_tools_selector(self, event):
        self.viewport.get_device_state(event)
        self.enter_context('Tools Selector')

class BrushStrokeModal(ModalContext):
    NAME = 'Brush Stroke'

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)
        vp.docproxy.draw_start(vp.device)

    def cleanup(self, event):
        vp = self.viewport
        vp.docproxy.draw_end()
        vp.unlock_focus()

    # User trigged Actions
    #

    @action(_T('draw at cursor'))
    def draw(self, event):
        self.viewport.docproxy.record(self.viewport.get_device_state(event))

    @action(_T('set erase mode'))
    def set_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(0.0)

    @action(_T('unset erase mode'))
    def unset_erase_mode(self, event):
        self.docproxy.drawbrush.set_erase(1.0)

class DragViewModal(ModalContext):
    NAME = 'Drag Viewport'

    def __init__(self, **kwds):
        super(DragViewModal, self).__init__(**kwds)
        self._text = tools.Text()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._cpos = vp.device.current.cpos
        self._x = 0
        self._y = 0
        self._text.set_text("Dx=%-4u, Dy=%-4u" % (0,0))

        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()
        vp.rem_tool(self._text)
        vp.enable_fast_filter(False)
        vp.repaint()

    # User trigged Actions
    #

    @action(_T('drag view'))
    def drag_view(self, event):
        vp = self.viewport

        # Compute cursor delta's
        cpos = event.get_cursor_position()
        dx = cpos[0] - self._cpos[0]
        dy = cpos[1] - self._cpos[1]
        self._x += dx
        self._y += dy
        self._cpos = cpos

        # update display
        self._text.set_text("Dx=%-4u, Dy=%-4u" % (self._x, self._y))
        vp.repaint_tools(clip=self._text.area)
        vp.scroll(dx, dy)

class RotateViewModal(ModalContext):
    NAME = 'Rotate Viewport'

    _rot = tools.Rotate()
    _text = tools.Text()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._angle = 0.
        self._rot.set_cursor_pos(vp.device.current.cpos)
        self._text.set_text("Angle: 0")

        vp.add_tool(self._rot)
        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()

        vp.rem_tool(self._rot)
        vp.rem_tool(self._text)

        vp.enable_fast_filter(False)
        vp.repaint()

    @action(_T('rotate view'))
    def rotate_view(self, event):
        vp = self.viewport

        self._rot.set_cursor_pos(event.get_cursor_position())
        self._angle = (self._angle + self._rot.dr) % (2*math.pi)
        self._text.set_text("Angle: %u" % math.degrees(self._angle))

        vp.repaint_tools()
        vp.rotate(-self._rot.dr)

class LastColorModal(ModalContext):
    NAME = 'Last Colors Selector'

    _colors = [ None ] * 8

    def __init__(self, **kwds):
        super(LastColorModal, self).__init__(**kwds)
        self._tool = tools.ColorWheel()
        self.push_color(self.viewport.docproxy.get_brush_color_rgb())

    @classmethod
    def push_color(cl, rgb):
        if rgb != cl._colors[0]:
            cl._colors.insert(0, rgb)
            cl._colors.pop(-1)

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor(False)
        self._tool.set_colors(self._colors)
        self._tool.set_center(vp.device.current.cpos)
        vp.add_tool(self._tool)

    def cleanup(self, event):
        self.viewport.rem_tool(self._tool)

    def on_confirm(self, event):
        i = self._tool.selection
        if i >= 0:
            # Slice the historic and put the selected color as first
            rgb = self._colors.pop(i)
            self._colors.insert(0, rgb)
            self.viewport.docproxy.set_brush_color_rgb(*rgb)

    # User trigged Actions
    #

    @action(_T('check cursor position'))
    def check_cursor(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        if vp.is_tool_hit(self._tool, *cpos):
            # TODO: CPU eating when pen used
            self._tool.cpos = cpos
        elif self._tool.cpos:
            self._tool.cpos = None
        else:
            return

        vp.repaint_tools(self._tool.area)
        vp.redraw(self._tool.area)

class ToolsModal(ModalContext):
    NAME = 'Tools Selector'

    _sel = -1

    def __init__(self, **kwds):
        super(ToolsModal, self).__init__(**kwds)
        self._tool = tools.ToolsWheel()
        self.refresh()

    def refresh(self):
        icons = []
        for name in prefs['view-icons-names']:
            icons.append(ICONS[name])
        self._tool.set_icons(icons)

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor(False)
        self._tool.set_center(vp.device.current.cpos)
        vp.add_tool(self._tool)

    def cleanup(self, event):
        self.viewport.rem_tool(self._tool)

    def on_confirm(self, event):
        i = self._tool.selection
        if i >= 0:
            return prefs['view-toolswheel-binding'][i]

    # User trigged Actions
    #

    @action(_T('check cursor position'))
    def check_cursor(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        if vp.is_tool_hit(self._tool, *cpos):
            # TODO: CPU eating when pen used
            self._tool.cpos = cpos
        elif self._tool.cpos:
            self._tool.cpos = None
        else:
            return

        vp.repaint_tools(self._tool.area)
        vp.redraw(self._tool.area)

class SetMaxRadiusModal(ModalContext):
    NAME = 'Max Radius Interactive'

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        self._cpos = self._first_cpos = vp.show_brush_cursor()

    def cleanup(self, event):
        self.viewport.unlock_focus()

    # User trigged Actions
    #

    @action(_T('resize brush'))
    def resize_brush(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        dr = self._cpos[1] - cpos[1]
        vp.docproxy.add_brush_radius_max(dr*.25)
        vp.repaint_cursor(*self._first_cpos)
        self._cpos = cpos

class SetBothRadiusModal(ModalContext):
    NAME = 'Both Radius Interactive'

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        self._cpos = self._first_cpos = vp.show_brush_cursor()

    def cleanup(self, event):
        self.viewport.unlock_focus()

    # User trigged Actions
    #

    @action(_T('resize brush'))
    def resize_brush(self, event):
        vp = self.viewport
        cpos = event.get_cursor_position()
        dr = self._cpos[1] - cpos[1]
        vp.docproxy.add_brush_radius(dr*.25)
        vp.repaint_cursor(*self._first_cpos)
        self._cpos = cpos

class DragLayerModal(ModalContext):
    NAME = 'Drag Layer'

    def __init__(self, **kwds):
        super(DragLayerModal, self).__init__(**kwds)
        self._text = tools.Text()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._old_mat = cairo.Matrix(*self.docproxy.document.active.matrix)
        self._cpos = vp.device.current.cpos
        self._x = 0
        self._y = 0
        self._text.set_text("Dx=%-4u, Dy=%-4u" % (0,0))

        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()
        vp.rem_tool(self._text)
        vp.enable_fast_filter(False)
        vp.repaint()

    def on_confirm(self, event):
        docproxy = self.viewport.docproxy
        layer = docproxy.active_layer
        docproxy.record_layer_matrix(layer, self._old_mat)

    # User trigged Actions
    #

    @action(_T('drag layer'))
    def drag_layer(self, event):
        vp = self.viewport
        tool = self._text

        # Compute cursor delta's
        cpos = event.get_cursor_position()
        dx = cpos[0] - self._cpos[0]
        dy = cpos[1] - self._cpos[1]
        self._x += dx
        self._y += dy
        self._cpos = cpos

        # update display
        tool.set_text("Dx=%-4u, Dy=%-4u" % (self._x, self._y))
        vp.repaint_tools(tool.area, redraw=True)
        vp.docproxy.layer_translate(*vp.get_model_distance(dx, dy))

class RotateLayerModal(ModalContext):
    NAME = 'Rotate Layer'

    def __init__(self, **kwds):
        super(RotateLayerModal, self).__init__(**kwds)
        self._text = tools.Text()
        self._rot = tools.Rotate()

    def setup(self, event):
        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

        self._old_mat = cairo.Matrix(*self.docproxy.document.active.matrix)
        pos = vp.width/2, vp.height/2
        pos = vp.get_model_point(*pos)
        self._ro = vp.docproxy.get_layer_pos(*pos)

        self._angle = 0.
        self._rot.set_cursor_pos(vp.device.current.cpos)
        self._text.set_text("Angle: 0")

        vp.add_tool(self._rot)
        vp.add_tool(self._text)
        vp.enable_fast_filter()

    def cleanup(self, event):
        vp = self.viewport
        vp.unlock_focus()
        vp.rem_tool(self._rot)
        vp.rem_tool(self._text)

        # Force fine display
        vp.enable_fast_filter(False)
        vp.repaint()

    def on_confirm(self, event):
        docproxy = self.viewport.docproxy
        layer = docproxy.active_layer
        docproxy.record_layer_matrix(layer, self._old_mat)

    # User trigged Actions
    #

    @action(_T('rotate Layer'))
    def rotate_Layer(self, event):
        vp = self.viewport

        self._rot.set_cursor_pos(event.get_cursor_position())
        self._text.set_text("Angle: %u" % math.degrees(self._angle))

        # update display
        vp.repaint_tools(self._text.area, redraw=True)
        vp.repaint_tools(self._rot.area, redraw=True)
        vp.docproxy.layer_rotate(-self._rot.dr, *self._ro)

        self._angle = (self._angle + self._rot.dr) % (2*math.pi)

class HandlerModal(ModalContext):
    NAME = 'Handler'

    def setup(self, event):
        assert hasattr(self, 'handler')

        vp = self.viewport
        vp.lock_focus()
        vp.enable_motion_events()
        vp.show_brush_cursor(False)

    def cleanup(self, event):
        self.viewport.unlock_focus()

    # User trigged Actions
    #

    @action(_T('cursor move'))
    def cursor_move(self, event):
        hl = self.handler
        tool = hl.tool
        tool.move_handler(hl, *event.get_cursor_position())

        # Clear old and draw new position
        self.viewport.repaint_tools(tool.area, redraw=True)
        self.viewport.repaint_tools(tool.area, redraw=True)

class PickModal(ModalContext):
    NAME = 'Pick Mode'

    def __init__(self, **kwds):
        super(PickModal, self).__init__(**kwds)

    def setup(self, event):
        vp = self.viewport
        vp.enable_motion_events()
        vp.show_brush_cursor(True)
        vp.pick_mode(True)

    def cleanup(self, event):
        self.viewport.pick_mode(False)

    def on_confirm(self, event):
        color = self.viewport.get_exact_color(*event.get_cursor_position())
        if color:
            self.docproxy.set_brush_color_rgb(*color)

    # User trigged Actions
    #

    @action(_T('move brush cursor'))
    def move_cursor(self, event):
        self.viewport.repaint_cursor(*event.get_cursor_position())


from datetime import datetime

def fabricar_leilao(cur, id_, descricao='teste', criador='c153c124-7daa-4328-8f04-1dd824f5c309', data=None, diferenca_minima=100):
  cur.execute(f"""
    insert into leiloes (id, descricao, criador, data, diferenca_minima)
    values (%s, %s, %s, %s, %s)
  """, (
    id_,
    descricao,
    criador,
    data if data is not None else datetime.now(),
    diferenca_minima
  ))

def fabricar_lance(cur, id_, id_leilao, comprador='8f1061a8-a687-436a-8b1b-7a302994474a', valor=100, data=None):
  cur.execute(f"""
    insert into lances (id, id_leilao, comprador, valor, data)
    values (%s, %s, %s, %s, %s)
  """, (
    id_,
    id_leilao,
    comprador,
    valor,
    data if data is not None else datetime.now()
  ))


import gzip
import struct
from pathlib import Path

from ..utils.reader_utils import *  # noqa:F403

class User:
    def __init__(self, user_id, username, birthdate, gender):
        self.user_id = user_id
        self.username = username
        self.birthdate = birthdate
        self.gender = gender

    def __str__(self):
        return f"ID: {self.user_id}, username: {self.username}, \
         age: {self.birthdate}, gender: {self.gender}"

class Snapshot:
    def __init__(self, timestamp, translation, rotation, color_image,
                 depth_image, user_feelings):
        self.datetime = timestamp
        self.translation = translation
        self.rotation = rotation
        self.color_image = color_image
        self.depth_image = depth_image
        self.user_feelings = user_feelings

class ReaderImage:
    '''img_type- 'd' (for depth) or 'c' (for color)'''
    def __init__(self, width, height, vals, img_type):
        self.height = height
        self.width = width
        self.data = vals
        self.img_type = img_type

class UserFeelings:
    """
    4 floats between -1 and 1 representing the feelings.
    """
    def __init__(self, hunger, thirst, exhaustion, happiness):
        self.hunger = hunger
        self.thirst = thirst
        self.exhaustion = exhaustion
        self.happiness = happiness

class Reader:
    """
    An implementation of the reader for files in binary format.
    For full documentation on the functions, see the main Reader class.
    """
    def __init__(self, path, zipped=True):
        self.offset = 0
        self.path = Path(path)
        if zipped:
            self.open_func = lambda p: gzip.open(p, 'rb')
        else:
            self.open_func = lambda p: open(p, 'rb')

    def read_user(self):
        with (self.open_func)(self.path) as file:
            user_id = unpack_format(file, '<Q')
            username_length = unpack_format(file, '<L')
            username = unpack_string(file, username_length)
            birthdate = unpack_format(file, '<L')
            gender = unpack_format(file, 'c')
            self.offset = file.tell()

        return User(user_id, username, birthdate, gender)

    # returns the next snapshot
    def read_snapshot(self):
        with (self.open_func)(self.path) as file:
            file.seek(self.offset)

            timestamp = unpack_format(file, '<Q')
            translation = unpack_format(file, 'ddd')
            rotation = unpack_format(file, 'dddd')

            c_height = unpack_format(file, '<L')
            c_width = unpack_format(file, '<L')
            c_vals = file.read(c_height*c_width*3)
            color_image = ReaderImage(c_width, c_height, c_vals, 'c')

            d_height = unpack_format(file, '<L')
            d_width = unpack_format(file, '<L')
            d_vals = file.read(d_height*d_width*struct.calcsize('f'))
            depth_image = ReaderImage(d_width, d_height, d_vals, 'd')

            hunger, thirst, exaustion, happiness = unpack_format(file, 'ffff')
            user_feelings = UserFeelings(hunger, thirst, exaustion, happiness)

            self.offset = file.tell()

            snap = Snapshot(timestamp, translation, rotation, color_image, \
                            depth_image, user_feelings)
        return snap


# import os

from flask import Flask, request, abort, jsonify
# from flask_sqlalchemy import SQLAlchemy  # , or_
from flask_cors import CORS
# import random

from backend.models import setup_db, Book, db

BOOKS_PER_SHELF = 8

# @TODO: General Instructions
#   - As you're creating endpoints, define them and then search for 'TODO' within the frontend to update the
#    endpoints there. If you do not update the endpoints, the lab will not work - of no fault of your API code!
#   - Make sure for each route that you're thinking through when to abort and with which kind of error
#   - If you change any of the response body keys, make sure you update the frontend to correspond.

def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)
    CORS(app)

    # CORS Headers
    @app.after_request
    def after_request(response):
        response.headers.add(
            "Access-Control-Allow-Headers", "Content-Type,Authorization,true"
        )
        response.headers.add(
            "Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS"
        )
        return response

    @app.route("/books", methods=['GET'])
    def get_books():
        page = request.args.get("page", 1, type=int)
        start = (page - 1) * BOOKS_PER_SHELF
        end = start + BOOKS_PER_SHELF

        books = Book.query.filter().order_by("id")
        formatted_books = [book.format() for book in books]

        return jsonify(
            {
                "success": True,
                "books": formatted_books[start:end],
                "total_books": len(formatted_books),
            }
        )

    # @TODO: Write a route that will update a single book's rating.
    #         It should only be able to update the rating, not the entire representation
    #         and should follow API design principles regarding method and route.
    #         Response body keys: 'success'
    # TEST: When completed, you will be able to click on stars to update a book's rating and it will persist after
    # refresh
    @app.route("/books/<int:book_id>", methods=["PATCH"])
    def update_book_rating(book_id):
        book = Book.query.filter(Book.id == book_id).one_or_none()
        data = request.get_json()
        rating = data.get("rating", None)
        error = False
        response = {"success": True}
        try:
            book.rating = rating
            book.update()
        except Exception as e:
            book.revert_changes()
            error = True
            print(e)
        finally:
            db.session.close()
            if not error:
                response["success"] = True
            else:
                response["success"] = False
        return jsonify(response)

    # @TODO: Write a route that will delete a single book.
    #        Response body keys: 'success', 'deleted'(id of deleted book), 'books' and 'total_books'
    #        Response body keys: 'success', 'books' and 'total_books'

    # TEST: When completed, you will be able to delete a single book by clicking on the trashcan.
    @app.route("/books/<int:book_id>", methods=["DELETE"])
    def delete_book(book_id):
        page = request.args.get("page", 1, type=int)
        start = (page - 1) * BOOKS_PER_SHELF
        end = start + BOOKS_PER_SHELF

        books = Book.query.filter().order_by("id")
        formatted_books = [book.format() for book in books]

        book = Book.query.filter(Book.id == book_id).one_or_none()
        error = False
        response = {
            "success": False,
            "books": formatted_books[start:end],
            "total_books": len(formatted_books)
        }
        try:
            book.delete()
        except Exception as e:
            book.revert_changes()
            error = True
            print(e)
        finally:
            db.session.close()
            if not error:
                response["success"] = True
                response["deleted"] = book_id
        return jsonify(response)

    # @TODO: Write a route that create a new book.
    #        Response body keys: 'success', 'created'(id of created book), 'books' and 'total_books'
    # TEST: When completed, you will be able to a new book using the form. Try doing so from the last page of books.
    #       Your new book should show up immediately after you submit it at the end of the page.

    return app


from sklearn.impute import SimpleImputer
from sklearn.metrics import confusion_matrix as cm
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
from sklearn.metrics import (accuracy_score, f1_score, recall_score, precision_score,
                             classification_report, make_scorer, balanced_accuracy_score,
                             precision_recall_curve, mean_squared_error, roc_auc_score,
                             roc_curve, auc, r2_score, mean_absolute_error,
                             average_precision_score, explained_variance_score)
from sklearn.preprocessing import  OneHotEncoder
from sklearn.multiclass import OneVsRestClassifier, OneVsOneClassifier, OutputCodeClassifier
from sklearn.calibration import CalibratedClassifierCV

from scipy.stats import pearsonr, stats
from scipy.sparse import hstack, vstack
import joblib
from joblib import Parallel, delayed
import os
import numpy as np
import pandas as pd
import re
pd.set_option('display.max_rows', 100000)
pd.set_option('display.max_columns', 100000)
pd.set_option('display.width', 100000)

from .MLOpenWrite import OpenM, Openf
from .MLEstimators import ML
from .MLPlots import ClusT, ROCPR, MPlot
from .MLUtilities import _predict_proba_lr, CrossvalidationSplit, Check_Label, Check_Binar

class Baseinit:
    def __init__(self, arg, log, score= None , MClass=2, Y_name='Group', model='XGB', Type='C', *array, **dicts):
        self.arg = arg
        self.log = log
        self.array = array
        self.score = score
        self.model = model
        self.dicts = dicts
        self.Type  = Type
        self.MClass= MClass
        self.Y_name= Y_name
class Processing(Baseinit):
    def CVSplit(self, Xdf, Ydf, CVt='SSA', random_state = None ):
        all_test = []
        all_split= []
        if self.arg.crossV ==1:
            all_split = [ [range(Xdf.shape[0]), range(Xdf.shape[0])] ]
        else:
            CVS = CrossvalidationSplit(n_splits=self.arg.crossV, test_size=self.arg.testS, CVt=CVt  , n_repeats=2, leavP=self.arg.leavP )
            SFA = CrossvalidationSplit(n_splits=self.arg.crossV, test_size=self.arg.testS, CVt='SFA', n_repeats=2, leavP=self.arg.leavP )
            for train_index, test_index in CVS.split(Xdf, Ydf):
                all_test.extend( test_index )
                all_split.append( [train_index.tolist(), test_index.tolist()])

            if CVt == 'SSA':
                if len(set(all_test))< len(Ydf):
                    all_add = [ [tr.tolist(), te.tolist()] for tr, te in SFA.split(Xdf, Ydf)]
                    all_split += all_add
        return(all_split)

    def Pdecorator(_func):
        def wrapper(self, *args, **kargs):
            if self.Type=='C':
                self.SSS = CrossvalidationSplit(n_splits=9, test_size=self.arg.GStestS, CVt='SSS')
            elif self.Type=='R':
                self.SSS = CrossvalidationSplit(n_splits=3, n_repeats= 3, CVt='RSKF')
            else:
                self.SSS = ''

            if 'Model'in kargs:
                self.model = kargs['Model']
                self.estimator =  ML(self.model, Type=self.Type).GetPara().estimator
                if self.arg.SearchCV:
                    self.parameters = ML(self.model, Type=self.Type, SearchCV=self.arg.SearchCV ).GetPara().parameters
                else:
                    self.parameters = {}
            return _func(self, *args, **kargs)
        return wrapper

    def Hyperparemet(self, X_train, X_test, y_train, y_test):
        self.log.CIF( 'hyperparameter optimization in the %s model......'%self.model )
        if ( self.MClass >2 ) & (self.model in ['XGB']):
            self.estimator = self.estimator.set_params(objective='multi:softprob')

        if self.model in ['XGB']:
            _n_jobs = 20
            if 'scale_pos_weight' in self.parameters.keys():
                pos_weight = y_train.value_counts(normalize=True)
                self.parameters['scale_pos_weight'] += ( (1-pos_weight)/pos_weight ).to_list()
                self.parameters['scale_pos_weight']  = list(set( self.parameters['scale_pos_weight'] ))
        else:
            _n_jobs = self.arg.n_job

        ## add hyperopt Spearmint hyperparameter
        if not self.arg.SearchCV:
            clf = self.estimator
            self.log.CIF( 'decrepate hyperparameter optimization......' )
        elif self.arg.SearchCV == 'GSCV':
            clf = GridSearchCV(self.estimator, self.parameters,
                               n_jobs=_n_jobs,
                               cv=self.SSS,
                               scoring=self.score,
                               error_score = np.nan,
                               return_train_score=True,
                               refit = True)
            self.log.CIF( 'GSCV hyperparameter optimization......')
        elif self.arg.SearchCV == 'RSCV':
            clf = RandomizedSearchCV(self.estimator, self.parameters,
                                     n_jobs=_n_jobs,
                                     cv=self.SSS,
                                     n_iter = self.arg.n_iter,
                                     scoring=self.score,
                                     return_train_score=True,
                                     refit = True,
                                     error_score='raise')
            self.log.CIF( 'RSCV hyperparameter optimization......')

        if self.model in ['XGB_']:
            clf.fit(X_train, y_train,
                    #eval_metric=["error", "logloss"],
                    #eval_set=[(X_train, y_train), (X_test, y_test)],
                    eval_set=[(X_test, y_test)],
                    eval_metric= 'auc',
                    early_stopping_rounds=15,
                    verbose=False)
        else:
            clf.fit(X_train, y_train)

        if hasattr(clf, 'best_estimator_'):
            self.log.CIF( '%s best parameters in %s: \n%s' %(self.model, self.arg.SearchCV, clf.best_estimator_.get_params()) )
            return clf.best_estimator_
        else:
            self.log.CIF( '%s best parameters: \n%s' %(self.model, clf.get_params()) )
            return clf

    def Featurescoef(self, clf, index_=None):
        if self.model in ['MNB','BNB'] :
            importances= np.exp(clf.coef_)
            self.log.CWA('Note: Use coef_ exp values as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['CNB'] :
            if self.MClass ==2:
                importances= np.exp(-clf.feature_log_prob_)[1]
            else:
                importances= np.exp(-clf.feature_log_prob_)
            self.log.CWA('Note: Use feature_log_prob_ negative exp values as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['GNB'] :
            if self.MClass ==2:
                importances= clf.theta_[1]
            else:
                importances= clf.theta_
            self.log.CWA('Note: Use theta_ values as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['MLP'] :
            def collapse(coefs):
                Coefs = coefs[0]
                for b in coefs[1:]:
                    Coefs = Coefs.dot(b)
                return(Coefs/Coefs.sum(0))
            importances = collapse(clf.coefs_).T
            self.log.CWA('Note: Use coefs_ weighted average as the feature importance of the estimator %s.'%self.model)
        elif self.model in ['SVM', 'SVMrbf', 'nuSVMrbf']:
            dot_coef_ = clf.dual_coef_.dot( clf.support_vectors_ )
            importances = (1-np.exp(-dot_coef_)) / (1+np.exp(-dot_coef_))
            self.log.CWA('Note: Use exp dot of support_vectors_ and dual_coef_ values as the feature importance of the estimator %s.'%self.model)
        else:
            for i in ['feature_importances_', 'coef_']:
                try:
                    importances= eval('clf.%s'%i)
                    self.log.CWA('Note: Use %s as the feature importance of the estimator %s.'%(i,self.model))
                    break
                except AttributeError:
                    importances = []
                    self.log.CWA('Note: Cannot find the feature importance attributes of estimator %s.'%i)

        df_import = pd.DataFrame(np.array(importances).T)
        if not df_import.empty :
            df_import.index=index_
            df_import = df_import[(df_import != 0).any(1)]
        return df_import

    def OneHot(self, _clf, _X_Data, _OHE='N'):
        if  self.model in ['GBDT']:
            _X_Trans = _clf.apply(_X_Data)[:,:,0]
        elif self.model in ['XGB', 'RF']:
            _X_Trans = _clf.apply(_X_Data)
        if _OHE == 'N':
            _OHE = OneHotEncoder(categories='auto')
            _OHE.fit(_X_Trans)
        _X_Trans = _OHE.transform( _X_Trans.astype(np.int32) )
        return [_X_Trans, _OHE]

    def GetPredt_C(self, _clf, X_matrix, y_label=None, mclass=False):
        if y_label:
            _clf.fit(X_matrix, y_label)

        _predict = _clf.predict(X_matrix)
        try:
            _proba = _clf.predict_proba(X_matrix)
        except AttributeError:
            _proba = _clf._predict_proba_lr(X_matrix)
            self.log.CWA('Note: LinearSVC, SGB use _predict_proba_lr based on decision_function as predict_proba in GridsearchCV.')
        except:
            _proba = _predict_proba_lr( _clf.decision_function(X_matrix) )
            self.log.CWA('predict_proba use sigmoid transversion based on decision_function!')

        if (mclass & mclass != _proba.shape[1]):
            raise Exception('The columns length of predict probability is wrong!')
        return np.c_[_predict, _proba]

    def GetEvalu_C(self, y_true, y_predict, y_score, name=None):
        y_trueb = Check_Binar(y_true)

        Model_ = pd.Series({
                    'Accuracy'  : accuracy_score(y_true, y_predict),
                    'Accuracy_B': balanced_accuracy_score(y_true, y_predict),
                    'F1_score'  : f1_score(y_true, y_predict),
                    'Precision' : precision_score(y_true, y_predict),
                    'Recall'    : recall_score(y_true, y_predict),
        })
        Model_['Roc_auc'] = round(roc_auc_score(y_trueb, y_score), 6)
        Model_['Precision_A'] = round(average_precision_score( y_trueb, y_score), 6)

        if y_score.shape[1] > 2:
            for i in range(y_score.shape[1]):
                Model_['Roc_auc_' + str(i)] = round(roc_auc_score(y_trueb[:,i], y_score[:, i]), 6)
                Model_['Precision_A_' + str(i)] = round(average_precision_score( y_trueb[:, i], y_score[:, i]), 6)

        #Report = classification_report(y_true=y_true, y_pred=y_predict, output_dict=False)
        Model_.name = name
        return Model_.sort_index()

    def GetSplit(self, trprpr, label=None):
        _m = [re.sub('^Pred','', _i) for _i in trprpr.columns if re.match('Pred', _i)]
        return pd.concat([ self.GetEvalu_C(trprpr['TRUE'],
                                trprpr['Pred'+_j],
                                trprpr[sorted([_n for _n in trprpr.columns if re.search('Prob'+_j, _n)])],
                                name= label + _j)
                                for _j in _m
                        ], axis=1)

    def GetScore_C(self, train_pre, test_pre):
        return pd.concat( (self.GetSplit(train_pre, label='Train'),
                            self.GetSplit(test_pre, label='Test')), axis=1)

    @Pdecorator
    def GetFit_C(self, X_train, X_test, y_train, y_test, Model=None):
        clf_G = self.Hyperparemet(X_train, X_test, y_train, y_test)

        clf_C = CalibratedClassifierCV(clf_G, cv=self.SSS, method=self.arg.calibme)
        clf_C.fit(X_train, y_train)

        try:
            X_ = pd.concat( (X_train, X_test), axis=0)
        except TypeError:
            X_ = vstack( (X_train, X_test) )

        y_ = pd.concat((y_train, y_test), axis=0)

        G_prepro = self.GetPredt_C(clf_G, X_, mclass=self.MClass)
        C_prepro = self.GetPredt_C(clf_C, X_, mclass=self.MClass)

        Pre_Pro = pd.DataFrame( np.c_[y_, G_prepro, C_prepro], index=y_.index)
        Pre_Pro.columns = ['TRUE', 'Pred_%s'%self.model]+ ['%s_Prob_%s'%(x, self.model)  for x in range(self.MClass) ] + \
                                ['Pred_C_%s'%self.model] + ['%s_Prob_C_%s'%(x, self.model) for x in range(self.MClass) ]

        return { 'clf_G':clf_G, 'clf_C':clf_C, 'Pre_Pro' : Pre_Pro }

    def LearNing_C(self, X_train, X_test, y_train, y_test):
        MODEL = self.GetFit_C(X_train, X_test, y_train, y_test, Model = self.arg.model)

        clf_G = MODEL['clf_G']
        clf_C = MODEL['clf_C']
        Pre_Pro = MODEL['Pre_Pro']
        FeaCoef = self.Featurescoef(clf_G, index_=X_train.columns)

        Best_MD = [ {'model': self.arg.model     , 'clf': clf_G, 'features': X_train.columns.tolist() },
                    {'model': 'C_'+self.arg.model, 'clf': clf_C, 'features': X_train.columns.tolist() },]

        if (self.arg.model in ['GBDT', 'XGB', 'RF']) and (self.arg.Addmode !='N'):
            X_train_N, OHE = self.OneHot(clf_G, X_train)
            X_test_N , OHE = self.OneHot(clf_G, X_test, OHE)

            MODEL_A = self.GetFit_C( X_train_N, X_test_N, y_train, y_test, Model= self.arg.Addmode )
            Pre_ProA = MODEL_A['Pre_Pro'].iloc[:,1:]
            Pre_Pro = pd.concat([Pre_Pro, Pre_ProA], axis=1)

            Best_MD +=[ {'model': self.arg.Addmode     , 'clf': MODEL_A['clf_G'], 'leaf': OHE, 'features': X_train.columns.tolist() },
                        {'model': 'C_'+self.arg.Addmode, 'clf': MODEL_A['clf_C'], 'leaf': OHE, 'features': X_train.columns.tolist() },]

        if len(y_test)>2:
            Test_Mel = self.GetScore_C(Pre_Pro.loc[y_train.index], Pre_Pro.loc[y_test.index])
        else:
            Test_Mel = pd.DataFrame()

        return (Pre_Pro.loc[y_test.index], FeaCoef, Test_Mel, Best_MD)

    def Predicting_C(self,Best_Model,  pDFall, _X_names, _Y_name):
        Y_TRUE  = pDFall[_Y_name].to_frame(name= 'TRUE')
        Y_PRED , Y_Eval = [], []
        for _k, _cv in enumerate(Best_Model):
            Y_pred = [Y_TRUE]
            for _i, _m in enumerate(_cv):
                _mod = _m['model']
                clf_ = _m['clf']
                _Xft = _m['features']

                X_Pred = pDFall[_Xft]
                if 'leaf' in _m.keys():
                    leaf = _m['leaf']
                    X_Pred, _ = self.OneHot(_cv[0]['clf'], X_Pred, leaf)

                _prepro  = self.GetPredt_C(clf_, X_Pred, mclass=self.MClass)

                _prepro = pd.DataFrame( _prepro,
                                        index=pDFall.index,
                                        columns = ['Pred_%s'%_mod] + ['%s_Prob_%s'%(x, _mod) for x in range(self.MClass) ]
                                    )
                Y_pred.append(_prepro)

            Y_pred  = pd.concat( Y_pred, axis=1 )
            Y_predv = Y_pred[ ~Y_pred['TRUE'].isna() ]

            self.log.CIF( ('%s %s Model Predicting Parameters'% (_Y_name, self.arg.model)).center(45, '-') )
            if Y_predv.shape[0] > 2:
                Pred_Mel = self.GetSplit(Y_predv, label='Predict')
                self.log.CIF( "%s Modeling evaluation: \n%s" %(self.arg.model, Pred_Mel) )
            else:
                Pred_Mel = pd.DataFrame()
            self.log.CIF( ('Completed %2d%%'% ((_k+1)*100/len(Best_Model))).center(45, '-') )

            Y_PRED.append(Y_pred)
            Y_Eval.append(Pred_Mel)

        return (Y_PRED, Y_Eval)

    def FeatCoeffs(self, All_import, _Y_name, Xg):
        if All_import:
            All_import = pd.concat(All_import, axis=1,sort=False).fillna(0)
            column = sorted(set(All_import.columns))
            All_import = All_import[column]
            for i in column:
                All_import['%s_mean'%i]  = All_import[i].mean(axis=1)
                All_import['%s_std'%i]   = All_import[i].std(axis=1)
                All_import['%s_median'%i]= All_import[i].median(axis=1)
            All_import.sort_values(by=['%s_mean'%i for i in column], ascending=[False]*len(column), inplace=True, axis=0)

            Openf('%s%s_Class_features_importance.xls' %(self.arg.output, _Y_name), (All_import)).openv()
            MPlot('%s%s_Class_Features_importance.lines.pdf' %(self.arg.output, _Y_name)).Feature_Import_line( All_import, self.arg.model, _Y_name )
            MPlot('%s%s_Class_Features_importance.boxI.pdf'  %(self.arg.output, _Y_name)).Feature_Import_box( All_import, Xg, _Y_name, self.arg.model, sort_by_group=False )
            MPlot('%s%s_Class_Features_importance.boxII.pdf' %(self.arg.output, _Y_name)).Feature_Import_box( All_import, Xg, _Y_name, self.arg.model, sort_by_group=True)

    def ModelScore(self, All_evluat, _Y_name, label='Test'):
        if All_evluat:
            All_pvalues = pd.concat(All_evluat,  axis=0)
            Openf('%s%s_Class_%s_metrics_pvalues.xls'%(self.arg.output, _Y_name, label), (All_pvalues), index=True, index_label='Score').openv()

            All_pvalues['Score'] = All_pvalues.index
            MPlot('%s%s_Class_%s_metrics_scores.pdf'%(self.arg.output, _Y_name, label)).EvaluateCV( All_pvalues, 'Score',  All_pvalues.columns.drop('Score'))

    def CVMerge(self, All_test_pd, DFall, _X_names, _Y_name, Xg, label='Test'):
        All_test_ = pd.concat(All_test_pd,axis=0)

        _model = [re.sub('^Pred_','', _i) for _i in All_test_.columns if re.match('Pred_.*', _i)]
        All_Prob_mean = All_test_.filter(regex=("_Prob_")).groupby([All_test_.index]).mean()
        All_Prob_mean.columns +=  '_mean'
        All_Prob_median = All_test_.filter(regex=("_Prob_")).groupby([All_test_.index]).median()
        All_Prob_median.columns += '_median'
        All_Pred =  All_test_.filter(regex=("^TRUE|^Pred_")).groupby([All_test_.index]).apply(lambda x : x.mode(0).loc[0,:])
        All_Pred.columns = [ i + '_mode' if i !='TRUE' else i for i in All_Pred.columns ]

        def pred_(All_Pb_, All_Pred):
            _m = All_Pb_.columns.str.replace('.*_Prob','Prob').drop_duplicates(keep='first')
            for _x in _m:
                All_Pred[_x.replace('Prob','Pred') ] = All_Pb_.filter(regex=_x, axis=1).values.argmax(1)
            return All_Pred

        All_Pred = pred_(All_Prob_mean, All_Pred)
        All_Pred = pred_(All_Prob_median, All_Pred)

        ALL_Result  = pd.concat([All_Pred, All_Prob_mean, All_Prob_median], axis=1)

        Openf('%s%s_Class_%s_detials.xls'%(self.arg.output, _Y_name, label), (All_test_), index=True, index_label='sample').openv()
        Openf('%s%s_Class_%s_summary.xls'%(self.arg.output, _Y_name, label), (ALL_Result), index=True, index_label='sample').openv()
        ClusT('%s%s_Class_%s_Feature.Data_complete.pdf'%(self.arg.output, _Y_name, label) ).Plot_heat( DFall[_X_names], ALL_Result.filter(regex=("^TRUE|^Pred_.*_mean")), Xg, method='complete')
        ClusT('%s%s_Class_%s_Feature.Data_average.pdf' %(self.arg.output, _Y_name, label) ).Plot_heat( DFall[_X_names], ALL_Result.filter(regex=("^TRUE|^Pred_.*_mean")), Xg, method='average')

        ALL_Resultv = ALL_Result[~ ALL_Result['TRUE'].isna()]
        if ALL_Resultv.shape[0] > 2:
            Parallel( n_jobs=-1 )( delayed( _p)
                                    ( ALL_Resultv['TRUE'], ALL_Resultv['Pred_%s_mean'%_m], ALL_Resultv.filter(regex='.*_Prob_%s_mean'%_m, axis=1), _m )
                                    for _m in _model
                                    for _p in [ ROCPR('%s%s_Class_%s_%s_ROC.pdf'%(self.arg.output, _Y_name, label, _m)).ROC_CImport,
                                                ROCPR('%s%s_Class_%s_%s_PR.pdf' %(self.arg.output, _Y_name, label, _m)).PR_CImport]
                                )

            Parallel( n_jobs=-1 )( delayed( _p)
                        ( All_test_pd, _Y_name, _m )
                        for _m in _model
                        for _p in [ ROCPR('%s%s_Class_%s_%s_CVROC.pdf'%(self.arg.output, _Y_name, label, _m)).ROC_EImport,
                                    ROCPR('%s%s_Class_%s_%s_CVPR.pdf' %(self.arg.output, _Y_name, label, _m)).PR_EImport]
                    )

            ROCPR( '%s%s_Class_%s_All_ROC.pdf' % (self.arg.output, _Y_name, label) ).ROC_MImport(ALL_Resultv, _model, _Y_name)
            ROCPR( '%s%s_Class_%s_All_PR.pdf'  % (self.arg.output, _Y_name, label) ).PR_MImport( ALL_Resultv, _model, _Y_name)

            _EvalueA = self.GetSplit(ALL_Resultv.filter(regex='^TRUE|_mean$', axis=1), label=label)
            self.log.CIF( "The final mean evaluation: \n%s" %_EvalueA )

        self.log.CIF( ('Finish %s'% label).center(45, '-') )

    def LearNing_R(self,):
        X_train, X_test, y_train, y_test = self.array
        Y = y_train.name
        clf = GridSearchCV(self.estimator, self.parameters, n_jobs=self.arg.n_job, cv=10,return_train_score =True,iid=True)
        clf.fit(X_train, y_train)
        if 'joblibR' in self.dicts.keys():
            joblib.dump(clf.best_estimator_, '%sRegress_%s_%s_best_estimator.pkl'%(self.arg.outdir,Y,self.model), compress = 1)

        try:
            importances= clf.best_estimator_.feature_importances_
            df_import = pd.DataFrame(np.array(importances).T,columns=[self.model + '_import'],index=X_train.columns)
            #.sort_values(by=[self.model + '_import'],ascending=[False])
        except AttributeError:
            importances= clf.best_estimator_.coef_
            df_import = pd.DataFrame(np.array(importances).T,columns=[self.model + '_import'],index=X_train.columns)
            #.sort_values(by=[self.model + '_import'],ascending=[False])
        except AttributeError:
            importances= clf.best_estimator_.coefs_
            df_import = pd.DataFrame(np.array(importances).T)
            print(df_import)
        except AttributeError:
            print('aaaaaaaaaa')
        df_import = df_import[df_import[self.model + '_import'] != 0]

        #cross_validate cross_val_score cross_val_predict
        score = clf.score(X_test, y_test)
        Y_trapred = clf.predict(X_train)
        Y_tespred = clf.predict(X_test)

        model_metrics_name = [explained_variance_score, mean_absolute_error, mean_squared_error, r2_score]
        tmp_score = [m(y_test, Y_tespred)  for m in model_metrics_name]
        tmp_score.append( pearsonr(y_test, Y_tespred)[0] )

        print(80 * '-')
        print('The parameters of the best model are: ')
        print(self.model, clf.best_params_, clf.best_score_)
        print(self.model, "_weight:", df_import)
        print(self.model, "_test cor:", tmp_score)
        print(self.model, "_test score:", score)
        print(80 * '-')
        return (tmp_score, df_import, Y_tespred)

    def Predict_R(self):
        (Cf_xy, Xa, Yi ) =self.array
        Y = Yi.name
        clf = joblib.load('%sClass_%s_%s_best_estimator.pkl'%(self.arg.outdir,Y,self.model))
        df_import = Openf('%sClass_%s_%s_best_estimator.imp'%(self.arg.outdir,Y,self.model) , index_col='features', index=True).openb()
        X_predict = Cf_xy[df_import.index]
        All_Y_predict = []
        All_Y_predict_pro = []
        for i in range(10):
            Y_predict = clf.predict(X_predict)
            Y_predict_pro    = clf.predict_proba(X_predict)

            if not Yi.isnull().any():
                Y_predict_accuracy  = accuracy_score(Yi, Y_predict)
                Y_predict_R2_score  = r2_score(Yi, Y_predict)
                Y_predict_pro       = clf.predict_proba(X_predict)
                Y_predict_pro_val   = Y_predict_pro[:, 1]
                fpr,tpr,threshold   = roc_curve(Yi, Y_predict_pro_val)
                roc_auc = auc(fpr,tpr)
                metrics_pvalues = [['Model', 'Y_predict_accuracy', 'Y_predict_R2_score', 'roc_auc'],
                                   [self.model , Y_predict_accuracy, Y_predict_R2_score, roc_auc]]
                metrics_pvalues = pd.DataFrame(metrics_pvalues[1:], columns=metrics_pvalues[0])
                ROC_list        = [fpr, tpr, roc_auc, Y_predict_accuracy, self.model]

class Modeling():
    def __init__(self, arg, log, *array, **dicts):
        self.arg = arg
        self.log = log
        self.array = array
        self.dicts = dicts
        self.MClass= 2
        self.arg.output = '%s/03ModelFit/%s'%( self.arg.outdir, self.arg.header )
        os.makedirs(os.path.dirname(self.arg.output), exist_ok=True)

    def Model_X(self, DFall, _X_names, _Y_name, Xg, Type= 'C'):
        self.MClass = DFall[_Y_name].nunique()
        DFall[_Y_name] = Check_Label(DFall[_Y_name])
        CVRlt = Processing( self.arg, self.log, model=self.arg.model, Y_name=_Y_name, MClass= self.MClass, Type = Type )

        All_Test, All_coefs_, All_evluat, All_estmt_ = [], [], [], []
        for _k in range(self.arg.Repeatime):
            CVM   = CVRlt.CVSplit(DFall[_X_names], DFall[_Y_name], CVt = self.arg.CVfit)
            for _n, (train_index, test_index) in enumerate(CVM):
                _Train , _Test   = DFall.iloc[train_index, :], DFall.iloc[test_index, :]
                X_train, y_train = _Train[_X_names], _Train[_Y_name]
                X_test , y_test  = _Test[ _X_names], _Test[_Y_name]

                self.log.CIF( ('%s %s Model Fitting and hyperparametering.'% (_Y_name, self.arg.model)).center(45, '-') )
                _Test, _coefs_, _evluat, _estmt_  = CVRlt.LearNing_C( X_train, X_test, y_train, y_test )

                All_Test.append(_Test)
                All_estmt_.append(_estmt_)

                if not _coefs_.empty:
                    self.log.CIF( "%s Feature coefficiency: \n%s" % (self.arg.model, _coefs_) )
                    All_coefs_.append(_coefs_)
                if not _evluat.empty:
                    self.log.CIF( "%s Modeling evaluation: \n%s" %(self.arg.model, _evluat) )
                    All_evluat.append(_evluat)

                self.log.CIF( ('Modeling has been Completed %2d%%'% ((_k+1)*(_n+1)*100/(self.arg.Repeatime*len(CVM)))).center(45, '-') )

        ### All_Test_predict
        CVRlt.CVMerge( All_Test, DFall, _X_names, _Y_name, Xg, label='Test' )
        ### All_coefs_
        CVRlt.FeatCoeffs(All_coefs_, _Y_name, Xg)
        ### All_evaluate_score_
        CVRlt.ModelScore(All_evluat, _Y_name, label='Test')
        ### All_evaluate_model_
        joblib.dump(All_estmt_, '%s%s_Class_best_estimator.pkl' %(self.arg.output, _Y_name), compress=1)

    def Fitting(self):
        (group, RYa, CYa, Xa, Xg) = OpenM(self.arg, self.log).openg()
        YType  =  group[ (group.Variables.isin( RYa + CYa)) ][['Variables','Type']]

        for Yi,Typi in YType.values:
            if self.arg.pca:
                Fsltfile = '%s/02FeatureSLT/%s%s_Class_Regress_FeatureSLT.PCA.xls' %(self.arg.outdir, self.arg.header, Yi )
            else :
                Fsltfile = '%s/02FeatureSLT/%s%s_Class_Regress_FeatureSLT.Data.xls'%(self.arg.outdir, self.arg.header, Yi )

            DFall = Openf(Fsltfile, index_col=0).openb()
            _Xi   = list( set(DFall.columns)- set([Yi]) )

            self.log.CIF( ('%s: Supervised MODELing'%Yi).center(45, '*') )
            self.log.NIF( '%s Value Counts:\n%s' %(Yi, DFall[Yi].value_counts().to_string()) )
            self.Model_X( DFall, _Xi , Yi, Xg, Type= Typi )
            self.log.CIF( ('%s: Supervised MODELing Finish'%Yi).center(45, '*') )


from django.contrib.auth import get_user_model
from django.test import TestCase, Client
from django.urls import reverse
from http import HTTPStatus
import unittest

from ..models import Group, Post

User = get_user_model()

class PostsURLTests(TestCase):
    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        user = User.objects.create_user(username='user')
        cls.group = Group.objects.create(
            title='Test case',
            slug='test-slug',
        )
        cls.post = Post.objects.create(
            text='Create new post',
            group=cls.group,
            author=user,
        )

    def setUp(self):
        self.guest_client = Client()
        self.user = User.objects.create_user(username='Test_user')
        self.authorized_client = Client()
        self.authorized_client.force_login(self.user)
        self.author_client = Client()
        self.author_client.force_login(self.post.author)

        self.templates_urls = {
            'index.html': reverse('index'),
            'group.html': reverse(
                'group', kwargs={'slug': PostsURLTests.group.slug}
            ),
            'new_post.html': reverse('new_post'),
            'profile.html': reverse(
                'profile', kwargs={'username': PostsURLTests.post.author}
            ),
            'post.html': reverse(
                'post', kwargs={
                    'username': PostsURLTests.post.author,
                    'post_id': PostsURLTests.post.id,
                })
        }

    def test_status_web_pages_authorized(self):
        for page in self.templates_urls.values():
            with self.subTest(page=page):
                response = self.authorized_client.get(page)
                self.assertEqual(response.status_code, HTTPStatus.OK)

    @unittest.expectedFailure
    def test_status_web_pages_unauthorized(self):
        for page in self.templates_urls.values():
            with self.subTest(page=page):
                response = self.guest_client.get(page)
                self.assertEqual(response.status_code, HTTPStatus.OK)

    def test_urls_uses_correct_template(self):
        for template, url in self.templates_urls.items():
            with self.subTest(template=template):
                response = self.authorized_client.get(url)
                self.assertTemplateUsed(response, template)

    def test_status_post_edit_page_unauthorized(self):
        response = self.guest_client.get(reverse('post_edit', kwargs={
            'username': PostsURLTests.post.author,
            'post_id': PostsURLTests.post.id}))
        self.assertRedirects(response, reverse('post', kwargs={
            'username': PostsURLTests.post.author,
            'post_id': PostsURLTests.post.id}))

    def test_status_post_edit_page_authorized(self):
        response = self.authorized_client.get(reverse('post_edit', kwargs={
            'username': PostsURLTests.post.author,
            'post_id': PostsURLTests.post.id}))
        self.assertRedirects(response, reverse('post', kwargs={
            'username': PostsURLTests.post.author,
            'post_id': PostsURLTests.post.id}))

    def test_status_post_edit_page_author(self):
        response = self.author_client.get(reverse('post_edit', kwargs={
            'username': PostsURLTests.post.author,
            'post_id': PostsURLTests.post.id}))
        self.assertEqual(response.status_code, HTTPStatus.OK)


import sys
import re
import os
import os.path
import datetime
import subprocess
from   .              import ErrorMessage
from   .Project       import Project
from   .Configuration import Configuration

class Builder:

    def __init__ ( self ):
        self._conf             = Configuration()
        self._quiet            = False
        self._rmBuild          = False
        self._doBuild          = True
        self._noCache          = False
        self._ninja            = False
        self._clang            = False
        self._manylinux        = False
        self._noSystemBoost    = False
        self._macports         = False
        self._devtoolset       = 0
        self._llvmtoolset      = 0
        self._bfd              = "OFF"
        self._qt4              = False
        self._openmp           = False
        self._enableShared     = "ON"
        self._enableDoc        = "OFF"
        self._checkDatabase    = "OFF"
        self._checkDeterminism = "OFF"
        self._verboseMakefile  = "OFF"
        self._makeArguments    = []
        self._environment      = os.environ
        return

    def __setattr__ ( self, attribute, value ):
        if attribute[0] == "_":
            self.__dict__[attribute] = value
            return
        if attribute in self._conf.getAllIds(): setattr( self._conf, attribute, value )
        if   attribute == "quiet":            self._quiet            = value
        elif attribute == "rmBuild":          self._rmBuild          = value
        elif attribute == "doBuild":          self._doBuild          = value
        elif attribute == "noCache":          self._noCache          = value
        elif attribute == "ninja":            self._ninja            = value
        elif attribute == "clang":            self._clang            = value
        elif attribute == "manylinux":        self._manylinux        = value
        elif attribute == "macports":
            self._macports = value
            if value: self._noSystemBoost = True
        elif attribute == "devtoolset":
            self._devtoolset = value
            if value: self._noSystemBoost = True
        elif attribute == "llvmtoolset":
            self._llvmtoolset = value
        elif attribute == "bfd":              self._bfd              = value
        elif attribute == "qt4":              self._qt4              = value
        elif attribute == "openmp":           self._openmp           = value
        elif attribute == "enableDoc":        self._enableDoc        = value
        elif attribute == "enableShared":     self._enableShared     = value
        elif attribute == "checkDatabase":    self._checkDatabase    = value
        elif attribute == "checkDeterminism": self._checkDeterminism = value
        elif attribute == "verboseMakefile":  self._verboseMakefile  = value
        elif attribute == "makeArguments":    self._makeArguments    = value.split ()
        return

    def __getattr__ ( self, attribute ):
        if attribute[0] != "_":
            if attribute == 'conf': return self._conf
            if attribute in self._conf.getAllIds():
                return getattr( self._conf, attribute )
        if not attribute in self.__dict__:
            raise ErrorMessage( 1, 'Builder has no attribute <%s>.'%attribute )
        return self.__dict__[attribute]

    def _guessGitHash ( self, project ):
        self.gitHash = 'x'
        os.chdir ( self.sourceDir+'/'+project.getName() )
        command = [ 'git', 'log', '--pretty=format:%h', '-n', '1']
        self.gitHash = subprocess.Popen ( command, stdout=subprocess.PIPE ).stdout.readlines()[0]
        return

    def _configure ( self, fileIn, fileOut ):
        fdFileIn  = open ( fileIn , "r" )
        fdFileOut = open ( fileOut, "w" )
        for line in fdFileIn.readlines():
            stable       = False
            substituted0 = line
            while not stable:
                substituted1 = re.sub ( r"@revdate@"    , self.revDate, substituted0 )
                substituted1 = re.sub ( r"@githash@"    , self.gitHash, substituted1 )
                substituted1 = re.sub ( r"@coriolisTop@", "/usr"      , substituted1 )
                if substituted0 == substituted1: stable = True
                else: substituted0 = substituted1
            fdFileOut.write ( substituted0 )
        fdFileIn.close ()
        fdFileOut.close ()
        return

    def _doSpec ( self ):
        self._configure ( self.specFileIn, self.specFile )
        return

    def _doDebChangelog ( self ):
        self._configure ( self.debChangelogIn, self.debChangelog )
        return

    def _execute ( self, command, error ):
        collections = []
        if self._devtoolset:
            collections.append( 'devtoolset-{}'.format(self._devtoolset) )
            print( 'Using devtoolset-{0} (scl enable devtoolset-{0} ...)'.format(self._devtoolset) )
        if self._llvmtoolset:
            collections.append( 'llvm-toolset-{}'.format(self._llvmtoolset) )
            print( 'Using llvm-toolset-{0} (scl enable llvm-toolset-{v} ...)'.format(self._llvmtoolset) )
        if collections:
            commandAsString = ''
            for i in range(len(command)):
                if i: commandAsString += ' '
                if ' ' in command[i]: commandAsString += '"'+command[i]+'"'
                else:                 commandAsString += command[i]
            command = [ 'scl', 'enable' ]
            command += collections
            command.append( commandAsString )
        sys.stdout.flush ()
        sys.stderr.flush ()
        child = subprocess.Popen ( command, env=self._environment, stdout=None )
        (pid,status) = os.waitpid ( child.pid, 0 )
        status >>= 8
        if status != 0:
            ErrorMessage( status, "%s (status:%d)."%(error,status) ).terminate()
        return

    def _enableTool ( self, tool ):
        return

    def _build ( self, tool ):
        toolSourceDir   = os.path.join ( self.sourceDir, tool.getToolDir() )
        toolBuildDir    = os.path.join ( self.buildDir , tool.name )
        cmakeInstallDir = os.path.join ( self.installDir, "share", "cmake", "Modules" )
       # Supplied directly in the CMakeLists.txt.
       #cmakeModules  = os.path.join ( self.installDir, "share", "cmake", "Modules" )
        if not os.path.isdir(toolSourceDir):
            print( ErrorMessage( 0, 'Missing tool source directory: "{}" (skipped).' \
                                    .format(toolSourceDir) ))
            return
        if self._rmBuild:
            print( 'Removing tool build directory: "{}".'.format(toolBuildDir) )
            command = [ "/bin/rm", "-rf", toolBuildDir ]
            self._execute ( command, "Removing tool build directory" )

        command = [ 'cmake' ]
        if self.libSuffix:      command += [ "-D", "LIB_SUFFIX:STRING=%s" % self.libSuffix ]
        if self._ninja:         command += [ "-G", "Ninja" ]
        if self._macports:      command += [ "-D", "WITH_MACPORTS:STRING=TRUE" ]
        if self._noSystemBoost: command += [ "-D", "Boost_NO_SYSTEM_PATHS:STRING=TRUE"
                                          #, "-D", "BOOST_INCLUDEDIR:STRING=/usr/include/boost169"
                                          #, "-D", "BOOST_LIBRARYDIR:STRING=/usr/lib64/boost169"
                                           ]
        if self._bfd:           command += [ "-D", "USE_LIBBFD:STRING=%s" % self._bfd ]
        if self._qt4:           command += [ "-D", "WITH_QT4:STRING=TRUE" ]
        if self._openmp:        command += [ "-D", "WITH_OPENMP:STRING=TRUE" ]
        if self._manylinux:     command += [ "-D", "USE_MANYLINUX:STRING=TRUE" ]
        command += [ "-D", "CMAKE_BUILD_TYPE:STRING=%s"     % self.buildMode
                  #, "-D", "BUILD_SHARED_LIBS:STRING=%s"    % self.enableShared
                   , "-D", "CMAKE_INSTALL_PREFIX:STRING=%s" % self.installDir
                   , "-D", "CMAKE_INSTALL_DIR:STRING=%s"    % cmakeInstallDir
                  #, "-D", "CMAKE_MODULE_PATH:STRING=%s"    % cmakeModules
                  #, "-D", "Boost_DEBUG:STRING=TRUE"
                   , toolSourceDir ]

        if not os.path.isdir(toolBuildDir):
            print( 'Creating tool build directory: "{}".'.format(toolBuildDir) )
            os.makedirs ( toolBuildDir )
            os.chdir    ( toolBuildDir )
            self._execute ( command, "First CMake failed" )
        os.chdir ( toolBuildDir )
        if self._noCache:
            cmakeCache = os.path.join(toolBuildDir,"CMakeCache.txt")
            if os.path.isfile ( cmakeCache ): os.unlink ( cmakeCache )

        command += [ "-D", "BUILD_DOC:STRING=%s"              % self._enableDoc
                   , "-D", "CMAKE_VERBOSE_MAKEFILE:STRING=%s" % self._verboseMakefile
                   , "-D", "CMAKE_INSTALL_PREFIX:STRING=%s"   % self.installDir
                   , "-D", "CMAKE_INSTALL_DIR:STRING=%s"      % cmakeInstallDir
                   ]
        if self.libSuffix:                 command += [ "-D", "LIB_SUFFIX:STRING=%s"        % self.libSuffix ]
        if self._checkDatabase    == 'ON': command += [ "-D", "CHECK_DATABASE:STRING=ON"    ]
        if self._checkDeterminism == 'ON': command += [ "-D", "CHECK_DETERMINISM:STRING=ON" ]
        command += [ toolSourceDir ]

        self._execute ( command, "Second CMake failed" )
        if self._doBuild:
            command  = [ "make" ]
            if self._ninja:
                command  = [ "ninja-build" ]
           #command += [ "DESTDIR=%s" % self.installDir ]
            command += self._makeArguments
            print( "Make/Ninja command:", command )
            sys.stdout.flush ()
            self._execute ( command, "Build failed" )
        return

    def gitArchive ( self, projectName ):
        rawArchive = self.tarballDir+'/'+projectName+'.tar'
        os.chdir ( self.sourceDir+'/'+projectName )
        command = [ 'git'
                  , 'archive'
                  , '--prefix=%s/' % projectName
                  , '--output=%s'  % rawArchive
                  , 'devel'
                  ]
        self._execute ( command, "git archive of project %s" % projectName )
        if not os.path.isdir ( self.archiveDir ):
            os.mkdir ( self.archiveDir )
        os.chdir ( self.archiveDir )

        command = [ 'tar', 'xf', rawArchive ]
        self._execute ( command, "unpacking raw archive %s" % rawArchive )

        command = [ 'rm', rawArchive ]
        self._execute ( command, "Removing raw archive %s" % rawArchive )

       # Adds files neededs only for packaging purpose.
        command = [ "/bin/ln", "-s", "./coriolis/bootstrap/Makefile.package"
                                   , self.archiveDir+"/Makefile" ]
        self._execute ( command, "link of %s failed" % "coriolis/boostrap/Makefile.package")

        command = [ "/bin/ln", "-s", "./coriolis/bootstrap/debian", self.archiveDir ]
        self._execute ( command, "Copying Debian/Ubuntu package control files" )

   #   # Remove unpublisheds (yet) tools/files.
   #    for item in self.packageExcludes:
   #        command = [ "/bin/rm", "-rf", os.path.join(self.archiveDir,item) ]
   #        self._execute ( command, "rm of %s failed" % item)
   #
   #   # Adds files neededs only for packaging purpose.
   #    command = [ "/bin/cp", "-r", os.path.join(self.sourceDir ,"bootstrap","Makefile.package")
   #                               , os.path.join(self.archiveDir,"Makefile") ]
   #    self._execute ( command, "copy of %s failed" % "boostrap/Makefile.package")
   #
   #    os.chdir ( self.archiveDir )
   #    command = [ "/usr/bin/patch", "--remove-empty-files"
   #                                , "--no-backup-if-mismatch"
   #                                , "-p0", "-i", self.distribPatch ]
   #    self._execute ( command, "patch for distribution command failed" )
        absSourceTarBz2 = '%s/%s' % (self.tarballDir,self.sourceTarBz2)
        os.chdir ( self.tarballDir )
        command = [ 'tar', 'jcf', absSourceTarBz2, os.path.basename(self.archiveDir) ]
        self._execute ( command, "Creating composite archive %s" % absSourceTarBz2 )
        return

    def _setEnvironment ( self, systemVariable, userVariable ):
        if not systemVariable in self._environment or self._environment[systemVariable] == "":
            if not userVariable in self._environment or self._environment[userVariable] == "" :
                self._environment[ systemVariable ] = self.installDir
                print( '[WARNING] Neither "{0}" nor "{1}" environment variables are sets.' \
                       .format(systemVariable,userVariable) )
                print( '          Setting "{0}" to "{1}".'.format(systemVariable,self.installDir) )
            else:
                self._environment[ systemVariable ] = self._environment[ userVariable ]
        if not self._quiet:
            print( 'Setting "{0}" to "{1}".'.format(systemVariable,self._environment[systemVariable]) )
            if userVariable in self._environment:
                print( 'Transmitting "{0}" as "{1}".'.format(userVariable,self._environment[userVariable]) )
        return

    def _commandTemplate ( self, tools, projects, command ):
        if self._clang:
            self._environment[ 'CC'  ] = 'clang'
            self._environment[ 'CXX' ] = 'clang++'
        if self._devtoolset:
            self._environment[ 'BOOST_INCLUDEDIR' ] = '/opt/rh/devtoolset-%d/root/usr/include' % self._devtoolset
            self._environment[ 'BOOST_LIBRARYDIR' ] = '/opt/rh/devtoolset-%d/root/usr/lib'     % self._devtoolset
        if self._macports:
            self._environment[ 'BOOST_INCLUDEDIR' ] = '/opt/local/include'
            self._environment[ 'BOOST_LIBRARYDIR' ] = '/opt/local/lib'
       # Set or guess the various projects TOP environment variables.
        for project in self.projects:
            topVariable     = "%s_TOP"      % project.getName().upper()
            topUserVariable = "%s_USER_TOP" % project.getName().upper()
            self._setEnvironment ( topVariable, topUserVariable )
        if tools:
           # Checks if the requested tools are in the various projects.
            self.standalones = tools
            for project in self.projects:
                self.standalones = project.activate ( self.standalones )
            for tool in self.standalones:
                print( '[WARNING] Tool "{}" is not part of any project.'.format(tool) )
        if projects:
            for projectName in projects:
                project = self.getProject ( projectName )
                if not project:
                    ErrorMessage( 1, "No project of name \"%s\"."%projectName ).terminate()
                project.activateAll()
        if not tools and not projects:
            for project in self.projects:
                project.activateAll ()
        for project in self.projects:
            for tool in project.getActives():
                print( '\nProcessing tool: "{}".'.format(tool.name) )
                getattr(self,command) ( tool )
        return

    def enable ( self, tools, projects ):
        self._commandTemplate ( tools, projects, "_enableTool" )
        return

    def enabledTools ( self ):
        tools = []
        for project in self.projects:
            tools += project.getActives()
        return tools

    def build ( self, tools, projects ):
        self._commandTemplate ( tools, projects, "_build" )
        return

    def gitTarball ( self, tools, projects ):
        if self.gitHash == "x":
            self._guessGitHash ( self.getProject(projects[0]) )
        self._doSpec ()
   #    self._doDebChangelog ()
        if os.path.isdir(self.tarballDir):
            print( 'Removing previous tarball directory: "{}".'.format(self.tarballDir) )
            command = [ "/bin/rm", "-rf", self.tarballDir ]
            self._execute ( command, "Removing top export (tarball) directory" )
        print( 'Creating tarball directory: "{}".'.format(self.tarballDir) )
        os.makedirs ( self.tarballDir )
        self.gitArchive ( projects[0] )
        return

    def userTarball ( self, tools, projects ):
        self.enable( tools, projects )
        userSourceTarBz2 = os.path.join ( self.tarballDir
                                        , datetime.date.today().strftime('%s-%s-%%Y%%m%%d.tar.bz2'%
                                                                         (self.packageName
                                                                         ,self.packageVersion)) )
        excludes = []
        for exclude in self.packageExcludes:
            excludes += [ '--exclude='+exclude ]
        os.chdir ( self.sourceDir )
        command = [ "/bin/tar"
                  , "--exclude-backups"
                  , "--exclude-vcs"
                  , "--transform=s,^,%s/src/,"%self.projectDir ] \
                + excludes                                        \
                + [ "-jcvf", userSourceTarBz2 ]                   \
                + self.enabledTools()
        self._execute ( command, "tar command failed" )
        return

    def doRpm ( self ):
        self.gitTarball ( [], self.packageProjects )
        for rpmDir in [ "SOURCES", "SPECS", "BUILD", "tmp"
                      , "SRPMS", "RPMS/i386", "RPMS/i686", "RPMS/x86_64" ]:
            rpmFullDir = os.path.join ( self.rpmbuildDir, rpmDir )
            if not os.path.isdir(rpmFullDir):
                os.makedirs ( rpmFullDir )
            else:
                for entry in os.listdir(rpmFullDir):
                    path = os.path.join( rpmFullDir, entry )
                    if os.path.islink(path):
                        realpath = os.path.realpath( os.readlink(path) )
                        if not os.path.isfile(realpath):
                            print( 'Remove obsolete link: "{}".'.format(path) )
                            os.unlink( path )
        rpmSpecFile   = os.path.join ( self.rpmbuildDir, "SPECS"  , "coriolis2.spec" )
        rpmSourceFile = os.path.join ( self.rpmbuildDir, "SOURCES", self.sourceTarBz2 )
        sourceFile    = os.path.join ( self.tarballDir , self.sourceTarBz2 )

        if os.path.isfile ( rpmSpecFile ):
            os.unlink ( rpmSpecFile )
        os.symlink ( self.specFile, rpmSpecFile   )
        if not os.path.islink ( rpmSourceFile ):
            os.symlink ( sourceFile, rpmSourceFile )

        os.chdir ( self.rpmbuildDir )
        command = [ "/usr/bin/rpmbuild"
                  , "--define", "_topdir                 %s" % self.rpmbuildDir
                  , "--define", "_tmppath                %s" % self.tmppathDir
                 #, "--define", "_enable_debug_packages  0"
                  , "--with", "binarytar" ]
        if self._devtoolset:
            command += [ "--define", "scl devtoolset-%d"%self._devtoolset ]
        command += [ "-ba", "--clean", rpmSpecFile ]
        self._execute ( command, "Rebuild rpm packages" )
        return

    def doDeb ( self ):
        self.svnTarball ( [], self.packageProjects )
        if not os.path.isdir(self.debbuildDir):
            os.makedirs ( self.debbuildDir )
        os.chdir ( self.debbuildDir )
        sourceFile  = os.path.join ( self.tarballDir , self.sourceTarBz2 )
        debOrigFile = os.path.join ( self.debbuildDir, "coriolis2_1.0.%s.orig.tar.bz2" % self.gitHash )
        if not os.path.islink(debOrigFile):
          os.link ( sourceFile, debOrigFile )

        command = [ "/bin/tar", "jxf", debOrigFile ]
        self._execute ( command, "Unpacking pristine sources" )

       #command = [ "/bin/cp", "-r", self.debianDir, "." ]
       #self._execute ( command, "Copying Debian/Ubuntu package control files" )

        packageDir = os.path.join ( self.debbuildDir, "coriolis2-1.0.%s" % self.gitHash )
        os.chdir ( packageDir )
        self._environment["CFLAGS"  ] = "-O2"
        self._environment["CXXFLAGS"] = "-O2"
        command = [ "/usr/bin/debuild", "-us", "-uc" ]
        self._execute ( command, "Rebuild Debian packages" )
        return

    def getProject        ( self, name     ): return self._conf.getProject(name)
    def loadConfiguration ( self, confFile ): self._conf.load( confFile )
    def showConfiguration ( self ):           self._conf.show()


from tkinter import *
from PIL import ImageTk, Image
from tkinter import messagebox

root = Tk()
root.title('Time to play with windows')
# root.iconbitmap('')

def check():
    message = messagebox.askyesno("Confirmation","Open another window?")

    if message == 1:
        open_window()

def open_window():
    window = Toplevel()
    window.title('New window lol')
    # window.iconbitmap('')
    global image1
    image1 = ImageTk.PhotoImage(Image.open('images/img2.jpg'))
    image_to_show = Label(window, image=image1)
    image_to_show.grid(row=1, column=0)
    btn1 = Button(window,  text="Close", command= window.destroy)
    btn1.grid(row=0,column=0)

btn = Button(root, text='See here', command=check).pack()

root.mainloop()