class EditableRectangle:

    _angle = 0

    def __init__(self, ax):
        self.ax = ax

        # Set up main rectangle
        self.rect = Rectangle((0, 0), 0, 0, visible=False, transform=None, picker=True)
        self.ax.add_patch(self.rect)

        # Set up anchors
        self.anchors = []
        for i in range(len(RECTANGLE_ANCHOR_LOCS)):
            anchor = Rectangle((0, 0), ANCHOR_SIZE, ANCHOR_SIZE, visible=False, transform=None, facecolor='red', picker=True)
            self.anchors.append(anchor)
            self.ax.add_patch(anchor)

        self.press = None
        self.mode = None
        self.connect()

    def connect(self):
        self.cid_press = self.ax.figure.canvas.mpl_connect('button_press_event', self.on_press)
        self.cid_release = self.ax.figure.canvas.mpl_connect('button_release_event', self.on_release)
        self.cid_motion = self.ax.figure.canvas.mpl_connect('motion_notify_event', self.on_motion)
        self.cid_pick = self.ax.figure.canvas.mpl_connect('pick_event', self.on_pick)

    def on_pick(self, event):
        if event.artist in self.anchors:
            if event.mouseevent.key == 'r':
                self.mode = 'anchor-rotate'
                self.center_x = self.x0 + self.width * 0.5
                self.center_y = self.y0 + self.height * 0.5
                self.angle_start = self.angle
                self.angle_drag_start = np.degrees(np.arctan2(event.mouseevent.y - self.center_y, event.mouseevent.x - self.center_x))
                print(self.angle_start)
            else:
                self.mode = 'anchor-drag'
                anchor_index = self.anchors.index(event.artist)
                self.active_anchor_index = anchor_index
            self.press = True
        elif event.artist is self.rect:
            self.mode = 'rectangle-drag'
            self.drag_start_x0 = self.x0
            self.drag_start_y0 = self.y0
            self.drag_start_x = event.mouseevent.x
            self.drag_start_y = event.mouseevent.y
            self.press = True

    def on_press(self, event):

        if event.inaxes != self.ax:
            return

        if self.mode == 'create':
            self.x0 = event.x
            self.y0 = event.y
            self.rect.set_visible(True)
            self.press = True

        # contains, attrd = self.rect.contains(event)
        # if not contains: return
        # print('event contains', self.rect.xy)
        # x0, y0 = self.rect.xy
        # self.press = x0, y0, event.x, event.y

    @property
    def angle(self):
        return self._angle

    @angle.setter
    def angle(self, value):
        self._angle = value
        self.rect.angle = value
        self.rect._update_patch_transform()

    @property
    def x0(self):
        return self.rect.get_x()

    @x0.setter
    def x0(self, value):
        self.rect.set_x(value)

    @property
    def y0(self):
        return self.rect.get_y()

    @y0.setter
    def y0(self, value):
        self.rect.set_y(value)

    @property
    def width(self):
        return self.rect.get_width()

    @width.setter
    def width(self, value):
        self.rect.set_width(value)

    @property
    def height(self):
        return self.rect.get_height()

    @height.setter
    def height(self, value):
        self.rect.set_height(value)

    def on_motion(self, event):

        if self.press is None:
            return

        if event.inaxes != self.ax:
            return

        if self.mode == 'create':

            self.width = event.x - self.x0
            self.height = event.y - self.y0

            self.rect.figure.canvas.draw()

        elif self.mode == 'rectangle-drag':

            self.x0 = self.drag_start_x0 + event.x - self.drag_start_x
            self.y0 = self.drag_start_y0 + event.y - self.drag_start_y

            self.update_anchors()

            self.rect.figure.canvas.draw()

        elif self.mode == 'anchor-drag':

            px, py = RECTANGLE_ANCHOR_LOCS[self.active_anchor_index]

            if px == -1:
                self.x0, self.width = event.x, self.x0 + self.width - event.x
            elif px == 1:
                self.width = event.x - self.x0

            if py == -1:
                self.y0, self.height = event.y, self.y0 + self.height - event.y
            elif py == 1:
                self.height = event.y - self.y0

            self.update_anchors()

            self.rect.figure.canvas.draw()

        elif self.mode == 'anchor-rotate':

            angle_current = np.degrees(np.arctan2(event.y - self.center_y, event.x - self.center_x))

            self.angle = self.angle_start + (angle_current - self.angle_drag_start)

            self.update_anchors()

            self.rect.figure.canvas.draw()

    def on_release(self, event):
        if self.mode == 'create':
            self.update_anchors()
            self.set_anchor_visibility(True)
        self.press = None
        self.mode = None
        self.rect.figure.canvas.draw()

    def set_anchor_visibility(self, visible):
        for anchor in self.anchors:
            anchor.set_visible(visible)

    def update_anchors(self):
        for anchor, (dx, dy) in zip(self.anchors, RECTANGLE_ANCHOR_LOCS):
            xc = self.x0 + 0.5 * self.width
            yc = self.y0 + 0.5 * self.height
            dx = 0.5 * (dx * self.width - ANCHOR_SIZE)
            dy = 0.5 * (dy * self.height - ANCHOR_SIZE)
            dxr = dx * np.cos(np.radians(self.angle)) - dy * np.sin(np.radians(self.angle))
            dyr = dx * np.sin(np.radians(self.angle)) + dy * np.cos(np.radians(self.angle))
            anchor.set_xy((xc + dxr, yc + dyr))

    def disconnect(self):
        self.ax.figure.canvas.mpl_disconnect(self.cid_press)
        self.ax.figure.canvas.mpl_disconnect(self.cid_release)
        self.ax.figure.canvas.mpl_disconnect(self.cid_motion)