# Copyright 2019 Xilinx Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import time
import base64
from six import itervalues, next

import cv2
import numpy as np

from vai.dpuv1.rt import xdnn, xdnn_io
from vai.dpuv1.rt.xsnodes.base import XstreamNode, XstreamNodeArgs

class Node(XstreamNode):
    """
    This class implements the Facedetect node. Initializing the class creates
    and starts the node through the loop() method

    Args:
        XstreamNode (XstreamNode): The base class of all nodes

    Returns:
        Facedetect: An instance of the class
    """

    def initialize(self, args):
        self._parser = xdnn.CompilerJsonParser(args['netcfg'])
        self._fpgaRT = xdnn.XDNNFPGAOp(args)
        self._indictnames = args["input_names"]
        self._outdictnames = args["output_names"]

        self._firstInputShape = next(itervalues(self._parser.getInputs()))
        self._meanarr = np.zeros(
            (
                self._firstInputShape[2],
                self._firstInputShape[3],
                self._firstInputShape[1],
            ),
            dtype=np.float32, order='C'
        )

        self.expand_scale_ = 0.0
        self.force_gray_ = False
        self.input_mean_value_ = 128.0
        self.input_scale_ = 1.0
        self.pixel_blob_name_ = 'pixel-prob'
        self.bb_blob_name_ = 'bb-output-tiled'

        self.res_stride_ = 4
        self.det_threshold_ = 0.7
        self.nms_threshold_ = 0.3
        self.input_channels_ = 3

        self._streamIds = [0, 1, 2, 3, 4, 5, 6, 7] # Allow 8 streams

        print("Facedetect: Starting loop")
        self.run()

    # --------------------------------------------------------
    # Fast R-CNN
    # Copyright (c) 2015 Microsoft
    # Licensed under The MIT License [see LICENSE for details]
    # Written by Ross Girshick
    # --------------------------------------------------------
    @staticmethod
    def nms(dets, thresh):
        """
        Implementation of Fast R-CNN using non-maximum supression (nms)

        Args:
            dets ([type]): [description]
            thresh ([type]): [description]

        Returns:
            [type]: [description]
        """
        x1 = dets[:, 0]
        y1 = dets[:, 1]
        x2 = dets[:, 2]
        y2 = dets[:, 3]
        scores = dets[:, 4]

        areas = (x2 - x1 + 1) * (y2 - y1 + 1)
        order = scores.argsort()[::-1]

        keep = []
        while order.size > 0:
            i = order[0]
            keep.append(i)
            xx1 = np.maximum(x1[i], x1[order[1:]])
            yy1 = np.maximum(y1[i], y1[order[1:]])
            xx2 = np.minimum(x2[i], x2[order[1:]])
            yy2 = np.minimum(y2[i], y2[order[1:]])

            w = np.maximum(0.0, xx2 - xx1 + 1)
            h = np.maximum(0.0, yy2 - yy1 + 1)
            inter = w * h
            ovr = inter / (areas[i] + areas[order[1:]] - inter)

            inds = np.where(ovr <= thresh)[0]
            order = order[inds + 1]

        return keep

    def GSTilingLayer_forward(self, bottom, stride):
        stride_sq = stride**2

        input_batch = bottom.shape[0]
        input_channels = bottom.shape[1]
        input_height = bottom.shape[2]
        input_width = bottom.shape[3]

        output_batch = input_batch
        output_channels = input_channels//stride_sq
        output_height = input_height*stride
        output_width = input_width*stride

        top = np.zeros(
            [output_batch, output_channels, output_height, output_width],
            dtype=np.float32
        )

        for n in range(input_batch):
            for ic in range(input_channels):
                off_div = (ic // output_channels) // stride
                off_mod = (ic // output_channels) % stride
                oc = ic % output_channels
                for iy in range(input_height):
                    oy = iy * stride + off_div
                    ox = off_mod - stride
                    top[n,oc,oy,off_mod::stride] = bottom[n,ic,iy,:input_width]

        return top

    def SoftmaxLayer_forward(self, bottom):
        input_batch = bottom.shape[0]
        input_channels = bottom.shape[1]
        input_height = bottom.shape[2]
        input_width = bottom.shape[3]

        top = np.zeros(
            [input_batch, input_channels, input_height, input_width],
            dtype=np.float32
        )

        for n in range(input_batch):

            scale_data = np.zeros([input_height,input_width],dtype=np.float32)
            scale_data = bottom[n,0,...]

            for c in range(1,input_channels):
                scale_data = np.maximum(scale_data, bottom[n, c, ...])

            tmp_bottom = bottom[n, ...] - scale_data
            tmp_bottom = np.exp(tmp_bottom)

            scale_data = np.sum(tmp_bottom, axis=0)
            tmp_bottom = tmp_bottom / scale_data
            top[n] = tmp_bottom

        return top

    # Called for every batch
    def forward(self, bottom):
        top = [0]*len(self._outdictnames)

        indict = {}
        outdict = {}

        for i, n in enumerate(self._indictnames):
            # default to 1 batch
            indict[n] = np.ascontiguousarray(np.expand_dims(bottom[i], 0))

        for i, name in enumerate(self._outdictnames):
            dim = self._parser.getOutputs()[name]
            top[i] = np.empty(dim, dtype=np.float32)
            outdict[name] = top[i]

        # Get a free stream if available
        if self._streamIds:
            streamId = self._streamIds.pop(0)
        else:
            return None

        start_time = time.time()
        # self.fpgaRT.execute(indict, outdict, streamId)
        self._fpgaRT.exec_async(indict, outdict, streamId)
        self._fpgaRT.get_result(streamId)
        end_time = time.time()

        self._streamIds.append(streamId) # Return stream

        return outdict

    def detect(self, image):
        # transpose HWC (0,1,2) to CHW (2,0,1)
        transformed_image = np.transpose(image, (2, 0, 1))

        transformed_image = (transformed_image-self.input_mean_value_)*self.input_scale_
        sz = image.shape

        # Call FPGA
        output = self.forward([transformed_image.astype(np.float32)])

        # Put CPU layers into postprocess
        pixel_conv = output['pixel-conv']
        pixel_conv_tiled = self.GSTilingLayer_forward(pixel_conv, 8)
        prob = self.SoftmaxLayer_forward(pixel_conv_tiled)
        prob = prob[0, 1, ...]

        bb = output['bb-output']
        bb = self.GSTilingLayer_forward(bb, 8)
        bb = bb[0, ...]

        ##import pdb; pdb.set_trace()
        gy = np.arange(0, sz[0], self.res_stride_)
        gx = np.arange(0, sz[1], self.res_stride_)
        gy = gy[0 : bb.shape[1]]
        gx = gx[0 : bb.shape[2]]
        [x, y] = np.meshgrid(gx, gy)

        #print bb.shape[1],len(gy),sz[0],sz[1]
        bb[0, :, :] += x
        bb[2, :, :] += x
        bb[1, :, :] += y
        bb[3, :, :] += y
        bb = np.reshape(bb, (4, -1)).T
        prob = np.reshape(prob, (-1, 1))
        bb = bb[prob.ravel() > self.det_threshold_, :]
        prob = prob[prob.ravel() > self.det_threshold_, :]
        rects = np.hstack((bb, prob))
        keep = self.nms(rects, self.nms_threshold_)
        rects = rects[keep, :]
        rects_expand = []
        for rect in rects:
            rect_expand = []
            rect_w = rect[2] - rect[0]
            rect_h = rect[3] - rect[1]
            rect_expand.append(int(max(0,rect[0]-rect_w*self.expand_scale_)))
            rect_expand.append(int(max(0,rect[1]-rect_h*self.expand_scale_)))
            rect_expand.append(int(min(sz[1],rect[2]+rect_w*self.expand_scale_)))
            rect_expand.append(int(min(sz[0],rect[3]+rect_h*self.expand_scale_)))
            rect_expand.append('face')
            rects_expand.append(rect_expand)

        return rects_expand

    def loop(self, payload):
        (meta, buf) = payload
        meta['callback'] = self._callback

        npimg = np.frombuffer(buf, dtype=getattr(np, meta['dtype']))
        image = np.reshape(npimg, (meta['image_height'], meta['image_width'], meta['image_channels']))

        image_resize = cv2.resize(
            image,
            (320, 320),
            interpolation=cv2.INTER_LINEAR
        )
        if image_resize is not None:
            boxes = self.detect(image_resize)
            meta['boxes'] = boxes
            meta['status'] = 0
            retval, img_str = cv2.imencode(".jpg", image_resize)

            if retval:
                base64_str = base64.b64encode(img_str)
                meta['img'] = base64_str.decode('utf-8')
            else:
                raise NotImplementedError

        # delete objects to decrement obj store refcount
        # -- this is so the object can be auto-deleted,
        #        so we can reuse the id in the put() below
        del buf
        del payload

        self.put(meta)

class Args(XstreamNodeArgs):
    def __init__(self):
        super(Args, self).__init__()

        self.add_start_arg(
            'netcfg',
            "(?): insert description of netcfg"
        )
        self.add_start_arg(
            '_parser',
            "(?): insert description of _parser"
        )
        self.add_start_arg(
            '_indictnames',
            "(str): insert description of _indictnames"
        )
        self.add_start_arg(
            '_outdictnames',
            "(str): insert description of _outdictnames"
        )
        self.add_start_arg(
            'XDNNFPGAOp_args',
            "(?): Not sure which arguments might be needed for the XDNNFPGAOp instance"
        )

        self.add_input_serve_arg(
            'BUFFER',
            "The buffer should contain an image to be parsed with np.dtype"

        )
        self.add_input_serve_arg(
            'dtype',
            "(str): This should be an attribute of np to indicate how to interpret the" +
                "numpy array"
        )
        self.add_input_serve_arg(
            'image_height',
            "(int): Height of the image in pixels"
        )
        self.add_input_serve_arg(
            'image_width',
            "(int): Width of the image in pixels"
        )
        self.add_input_serve_arg(
            'image_channels',
            "(int): Channels in the image (usually should be 3)"
        )

        self.add_output_serve_arg(
            'callback',
            "(str): The meta is updated with the callback value of this node"
        )
        self.add_output_serve_arg(
            'BUFFER',
            "The buffer is emptied"
        )
        self.add_output_serve_arg(
            'status',
            "0 - success"
        )
        self.add_output_serve_arg(
            'boxes',
            "(dict): Detected faces in this format: TBD"
        )
        self.add_output_serve_arg(
            'img',
            "(str): Base64-encoded image URI from the input buffer"
        )


import os

import torch

# -----------------------------------------------------------------------------------------------------------#
# PennFudanConfig
# VocConfig
# DefaultCocoConfig
# -----------------------------------------------------------------------------------------------------------#

CocoNamesPath = os.path.join(os.getcwd(), "conf", "coco.names")
VocNamesPath = os.path.join(os.getcwd(), "conf", "voc.names")

DarkNet53WeightPath = os.path.join(os.getcwd(), "weights", "demo_darknet53_weights.pth")

PennFudanConfig: dict = {
    # 1. 默认配置
    "anchors": [  # 锚框，width * height
        [
            [116, 90], [156, 198], [373, 326]  # 大
        ], [
            [30, 61], [62, 45], [59, 119]  # 中
        ], [
            [10, 13], [16, 30], [33, 23]  # 小
        ]
    ],
    "image_height": 416,  # 输入图片高度
    "image_width": 416,  # 输入图片宽度
    "conf_threshold": 0.5,  # 正确预测框的最小置信度
    "nms_iou_threshold": 0.3,  # 判断预测框重合的最大 iou 阈值
    "cuda": True and torch.cuda.is_available(),  # 是否使用 GPU
    # 2. 数据集专属配置
    # "dataset_root": "/Users/limengfan/Dataset/PennFudanPed",
    "dataset_root": "/home/lenovo/data/lmf/Dataset/PennFudanPed",
    # "weights_path": "/Users/limengfan/PycharmProjects/210429_YoloV3_Experiment/logs/"
    #                 "Pennfudan_Test_3_2_Epoch697-Train_Loss0.8573-Val_Loss4.8586.pth",  # 模型权重
    "weights_path": "/home/lenovo/data/lmf/210429_YoloV3_ExperimentSftp/logs/"
                    "Voc_Test_3_1_Epoch162-Train_Loss2.2315-Val_Loss4.3770.pth",  # 模型权重
    "pretrained_weights_path": os.path.join(os.getcwd(), "outer_weights", "demo_darknet53_weights.pth"),  # 预训练模型权重
    "classes": 1,  # 分类数目
    "labels": [  # 类别标签
        "person",
    ]
}

VocConfig: dict = {
    # 1. 默认配置
    "anchors": [  # 锚框，width * height
        [
            [116, 90], [156, 198], [373, 326]  # 大
        ], [
            [30, 61], [62, 45], [59, 119]  # 中
        ], [
            [10, 13], [16, 30], [33, 23]  # 小
        ]
    ],
    "image_height": 416,  # 输入图片高度
    "image_width": 416,  # 输入图片宽度
    "conf_threshold": 0.05,  # 正确预测框的最小置信度
    "nms_iou_threshold": 0.2,  # 判断预测框重合的最大 iou 阈值
    "cuda": True and torch.cuda.is_available(),  # 是否使用 GPU
    # 2. 数据集专属配置
    # "dataset_root": "/Users/limengfan/Dataset/VOC/VOC2012Train",
    "dataset_root": "/home/lenovo/data/lmf/Dataset/voc/VOCtrainval_11-May-2012",
    # "weights_path": "/Users/limengfan/PycharmProjects/210429_YoloV3_Experiment/logs/"
    #                 "Voc_Test_2_5_Epoch157-Train_Loss3.7029-Val_Loss4.4745.pth",  # 模型权重
    "weights_path": "/home/lenovo/data/lmf/210429_YoloV3_ExperimentSftp/logs/"
                    "Voc_Test2Epoch77-Train_Loss0.0538-Val_Loss22.3093.pth",  # 模型权重
    "pretrained_weights_path": os.path.join(os.getcwd(), "outer_weights", "demo_darknet53_weights.pth"),  # 预训练模型权重
    # "pretrained_weights_path": "/Users/limengfan/PycharmProjects/210429_YoloV3_Experiment/logs/"
    # "pretrained_weights_path": "/home/lenovo/data/lmf/210429_YoloV3_ExperimentSftp/logs/"
    #                            "Voc_Experiment_1_2_Epoch0023-Train_Loss6.2914-Val_Loss7.0953.pth",  # 预训练模型权重
    "classes": 20,  # 分类数目
    "labels": [
        line.strip() for line in
        open(VocNamesPath).readlines()
    ] if os.path.exists(VocNamesPath)
    else [print("warn in loading voc.names", VocNamesPath)],
}

DefaultCocoConfig: dict = {
    # 1. 默认配置
    "anchors": [  # 锚框，width * height
        [
            [116, 90], [156, 198], [373, 326]  # 大
        ], [
            [30, 61], [62, 45], [59, 119]  # 中
        ], [
            [10, 13], [16, 30], [33, 23]  # 小
        ]
    ],
    "image_height": 416,  # 输入图片高度
    "image_width": 416,  # 输入图片宽度
    "conf_threshold": 0.5,  # 正确预测框的最小置信度
    "nms_iou_threshold": 0.3,  # 判断预测框重合的最大 iou 阈值
    "cuda": False and torch.cuda.is_available(),  # 是否使用 GPU
    # 2. 数据集专属配置
    "weights_path": "/Users/limengfan/PycharmProjects/210318_SimpleYoloV3/weights/demo_yolov3_weights.pth",  # 模型权重
    "classes": 80,  # 分类数目
    "labels": [
        line.strip() for line in
        open(CocoNamesPath).readlines()
    ] if os.path.exists(CocoNamesPath)
    else [print("warn in loading coco.names", CocoNamesPath)],
}


#!/usr/bin/env python3

# Leon: Hero 273 -- A game made for a 48-hour game jam.
# Copyright (C) 2014 JT-Dev

# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:

# 1. The above copyright notice and this permission notice shall be included in
#    all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import pygame

import g
import utils
import constants
import sys

class TitleScreen(object):
	class Button(object):
		#0 Button Not Down
		#1 Button Down

		def __init__(self, pos, image_up, image_down, main, screen):
			self.image_up = image_up
			self.image_down = image_down
			self.rect = pygame.Rect(pos, self.image_up.get_rect().size)

			self.main = main
			self.screen = screen
			self.state = 0

		def clicked(self):
			if not self.screen:
				pygame.quit()
				sys.exit()

			self.main.running = False
			g.screen = self.screen

		def draw(self, surface):
			if self.state:
				surface.blit(self.image_down, self.rect)
			else:
				surface.blit(self.image_up, self.rect)

	def __init__(self, loader):
		self.background = loader.load("sprites/logo.png","image").convert_alpha()
		self.background = pygame.transform.scale(self.background, (constants.SCREEN_WIDTH // 2, constants.SCREEN_HEIGHT // 2))

		self.music = loader.load("sounds/titlescreen/music.ogg", "sound")
		self.music.play(loops=-1)

		g.deaths = 0

		self.running = True
		self.buttons = []

		play_button = self.Button((10, 100),
			loader.load("sprites/buttons/play_up.png", "image").convert_alpha(),
			loader.load("sprites/buttons/play_down.png", "image").convert_alpha(),
			self, g.screen_map["info"]
		)

		credit_button = self.Button((10, 155),
			loader.load("sprites/buttons/credits_up.png", "image").convert_alpha(),
			loader.load("sprites/buttons/credits_down.png", "image").convert_alpha(),
			self, g.screen_map["credit"]
		)

		quit_button = self.Button((10, 210),
			loader.load("sprites/buttons/quit_up.png", "image").convert_alpha(),
			loader.load("sprites/buttons/quit_down.png", "image").convert_alpha(),
			self, None
		)

		self.buttons.append(play_button)
		self.buttons.append(credit_button)
		self.buttons.append(quit_button)

	def update(self, inputmanager):
		clicked = False

		for button in self.buttons:
			if not inputmanager.click_pos:
				break

			if button.rect.collidepoint(inputmanager.click_pos):
				if inputmanager.click_state:
					button.state = 1
				else:
					clicked = True
					button.clicked()
			elif button.state:
				button.state = 0

		if clicked:
			self.music.stop()
			inputmanager.reset()

	def draw(self, surface):
		x = (constants.SCREEN_WIDTH - self.background.get_width()) // 2
		y = (constants.SCREEN_HEIGHT - self.background.get_height()) // 2

		surface.blit(self.background, (x, y))

		for button in self.buttons:
			button.draw(surface)

	def peek(self):
		return not self.running


import os
import tools.binary as BIN

pf = '../../content/CoCo/Daggorath/rompatch.txt'

dr = os.path.dirname(pf)

lines = []
with open('../../content/CoCo/Daggorath/rompatch.txt') as f:
    for g in f:
        if ';' in g:
            g = g[0:g.index(';')]
        g = g.strip()
        if g:
            lines.append(g)

first = lines[0].split(' ')

with open(os.path.join(dr,first[0]),'rb') as f:
    data = list(f.read())

for line in lines[1:]:
    org,dat = BIN.line_to_data(line)
    if dat:
        p = org - int(first[2],16)
        print(p,len(dat))
        for b in dat:
            data[p] = b
            p+=1

with open(os.path.join(dr,first[1]),'wb') as f:
    f.write(bytes(data))


#載入LineBot所需要的套件
from flask import Flask, request, abort

from linebot import (
    LineBotApi, WebhookHandler
)
from linebot.exceptions import (
    InvalidSignatureError
)
from linebot.models import *

import re
import mongodb

app = Flask(__name__)

# 必須放上自己的Channel Access Token
line_bot_api = LineBotApi('ebe0/QaFkSufFT7V8JzKU67yo1s9zK6ujgFzPeEftnZ/F0j3AGesJZuedpHmDtCapJF+f3dMZmtT3weqtVzU73ic1kumQTJAVKHkF+Nz3fNvxPbLXr14cNhS6IcWC2JRGVMfTCNcHplz3nJrcoysbwdB04t89/1O/w1cDnyilFU=')
# 必須放上自己的Channel Secret
handler = WebhookHandler('30c48e179824500fb837c06a79dbc750')

line_bot_api.push_message('Ub72a3a6d716f44d30d2ec6be9a5c0c5e', TextSendMessage(text='你可以開始了'))

# 監聽所有來自 /callback 的 Post Request
@app.route("/callback", methods=['POST'])
def callback():
    # get X-Line-Signature header value
    signature = request.headers['X-Line-Signature']

    # get request body as text
    body = request.get_data(as_text=True)
    app.logger.info("Request body: " + body)

    # handle webhook body
    try:
        handler.handle(body, signature)
    except InvalidSignatureError:
        abort(400)

    return 'OK'
'''
#訊息傳遞區塊
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    message = TextSendMessage(text=event.message.text)
    line_bot_api.reply_message(event.reply_token,message)
'''

#訊息傳遞區塊
@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    ### 抓到顧客的資料 ###
    profile = line_bot_api.get_profile(event.source.user_id)
    uid = profile.user_id #使用者ID
    usespeak=str(event.message.text) #使用者講的話
    line_bot_api.push_message(uid, TextSendMessage(usespeak))
    if re.match('[0-9]{4}[<>][0-9]',usespeak): # 先判斷是否是使用者要用來存股票的
        line_bot_api.push_message(uid, TextSendMessage('測試儲存'))
        mongodb.write_user_stock_fountion(stock=usespeak[0:4], bs=usespeak[4:5], price=usespeak[5:])
        line_bot_api.push_message(uid, TextSendMessage(usespeak[0:4]+'已經儲存成功'))
        return 0

    elif re.match('刪除[0-9]{4}',usespeak): # 刪除存在資料庫裡面的股票
        mongodb.delete_user_stock_fountion(stock=usespeak[2:])
        line_bot_api.push_message(uid, TextSendMessage(usespeak+'已經刪除成功'))
        return 0

#主程式
import os
if __name__ == "__main__":
    port = int(os.environ.get('PORT', 5000))
    app.run(host='0.0.0.0', port=port)


# -*- coding: utf-8 -*-
#
# http://zetcode.com/gui/pyqt5/
#

import sys, random, os, shutil, json
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import (QDate, QTime, QDateTime, Qt, QTimeZone, pyqtSignal, QObject, QBasicTimer, QMimeData, \
    QFile, QIODevice, QTextStream, QFileDevice, QUrl, QTextCodec, QDir)
from PyQt5.QtGui import QIcon, QFont, QColor, QPixmap, QDrag, QPainter, QPen, QBrush, QPainterPath
from PyQt5.QtWidgets import (QWidget, QToolTip,
    QPushButton, QApplication, QMessageBox, QDesktopWidget,
    QMainWindow, QMenu, QAction, QTextEdit, QLabel, qApp,
    QHBoxLayout, QVBoxLayout, QGridLayout, QLineEdit,
    QLCDNumber, QSlider, QInputDialog, QColorDialog, QFrame, QFileDialog, QFontDialog,
    QCheckBox, QProgressBar, QCalendarWidget, QSplitter, QComboBox, QListView, QListWidget,
    QListWidgetItem, QScrollArea,QGraphicsScene, QGraphicsView, QGraphicsItemGroup, QGraphicsItem,
    QGraphicsSceneMouseEvent, QGraphicsPixmapItem)

def demo_ui():
    # ===============================================================
    # Form implementation generated from reading ui file 'untitled.ui'
    #
    # Created by: PyQt5 UI code generator 5.13.0
    #
    # WARNING! All changes made in this file will be lost!
    class Ui_Dialog(object):
        def setupUi(self, Dialog):
            Dialog.setObjectName("Dialog")
            Dialog.resize(400, 300)
            self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
            self.buttonBox.setGeometry(QtCore.QRect(290, 20, 81, 241))
            self.buttonBox.setOrientation(QtCore.Qt.Vertical)
            self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
            self.buttonBox.setObjectName("buttonBox")

            self.retranslateUi(Dialog)
            self.buttonBox.accepted.connect(Dialog.accept)
            # self.buttonBox.rejected.connect(Dialog.reject)
            QtCore.QMetaObject.connectSlotsByName(Dialog)

        def retranslateUi(self, Dialog):
            _translate = QtCore.QCoreApplication.translate
            Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
    # ===============================================================

    class ImageDialog(QtWidgets.QDialog):
        def __init__(self):
            super(ImageDialog, self).__init__()

            # Set up the user interface from Designer.
            self.ui = Ui_Dialog()
            self.ui.setupUi(self)

            # Make some local modifications.

            # Connect up the buttons.
            # self.ui.buttonBox.accepted.connect(self.accept)
            # self.ui.buttonBox.rejected.connect(self.reject)
            self.ui.buttonBox.rejected.connect(self.clickCancel)

        def clickCancel(self):
            print("clickCancel")

    app = QtWidgets.QApplication(sys.argv)
    widget = ImageDialog()
    # widget.resize(400, 100)
    # widget.setWindowTitle("This is a demo for PyQt Widget.")
    widget.show()
    sys.exit(app.exec_())

def demo_simple_window():
    app = QtWidgets.QApplication(sys.argv)

    # A widget with no parent is called a window
    widget = QtWidgets.QWidget()
    widget.setWindowTitle("demo_simple_window")

    # It is 250px wide and 150px high
    widget.resize(250, 150)
    widget.move(0, 0)
    widget.show()

    # The sys.exit() method ensures a clean exit. The environment will be informed how the application ended.
    # The exec_() method has an underscore. It is because the exec is a Python keyword.
    sys.exit(app.exec_())

def test_date():
    now = QDate.currentDate()
    print("              ISODate:", now.toString(Qt.ISODate))
    print("DefaultLocaleLongDate:", now.toString(Qt.DefaultLocaleLongDate))
    print()

    datetime = QDateTime.currentDateTime()
    print("QDateTime: ", datetime.toString())
    print()

    time = QTime.currentTime()
    print("QTime: ", time.toString(Qt.DefaultLocaleLongDate))
    print()

    utc = datetime.toUTC()
    print("local: ", datetime.toString(Qt.ISODate))
    print("  utc: ", utc.toString(Qt.ISODate))
    print("the offset from UTC is {0} seconds".format(datetime.offsetFromUtc()))
    print()

    print("Days in month: {0}".format(now.daysInMonth()))
    print("Days in year: {0}".format(now.daysInYear()))
    print()

    d1 = QDate(2016, 12, 24)
    d2 = QDate(2017, 12, 24)
    days1 = d1.daysTo(now)
    days2 = now.daysTo(d2)
    print("between {0} and {1}, {2}".format(d1.toString(Qt.ISODate), now.toString(Qt.ISODate), days1))
    print("between {0} and {1}, {2}".format(now.toString(Qt.ISODate), d2.toString(Qt.ISODate), days2))
    print()

    dt1 = datetime.addDays(12)
    dt2 = datetime.addDays(-22)
    dt3 = datetime.addSecs(50)
    dt4 = datetime.addMonths(3)
    dt5 = datetime.addYears(12)
    print("Today: ", datetime.toString(Qt.ISODate))
    print("add 12 days: ", dt1.toString(Qt.ISODate))
    print("sub 22 days: ", dt2.toString(Qt.ISODate))
    print("add 50 seconds: ", dt3.toString(Qt.ISODate))
    print("add 3 months", dt4.toString(Qt.ISODate))
    print("add 12 years: ", dt5.toString(Qt.ISODate))
    print()

    # 夏令时, Daylight saving time (DST)
    print("Time zone: {0}".format(datetime.timeZoneAbbreviation()))
    if datetime.isDaylightTime():
        print("DST time")
    else:
        print("not DST time")
    print()

    unix_time = datetime.toSecsSinceEpoch()
    print("unix_time:", unix_time)
    # convert the Unix time to QDateTime
    d = QDateTime.fromSecsSinceEpoch(unix_time)
    print("convert the Unix time to QDateTime: ", d.toString(Qt.DefaultLocaleLongDate))
    print()

    # Julian day
    print("Julian day: ", now.toJulianDay())
    print(now.dayOfYear())
    print(QDate(-4713, 1, 1).daysTo(now))
    print()

    #
    borodino_battle = QDate(1812, 9, 7)
    slavkov_battle = QDate(1805, 12, 2)

    j_today = now.toJulianDay()
    j_borodino = borodino_battle.toJulianDay()
    j_slavkov = slavkov_battle.toJulianDay()

    d1 = j_today - j_slavkov
    d2 = j_today - j_borodino

    print("Days since Slavkov battle: {0}".format(d1))
    print("Days since Borodino battle: {0}".format(d2))
    print()

def demo_Example():
    class Example(QtWidgets.QWidget):
        def __init__(self):
            super().__init__()

        def init(self):
            x, y = 500, 0
            w, h = 320, 180
            self.setGeometry(x, y, w, h)
            self.setWindowIcon(QIcon("res/icon.jpg"))
            self.setWindowTitle("Example")

            QToolTip.setFont(QFont('SansSerif', 10))

            # tooltip
            self.setToolTip('This is a QWidget widget')

            btn = QPushButton(QIcon("res/icon.jpg"), "QPushButton", self)
            btn.setToolTip('
This is a QPushButton widget')

            # The sizeHint() method gives a recommended size for the button.
            btn.resize(btn.sizeHint())

            btn_rect = btn.geometry().getRect()

            # quit application after click bye button
            #
            # The event processing system in PyQt5 is built with the signal & slot mechanism.
            # If we click on the button, the signal clicked is emitted.
            # The slot can be a Qt slot or any Python callable.
            btnBye = QPushButton("Bye", self)
            # btnBye.clicked.connect(QApplication.instance().quit)
            btnBye.clicked.connect(self.close)
            btnBye.resize(btnBye.sizeHint())
            btnBye.move(0, btn_rect[3] * 1.1)

            self.show()
            pass

        # If we close a QWidget, the QCloseEvent is generated.
        def closeEvent(self, event):
            reply = QMessageBox.question(self, "Message", "Are you sure to quit?",
                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if reply == QMessageBox.Yes:
                event.accept()
            else:
                event.ignore()

        def moveToCenter(self):
            qr = self.frameGeometry()  # QRect
            desktopQR = QDesktopWidget().availableGeometry()
            print(desktopQR)
            cp = desktopQR.center()  # QPoint
            print("center position = ", cp)
            qr.moveCenter(cp)
            self.move(qr.topLeft())

    app = QtWidgets.QApplication([])
    ex = Example()
    ex.init()
    ex.moveToCenter()
    sys.exit(app.exec_())

def demo_MainWindow():
    class SampleMainWindow(QMainWindow):
        def __init__(self):
            super().__init__()
            self.initUI()

        def initUI(self):
            self.setGeometry(300, 300, 250, 150)

            # create status bar
            self.statusBar().showMessage("statusbar ready")

            # menubar
            menubar = self.menuBar()
            menubar.setNativeMenuBar(False)

            # item in menu
            # QAction is an abstraction for actions performed with
            # a menubar, toolbar, or with a custom keyboard shortcut
            exitAct = QAction(QIcon("res/icon.jpg"), "&Exit", self)
            exitAct.setShortcut("Alt+T")
            exitAct.setStatusTip("Exit application")
            exitAct.triggered.connect(qApp.quit)

            # menu in menubar
            fileMenu = menubar.addMenu("&File")  # fileMenu contains action
            fileMenu.addAction(exitAct)  # exitAct will do the work

            # submenu
            # Import => Import mail
            impMenu = QMenu("Import", self)
            impAct = QAction("Import mail", self)
            impAct.setStatusTip("Import mails ... ")
            impMenu.addAction(impAct)
            fileMenu.addMenu(impMenu)

            # check menu
            viewMenu = menubar.addMenu("View")

            viewStatAct = QAction("View statusbar", self, checkable=True)
            viewStatAct.setStatusTip("View statusbar")
            viewStatAct.setChecked(True)
            viewStatAct.triggered.connect(self.toggleMenu)

            viewMenu.addAction(viewStatAct)

            btn = QPushButton("11", self)
            btn.resize(btn.sizeHint())
            btn.addAction(exitAct)
            btn.clicked.connect(exitAct.triggered)
            btn.move(0, 80)

            # toolbar
            # Menus group all commands that we can use in an application.
            # Toolbars provide a quick access to the most frequently used commands.
            toolbar = self.addToolBar("TB")
            # toolbar.addAction(exitAct)
            # toolbar.addAction(impAct)
            toolbar.addAction(viewStatAct)

            # text edit widget in center
            textEdit = QTextEdit(self)
            self.setCentralWidget(textEdit)

            self.show()

        def toggleMenu(self, state):
            if state:
                self.statusBar().show()
            else:
                self.statusBar().hide()

        # To work with a context menu, we have to reimplement the contextMenuEvent() method.
        def contextMenuEvent(self, event: QtGui.QContextMenuEvent):
            # context menu / popup menu
            cmenu = QMenu(self)
            newAct = cmenu.addAction("New")
            openAct = cmenu.addAction("Open")
            quitAct = cmenu.addAction("Quit")

            # The mapToGlobal() method translates the widget coordinates to the global screen coordinates.
            action = cmenu.exec_(self.mapToGlobal(event.pos()))

            if action == quitAct:
                qApp.quit()

    app = QApplication([])
    main_window = SampleMainWindow()
    sys.exit(app.exec_())

def demo_Layout():
    class Example(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()

        def initUI(self):
            # ============================================
            # absolute
            # label = QLabel("Samle Text", self)
            # label.move(15, 10)
            # QLabel("Hello!!!", self).move(95, 12)
            # ============================================
            # box layout
            # okButton = QPushButton("OK")
            # cancelButton = QPushButton("Cancel")
            #
            # hbox = QHBoxLayout()
            # # horizontal center
            # hbox.addStretch(1)
            # hbox.addWidget(okButton)
            # hbox.addWidget(cancelButton)
            # hbox.addStretch(1)
            #
            # # self.setLayout(hbox)
            # vbox = QVBoxLayout()
            # vbox.addStretch(1)
            # vbox.addLayout(hbox)
            # self.setLayout(vbox)
            # ============================================
            # grid layout
            grid = QGridLayout()
            self.setLayout(grid)

            names = [
                'Cls', 'Bck', '', 'Close',
                '7', '8', '9', '/',
                '4', '5', '6', '*',
                '1', '2', '3', '-',
                '0', '.', '=', '+'
            ]

            positions = [(i, j) for i in range(5) for j in range(4)]
            print(len(positions), len(names))

            for position, name in zip(positions, names):
                print(">", position, name)

                if name == '':
                    continue
                button = QPushButton(name)
                grid.addWidget(button, *position)

            self.setGeometry(300, 300, 250, 150)
            self.show()

    app = QtWidgets.QApplication([])
    ex = Example()
    sys.exit(app.exec_())

def demo_grid_span():
    class Example(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()

        def initUI(self):
            title = QLabel("Title")
            author = QLabel("Author")
            review = QLabel("Review")

            titleEdit = QLineEdit()
            authorEdit = QLineEdit()
            reviewEdit = QTextEdit()

            grid = QGridLayout()

            # set spacing between widgets
            grid.setSpacing(10)

            grid.addWidget(title, 1, 0)
            grid.addWidget(author, 2, 0)
            grid.addWidget(review, 3, 0)

            grid.addWidget(titleEdit, 1, 1)
            grid.addWidget(authorEdit, 2, 1)
            grid.addWidget(reviewEdit, 3, 1, 5, 1)  # rowSpan = 5, columnSpan = 1

            self.setLayout(grid)
            self.setGeometry(300, 300, 350, 300)
            self.setWindowTitle("Review")
            self.show()

    app = QApplication([])
    ex = Example()
    sys.exit(app.exec_())

# When we call the application's exec_() method, the application enters the main loop.
# The main loop fetches events and sends them to the objects.
def demo_signals_slots():

    # Objects created from a QObject can emit signals
    class Communicate(QObject):
        closeApp = pyqtSignal()

    class Example(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()

        def initUI(self):
            self.c = Communicate()
            self.c.closeApp.connect(self.close)

            lcd = QLCDNumber(self)
            sld = QSlider(Qt.Horizontal, self)

            x, y = 0, 0
            self.text = "x: {0}, y: {1}"
            text = self.text.format(x, y)
            self.label = QLabel(text, self)

            btn1 = QPushButton("btn1", self)
            btn2 = QPushButton("btn2", self)
            btn1.clicked.connect(self.buttonClicked)
            btn2.clicked.connect(self.buttonClicked)
            self.btn1 = btn1

            hbox = QHBoxLayout()
            hbox.addWidget(btn1)
            hbox.addWidget(btn2)

            vbox = QVBoxLayout()
            vbox.addWidget(self.label)
            vbox.addWidget(lcd)
            vbox.addWidget(sld)
            vbox.addLayout(hbox)
            vbox.setSpacing(20)

            self.setLayout(vbox)
            sld.valueChanged.connect(lcd.display)

            # Mouse tracking is disabled by default
            self.setMouseTracking(True)

            self.setGeometry(0, 0, 300, 200)
            self.show()

        # reimplement the keyPressEvent() event handler
        def keyPressEvent(self, e: QtGui.QKeyEvent) -> None:
            if e.key() == Qt.Key_Space:
                print("诶?!")
            if e.key() == Qt.Key_Escape:
                self.close()

        def mouseMoveEvent(self, a0: QtGui.QMouseEvent) -> None:
            x = a0.x()
            y = a0.y()
            text = self.text.format(x, y)
            self.label.setText(text)

        def buttonClicked(self):
            # We determine the signal source by calling the sender() method.
            sender = self.sender()
            self.label.setText(sender.text() + " was pressed")

            if sender == self.btn1:
                self.c.closeApp.emit()

    app = QApplication([])
    ex = Example()
    sys.exit(app.exec_())

def demo_dialog():
    class Example(QWidget):

        def __init__(self):
            super().__init__()

            self.initUI()

        def initUI(self):
            # =====================================================
            # Input Dialog
            self.btn = QPushButton('Input', self)
            self.btn.move(20, 20)
            self.btn.clicked.connect(self.showDialog)

            self.le = QLineEdit(self)
            self.le.move(130, 22)

            # =====================================================
            # Color Dialog
            col = QColor(0, 0, 0)

            self.btn_color = QPushButton('Color', self)
            self.btn_color.move(20, 50)
            self.btn_color.clicked.connect(self.showColorDialog)

            self.frm = QFrame(self)
            self.frm.setStyleSheet("QWidget { background-color: %s }"
                                   % col.name())
            self.frm.setGeometry(130, 50, 100, 100)
            # =====================================================
            # File Dialog
            self.btn_file = QPushButton('File', self)
            self.btn_file.move(20, 180)
            self.btn_file.clicked.connect(self.showFileDialog)

            textEdit = QTextEdit(self)
            textEdit.setGeometry(130, 180, 100, 100)
            self.textEdit = textEdit
            # =====================================================
            # Font Dialog
            self.btn_font = QPushButton('File', self)
            self.btn_font.move(20, 300)
            self.btn_font.clicked.connect(self.showFontDialog)

            self.label = QLabel("Knowledge only matters", self)
            self.label.move(130, 300)
            # =====================================================

            self.setGeometry(300, 300, 300, 650)
            self.setWindowTitle('dialog')
            self.show()

        def showDialog(self):
            text, ok = QInputDialog.getText(self, 'Input Dialog',
                                            'Enter your name:')

            if ok:
                self.le.setText(str(text))

        def showColorDialog(self):
            col = QColorDialog.getColor()
            if col.isValid():
                self.frm.setStyleSheet("QWidget { background-color: %s }"
                                       % col.name())
                print(col.name())

        def showFileDialog(self):
            # fname = QFileDialog.getOpenFileName(self, 'Open file', '.')

            file_tuple = QFileDialog.getOpenFileNames(self, 'Open files', '.')
            fname = file_tuple[0]
            print(type(fname))
            print(fname)
            # fname_sorted = sorted(fname, key=lambda x: x)
            # print("1 ", fname)
            # print("2 ", fname_sorted)
            return

            if fname[0]:
                f = open(fname[0], 'r')

                with f:
                    data = f.read()
                    self.textEdit.setText(data)

        def showFontDialog(self):
            font, ok = QFontDialog.getFont()
            if ok:
                self.label.setFont(font)

    app = QApplication([])
    ex = Example()
    sys.exit(app.exec_())

def demo_widgets():
    class Example(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()

        def initUI(self):
            vbox = QVBoxLayout()

            # QLabel with QPixmap
            label = QLabel(self)
            label.setPixmap(QPixmap("res/icon.jpg"))
            label.setVisible(True)
            vbox.addWidget(label)
            self.label = label

            # checkbox
            # A QCheckBox is a widget that has two states: on and off
            cb = QCheckBox("show something", self)
            cb.toggle()
            cb.stateChanged.connect(self.changeTitle)
            cb.resize(cb.sizeHint())

            vbox.addWidget(cb)

            hbox = QHBoxLayout()

            # toggle
            toggle1 = QPushButton("Toggle1", self)
            toggle1.setCheckable(True)
            toggle1.clicked[bool].connect(self.toggle)

            toggle2 = QPushButton("Toggle2", self)
            toggle2.setCheckable(True)
            toggle2.clicked.connect(self.toggle)

            hbox.addWidget(toggle1)
            hbox.addWidget(toggle2)

            vbox.addLayout(hbox)

            # slider
            slider = QSlider(Qt.Horizontal, self)
            slider.valueChanged[int].connect(self.changeSliderVal)

            vbox.addWidget(slider)

            # progressbar
            # A progress bar is a widget that is used when we process lengthy tasks.
            hbox2 = QHBoxLayout()
            self.pbar = QProgressBar(self)
            btn_pbar = QPushButton("start", self)
            btn_pbar.clicked.connect(self.doAction)
            self.btn_pbar = btn_pbar

            self.timer = QBasicTimer()
            self.step = 0

            hbox2.addWidget(self.pbar)
            hbox2.addWidget(btn_pbar)
            vbox.addLayout(hbox2)

            # QCalendarWidget
            calendar = QCalendarWidget(self)
            calendar.setGridVisible(True)
            calendar.clicked[QDate].connect(self.showDate)

            self.labelDate = QLabel("labelDate", self)
            vbox.addWidget(calendar)
            vbox.addWidget(self.labelDate)

            self.setLayout(vbox)

            self.setStyleSheet("QWidget { background-color: %s }" % "#fff")
            # self.setGeometry(50, 50, 400, 600)
            self.show()

        def changeTitle(self, state):
            checked = state == Qt.Checked

            if checked:
                self.setWindowTitle("Hello Widgets")
            else:
                self.setWindowTitle("-")

            self.label.setVisible(checked)

        def toggle(self, pressed):
            source = self.sender()
            print(source.text(), pressed)

            col = "#ffffff"

            if pressed:
                if source.text() == "Toggle1":
                    col = "#894522"
                elif source.text() == "Toggle2":
                    col = "#32a14d"

            self.setStyleSheet("QWidget { background-color: %s }" % col)

        def changeSliderVal(self, val):
            print("valueChanged ", val)

            if val > 50:
                self.label.setPixmap(QPixmap("res/h.png"))
            else:
                self.label.setPixmap(QPixmap("res/icon.jpg"))

        def doAction(self):
            if self.step >= 100:
                self.btn_pbar.setText("start")
                self.step = 0
                self.pbar.setValue(self.step)
                return

            if self.timer.isActive():
                self.timer.stop()
                self.btn_pbar.setText("start")
            else:
                self.timer.start(50, self)
                self.btn_pbar.setText("stop")

        # Each QObject and its descendants have a timerEvent() event handler.
        # In order to react to timer events, we reimplement the event handler.
        def timerEvent(self, e) -> None:
            if self.step >= 100:
                self.timer.stop()
                self.btn_pbar.setText("finished")
            else:
                self.step = self.step + 1
                self.pbar.setValue(self.step)

        def showDate(self, date: QDate):
            # self.labelDate.setText(date.toString(Qt.DefaultLocaleLongDate))
            self.labelDate.setText(date.toString())

    app = QApplication([])
    ex = Example()
    sys.exit(app.exec_())

def demo_widgets2():
    class Example(QWidget):
        def __init__(self):
            super().__init__()
            # self.initUI()
            # self.initSplitter()
            self.initComboBox()

        def initUI(self):
            print("demo_widgets2.initUI")
            self.label = QLabel(self)
            self.edit = QLineEdit(self)
            self.edit.textChanged.connect(self.onTextChanged)

            vbox = QVBoxLayout()
            vbox.addWidget(self.label)
            vbox.addWidget(self.edit)

            self.setLayout(vbox)
            self.show()

        def onTextChanged(self, text):
            self.label.setText(text)
            # self.label.adjustSize()
            print(self.label.size())

        def initSplitter(self):
            print("demo_widgets2.initSplitter")
            hbox = QHBoxLayout(self)
            # hbox = QVBoxLayout(self)

            # QSplitter lets the user control the size of child widgets by dragging the boundary between its children.
            topleft = QFrame(self)
            topright = QFrame(self)
            bottom = QFrame(self)

            # We use a styled frame in order to see the boundaries between the QFrame widgets.
            topleft.setFrameShape(QFrame.StyledPanel)
            topright.setFrameShape(QFrame.StyledPanel)
            bottom.setFrameShape(QFrame.StyledPanel)

            # QLabel("a label", topleft)

            splitter1 = QSplitter(Qt.Horizontal)
            splitter2 = QSplitter(Qt.Vertical)

            splitter1.addWidget(topleft)
            splitter1.addWidget(topright)

            splitter2.addWidget(splitter1)
            splitter2.addWidget(bottom)

            hbox.addWidget(splitter2)

            self.setLayout(hbox)
            self.setGeometry(300, 300, 300, 200)
            self.show()

        def initComboBox(self):
            self.lbl = QLabel("Ubuntu", self)

            combo = QComboBox(self)

            # These are the names of Linux distros.
            combo.addItem("Ubuntu")
            combo.addItem("Mandriva")
            combo.addItem("Fedora")
            combo.addItem("Arch")
            combo.addItem("Gentoo")

            combo.move(50, 50)
            self.lbl.move(50, 150)

            combo.activated[str].connect(self.onActivated)

            self.setGeometry(300, 300, 300, 200)
            self.setWindowTitle('QComboBox')
            self.show()

        def onActivated(self, text):
            self.lbl.setText(text)
            self.lbl.adjustSize()
            print(text, type(text))

    app = QApplication([])
    ex = Example()
    sys.exit(app.exec_())

def demo_button_drag_drop():
    class Button(QPushButton):
        def __init__(self, title, parent):
            super().__init__(title, parent)

        def mouseMoveEvent(self, e: QtGui.QMouseEvent) -> None:
            if e.buttons() != Qt.RightButton:
                return

            mineData = QMimeData()
            mineData.setText("mineData in MouseMoveEvent")

            drag = QDrag(self)
            drag.setMimeData(mineData)
            drag.setHotSpot(e.pos() - self.rect().topLeft())

            dropAction = drag.exec_(Qt.MoveAction)

        def mousePressEvent(self, e: QtGui.QMouseEvent) -> None:
            # Notice that we call mousePressEvent() method on the parent as well.
            # Otherwise, we would not see the button being pushed.
            super().mousePressEvent(e)

            if e.button() == Qt.LeftButton:
                print("press")

    class Example(QWidget):
        def __init__(self):
            super().__init__()
        #     self.initUI()
        #
        # def initUI(self):
            self.setAcceptDrops(True)

            self.button = Button("Button", self)
            self.button.move(100, 65)

            self.setWindowTitle("Click or Move")
            self.setGeometry(300, 300, 280, 150)

        def dragEnterEvent(self, e: QtGui.QDragEnterEvent) -> None:
            e.accept()

        def dropEvent(self, e: QtGui.QDropEvent) -> None:
            position = e.pos()
            self.button.move(position)
            print("e.mimeData().text():")
            print(e.mimeData().text())

            e.setDropAction(Qt.MoveAction)
            e.accept()

    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()

def demo_painter():
    class Example(QWidget):

        def __init__(self):
            super().__init__()
            self.text = "Лев Николаевич Толстой\nАнна Каренина"
            self.show()

        # The painting is done within the paintEvent() method.
        # The painting code is placed between the begin() and end() methods of the QPainter object.
        def paintEvent(self, event: QtGui.QPaintEvent) -> None:
            print("paint event!", self.size())
            qp = QPainter()
            qp.begin(self)

            qp.setBrush(Qt.darkGray)
            qp.drawRect(self.rect())

            qp.setRenderHint(QPainter.Antialiasing)

            self.drawRectangles(qp)
            self.drawText(event, qp)
            self.drawPoints(qp)
            self.drawLines(qp)
            self.drawBrushes(qp)
            self.drawBezierCurve(qp)
            qp.end()

        def drawText(self, event, qp: QPainter):
            qp.setPen(QColor(168, 34, 3))
            qp.setFont(QFont("Decorative", 10))
            qp.drawText(event.rect(), Qt.AlignCenter, self.text)

        def drawPoints(self, qp: QPainter):
            # qp.setPen(Qt.red)
            qp.setPen(Qt.yellow)

            size = self.size()

            for i in range(1000):
                x = random.randint(1, size.width()-1)
                y = random.randint(1, size.height() - 1)
                qp.drawPoint(x, y)

        def drawRectangles(self, qp):
            col = QColor(0, 0, 0)
            col.setNamedColor('#d4d4d4')
            qp.setPen(col)

            # A brush is an elementary graphics object which is used to draw the background of a shape.
            qp.setBrush(QColor(200, 0, 0))
            qp.drawRect(10, 15, 90, 60)

            qp.setBrush(QColor(255, 80, 0, 160))
            qp.drawRect(130, 15, 90, 60)

            qp.setBrush(QColor(25, 0, 90, 200))
            qp.drawRect(250, 15, 90, 60)

        def drawLines(self, qp):
            # The QPen is an elementary graphics object.
            # It is used to draw lines, curves and outlines of rectangles, ellipses, polygons, or other shapes.
            pen = QPen(Qt.black, 2, Qt.SolidLine)

            qp.setPen(pen)
            qp.drawLine(20, 40, 250, 40)

            pen.setStyle(Qt.DashLine)
            qp.setPen(pen)
            qp.drawLine(20, 80, 250, 80)

            pen.setStyle(Qt.DashDotLine)
            qp.setPen(pen)
            qp.drawLine(20, 120, 250, 120)

            pen.setStyle(Qt.DotLine)
            qp.setPen(pen)
            qp.drawLine(20, 160, 250, 160)

            pen.setStyle(Qt.DashDotDotLine)
            qp.setPen(pen)
            qp.drawLine(20, 200, 250, 200)

            pen.setStyle(Qt.CustomDashLine)
            # Odd numbers define a dash, even numbers space.
            pen.setDashPattern([1, 4, 15, 4])
            qp.setPen(pen)
            qp.drawLine(20, 240, 250, 240)

        def drawBrushes(self, qp):
            # QBrush is an elementary graphics object.
            # It is used to paint the background of graphics shapes,
            # such as rectangles, ellipses, or polygons.
            # A brush can be of three different types:
            # a predefined brush, a gradient, or a texture pattern.
            brush = QBrush(Qt.SolidPattern)

            dx, dy = 360, 20

            qp.setBrush(brush)
            qp.drawRect(10 + dx, 15 + dy, 90, 60)

            brush.setStyle(Qt.Dense1Pattern)
            qp.setBrush(brush)
            qp.drawRect(130 + dx, 15 + dy, 90, 60)

            brush.setStyle(Qt.Dense2Pattern)
            qp.setBrush(brush)
            qp.drawRect(250 + dx, 15 + dy, 90, 60)

            brush.setStyle(Qt.DiagCrossPattern)
            qp.setBrush(brush)
            qp.drawRect(10 + dx, 105 + dy, 90, 60)

            brush.setStyle(Qt.Dense5Pattern)
            qp.setBrush(brush)
            qp.drawRect(130 + dx, 105 + dy, 90, 60)

            brush.setStyle(Qt.Dense6Pattern)
            qp.setBrush(brush)
            qp.drawRect(250 + dx, 105 + dy, 90, 60)

            brush.setStyle(Qt.HorPattern)
            qp.setBrush(brush)
            qp.drawRect(10 + dx, 195 + dy, 90, 60)

            brush.setStyle(Qt.VerPattern)
            qp.setBrush(brush)
            qp.drawRect(130 + dx, 195 + dy, 90, 60)

            brush.setStyle(Qt.BDiagPattern)
            qp.setBrush(brush)
            qp.drawRect(250 + dx, 195 + dy, 90, 60)

        def drawBezierCurve(self, qp:QPainter):
            # brush = QBrush(Qt.HorPattern)
            # brush.setStyle(Qt.HorPattern)
            # qp.setBrush(brush)

            pen = QPen(Qt.darkGreen, 2, Qt.SolidLine)
            qp.setPen(pen)
            qp.setBrush(Qt.transparent)

            path = QPainterPath()
            dx, dy = 0, 240
            path.moveTo(30 + dx, 30 + dy)
            # The curve is created with cubicTo() method
            # starting point, control point, and ending point
            path.cubicTo(30 + dx, 30 + dy, 200 + dx, 350 + dy, 350 + dx, 30 + dy)

            qp.drawPath(path)

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

def demo_custom_widget():
    MAX_CAPACITY = 700
    OVER_CAPACITY = 750

    class Communicate(QObject):
        updateBW = pyqtSignal(int)

    class BurningWidget(QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()

        def initUI(self):
            self.setMinimumSize(1, 30)
            self.value = 75
            self.num = [75, 150, 225, 300, 375, 450, 525, 600, 675]

        def setValue(self, value):
            self.value = value

        def paintEvent(self, e: QtGui.QPaintEvent) -> None:
            qp = QPainter()
            qp.begin(self)
            self.drawWidget(qp)
            qp.end()

        def drawWidget(self, qp):

            font = QFont("Serif", 7, QFont.Light)
            qp.setFont(font)

            size = self.size()
            w = size.width()
            h = size.height()

            step = int(round(w / 10))

            till = int(((w / OVER_CAPACITY) * self.value))
            full = int(((w / OVER_CAPACITY) * MAX_CAPACITY))

            if self.value >= MAX_CAPACITY:
                qp.setPen(QColor(255, 255, 255))
                qp.setBrush(QColor(255, 255, 184))
                qp.drawRect(0, 0, full, h)

                qp.setPen(QColor(255, 175, 175))
                qp.setBrush(QColor(255, 175, 175))
                qp.drawRect(full, 0, till - full, h)
            else:
                qp.setPen(QColor(255, 255, 255))
                qp.setBrush(QColor(255, 255, 184))
                qp.drawRect(0, 0, till, h)

            pen = QPen(QColor(20, 20, 20), 1, Qt.SolidLine)
            qp.setPen(pen)
            qp.setBrush(Qt.NoBrush)
            qp.drawRect(0, 0, w - 1, h - 1)

            j = 0
            for i in range(step, 10*step, step):
                #  draw the vertical lines
                qp.drawLine(i, 0, i, 5)

                # We use font metrics to draw the text.
                # We must know the width of the text in order to center it around the vertical line.
                metrics = qp.fontMetrics()
                fw = metrics.width(str(self.num[j]))
                qp.drawText(i - fw/2, h/2, str(self.num[j]))

                j = j + 1

    class Example(QWidget):
        def __init__(self):
            super().__init__()

            sld = QSlider(Qt.Horizontal, self)
            sld.setFocusPolicy(Qt.NoFocus)
            sld.setRange(1, OVER_CAPACITY)
            sld.setValue(75)
            sld.setGeometry(30, 40, 150, 30)

            self.c = Communicate()
            self.wid = BurningWidget()
            self.c.updateBW[int].connect(self.wid.setValue)
            sld.valueChanged[int].connect(self.changeValue)

            hbox = QHBoxLayout()
            hbox.addWidget(self.wid)

            vbox = QVBoxLayout()
            vbox.addStretch(1)
            vbox.addLayout(hbox)
            self.setLayout(vbox)

            self.setGeometry(300, 300, 390, 210)
            self.setWindowTitle("Burning Widget")
            # self.show()

        def changeValue(self, value):
            self.c.updateBW.emit(value)
            self.wid.repaint()

    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

def demo_drop_file():
    class DropFileWidget(QWidget):
        def __init__(self):
            super().__init__()

            vbox = QVBoxLayout()
            textEdit = QTextEdit(self)
            self.textEdit = textEdit

            textEdit.setAcceptDrops(False)
            # print("textEdit.acceptDrops() = ", textEdit.acceptDrops())
            # textEdit.dropEvent[QtGui.QDropEvent].connect(self.dropEvent)

            label = QLabel("Drag Text File", self)
            label.setAlignment(Qt.AlignCenter)
            print("label.acceptDrops()", label.acceptDrops())

            # ========================================================
            # # box layout
            #
            # box_1 = QHBoxLayout()
            #
            # box_1.addStretch(1)
            # box_1.addWidget(label)
            # box_1.addStretch(1)
            #
            # vbox.addLayout(box_1)
            # vbox.addWidget(label)
            #
            # # vbox.addStretch(1)
            # vbox.addWidget(textEdit)
            # self.setLayout(vbox)
            # ========================================================
            # grid layout
            grid = QGridLayout()

            grid.addWidget(label, 0, 0, 1, 2)
            grid.addWidget(textEdit, 1, 1, 3, 1)

            self.setLayout(grid)
            # ========================================================

            self.setAcceptDrops(True)
            self.setGeometry(100, 100, 400, 300)
            self.setWindowTitle("Drop File To Blank Area")
            self.show()

        def dragEnterEvent(self, e: QtGui.QDragEnterEvent) -> None:
            print("dragEnterEvent")
            e.accept()

        def dropEvent(self, e: QtGui.QDropEvent) -> None:
            print("drop event received..")
            print(e.mimeData().formats())
            # ==================================================

            # file_path = os.path.abspath(e.mimeData().text())
            # print(file_path)

            for url in e.mimeData().urls():
                # file_path = url.toLocalFile().toLocal8Bit().data()  # error: toLocal8Bit
                # print(url.toLocalFile())
                print()

                qurl = QUrl(url)
                file_path = qurl.toLocalFile()
                print("file_path = ", file_path)

                f = QFile(file_path)
                print("exist? ", f.exists())

                if f.exists():
                    f.open(QIODevice.ReadOnly | QIODevice.Text)
                    isOpen = f.isOpen()
                    print("f.isOpen() = ", isOpen)

                    if isOpen:
                        text_stream = QTextStream(f)
                        text_stream.setCodec(QTextCodec.codecForName("UTF-8"))
                        text_stream.setAutoDetectUnicode(True)
                        text = text_stream.readAll()
                        self.textEdit.setText(text)
                        print(text)
            # ==================================================
            e.accept()

    app = QApplication([])
    w = DropFileWidget()
    sys.exit(app.exec_())
    return

def demo_file():
    file_path = "out/temp/playQT.spec"
    file_path = os.path.abspath(file_path)

    f = QFile(file_path)
    # ret = f.copy("out/temp/playQT.spec.new.12")
    # f = QFile("out/temp/playQT.spec.new")

    ret = f.exists()
    print("exists ret = ", ret)

    f.open(QIODevice.ReadOnly | QIODevice.Text | QIODevice.Truncate)
    print("f.isOpen() ", f.isOpen())

    text_stream = QTextStream(f)
    s = text_stream.readAll()

    print(type(s))
    print("> len(s) = ", len(s))
    print("f.error() = ", f.error(), "QFileDevice.NoError = ", QFileDevice.NoError)
    print("errorString = ", f.errorString())
    f.close()
    print("f.isOpen() ", f.isOpen())

def demo_dir():
    out_path = os.path.abspath("out")
    # out_path = os.path.join(out_path, "d1")
    d = QDir(out_path)
    print(d.absolutePath())
    print("d.exists()", d.exists())
    print("d.exists('a.txt')", d.exists('a.txt'))  # check file exist
    print("d.exists('temp')", d.exists('temp'))  # check directory exist

    # remove empty directory
    # ret = d.rmdir("d1")
    # print("rmdir = ", ret)

    # remove directory
    # ret = d.removeRecursively()
    # print("ret = ", ret)

    # make a directory
    # d.mkdir("d1")

    # make directory path
    # ret = d.mkpath("d_1/d_2/d_3")
    # print("ret = ", ret)
    # ret = d.mkpath("d_1/d_4/d_5")
    # print("ret = ", ret)

    # remove directory path, if directory is empty
    # ret = d.rmpath("d_1/d_4/d_5")
    # print("ret = ", ret)

    ret = d.cd("d_1")
    print("cd = ", ret)
    print(d.absolutePath())
    if ret:
        ret = d.removeRecursively()
        print("removeRecursively() ret = ", ret)
    else:
        ret = d.mkpath("d_1/d_2/d_3")
        print("ret = ", ret)

        ret = d.mkpath("d_1/d_4/d_5")
        print("ret = ", ret)

        ret = d.cd("d_1/d_4/d_5")
        if ret:
            f = QFile(d.absoluteFilePath("a.txt"))
            f.open(QIODevice.ReadWrite | QIODevice.Text)
            text_stream = QTextStream(f)
            text_stream << \
"""begin
new line
next...
another...
end"""

def drop_display():
    class FileLineEdit(QLineEdit):
        drop_signal = pyqtSignal(str)

        def dropEvent(self, e: QtGui.QDropEvent) -> None:
            for url in e.mimeData().urls():
                qurl = QUrl(url)
                file_path = qurl.toLocalFile()
                self.setText(file_path)
                self.selectAll()
                self.drop_signal.emit(file_path)
                break

    class DisplayAbsolutePathWidget(QtWidgets.QWidget):
        def __init__(self):
            super().__init__()
            self.initUI()

        def initUI(self):
            label = QLabel("drag file in: ", self)
            line_edit = FileLineEdit("", self)
            self.line_edit = line_edit

            layout = QGridLayout()
            layout.addWidget(label, 0, 0)
            layout.addWidget(line_edit, 0, 1, 0, 5)

            self.setLayout(layout)
            self.setAcceptDrops(True)
            self.setMinimumWidth(567)
            self.setMaximumHeight(self.sizeHint().height())

        def dragEnterEvent(self, e: QtGui.QDragEnterEvent) -> None:
            e.accept()

        def dropEvent(self, e: QtGui.QDropEvent) -> None:
            self.line_edit.dropEvent(e)

    class SampleWindow(QMainWindow):
        def __init__(self):
            super().__init__()
            qWidget = QWidget(self)

            widget = DisplayAbsolutePathWidget()
            widget.line_edit.drop_signal[str].connect(self.onDrop)

            box = QVBoxLayout()
            box.addWidget(widget)
            # box.addWidget(DisplayAbsolutePathWidget())

            self.label = QLabel(self)
            box.addWidget(self.label, alignment=Qt.AlignCenter)

            qWidget.setLayout(box)
            # self.layout().addWidget(widget)
            # self.setCentralWidget(widget)
            self.setCentralWidget(qWidget)

        def onDrop(self, file_path):
            self.label.setPixmap(QPixmap(file_path))

    app = QApplication([])
    # widget = DisplayAbsolutePathWidget()
    # widget.show()
    window = SampleWindow()
    window.show()
    sys.exit(app.exec_())

    return

def demo_graphicsview():
    class MyGroup(QGraphicsItemGroup):

        def __init__(self):
            super().__init__()

            self.setCursor(Qt.OpenHandCursor)
            self.setFlag(QGraphicsItem.ItemIsMovable)
            self.setFlag(QGraphicsItem.ItemIsSelectable, True)

        def paint(self, painter, option, widget):
            painter.setRenderHint(QPainter.Antialiasing)

            brush = QBrush(QColor("#33EE33"))
            pen = QPen(brush, 1.0)
            pen.setStyle(Qt.DotLine)
            # pen.setStyle(Qt.SolidLine)
            painter.setPen(pen)

            if self.isSelected():
                boundRect = self.boundingRect()
                painter.drawRect(boundRect)

    class Scene(QGraphicsScene):

        def __init__(self):
            super().__init__()

        def setGraphicsView(self, view: QGraphicsView):
            self._view = view

        def initScene(self):
            # 初始化的坐标是(0,0)的时候, 后面的setPos()才会生效
            # self.r1 = self.addRect(120, 248, 100, 50)
            self.r1 = self.addRect(0, 0, 100, 50)
            # self.r1.setFlag(QGraphicsItem.ItemIsMovable)
            # self.r1.setFlag(QGraphicsItem.ItemIsSelectable, True)

            self.r2 = self.addRect(0, 0, 50, 50)
            self.r2.setFlag(QGraphicsItem.ItemIsMovable)
            self.r2.setFlag(QGraphicsItem.ItemIsSelectable, True)

            self.c = self.addEllipse(30, 150, 60, 60)
            self.c.setFlag(QGraphicsItem.ItemIsMovable)
            self.c.setFlag(QGraphicsItem.ItemIsSelectable, True)

            self.l = self.addLine(2.0, 2.0, 1000.0, 0.0, QPen(QColor("#ee8090"), 2.0, Qt.DashLine, Qt.RoundCap))
            self.addRect(self.r2.rect().width() + 2, 2, 50, 50)

            self.r2.setPos(2, 2)
            bottomRight = self.r2.rect().bottomRight()
            print(int(bottomRight.x()), int(bottomRight.y()))

            p0 = self.r2.mapToParent(int(bottomRight.x()), int(bottomRight.y()))
            p0 = self.r2.mapToParent(50, 50)
            print("p0 = ", p0.x(), p0.y())
            # setPos() 需要传入 parent 坐标系内的坐标
            self.r1.setPos(p0)

            # self.addRect(p0.x(), p0.y(), 150, 150)

        def mouseMoveEvent(self, e):
            p0 = self.r2.mapToScene(self.r2.pos())
            p = e.scenePos()
            self.r1.setPos(p)
            self.l.setLine(p0.x(), p0.y(), p.x(), p.y())

    class View(QGraphicsView):

        def __init__(self):
            super().__init__()

            self.setGeometry(0, 0, 300, 300)

            policy = Qt.ScrollBarAlwaysOff

            self.setVerticalScrollBarPolicy(policy)
            self.setHorizontalScrollBarPolicy(policy)
            self.setRenderHint(QPainter.Antialiasing)
            self.setDragMode(QGraphicsView.RubberBandDrag)

            self.init()

        def init(self):
            self.group = None
            self.scene = Scene()
            self.scene.setGraphicsView(self)
            self.scene.initScene()
            self.setSceneRect(0, 0, 300, 300)
            self.setScene(self.scene)

        def keyPressEvent(self, event):

            key = event.key()

            if key == Qt.Key_U:

                if self.group != None and self.group.isSelected():

                    items = self.group.childItems()
                    self.scene.destroyItemGroup(self.group)
                    self.group = None

                    for item in items:
                        item.setSelected(False)

            if key == Qt.Key_G:

                if self.group:
                    return

                selectedItems = self.scene.selectedItems()

                if len(selectedItems) > 0:
                    self.group = MyGroup()

                    for item in selectedItems:
                        self.group.addToGroup(item)

                    self.scene.addItem(self.group)

    class Example(QWidget):

        def __init__(self):
            super().__init__()

            self.initUI()

        def initUI(self):
            # hbox = QHBoxLayout()
            self.view = View()
            # btn = QPushButton("show/hide", self)
            # btn.clicked.connect(self.onClicked)

            # hbox.addWidget(btn)
            # hbox.addWidget(self.view)
            # hbox.addStretch(1)

            # self.setLayout(hbox)
            self.view.setParent(self)
            self.setWindowTitle("Grouping")
            self.setGeometry(250, 150, 300, 300)

        def onClicked(self):
            print(self.view.isVisible())
            self.view.setVisible(not self.view.isVisibleTo(self))

    app = QApplication([])
    ex = Example()
    ex.show()
    sys.exit(app.exec_())

if __name__ == "__main__":
    print("case __main__")
    # demo_ui()
    # test_date()
    # demo_simple_window()
    # demo_Example()
    # demo_MainWindow()
    # demo_Layout()
    # demo_grid_span()
    # demo_signals_slots()
    # demo_dialog()
    # demo_widgets()
    # demo_widgets2()
    # demo_button_drag_drop()
    # demo_painter()
    # demo_custom_widget()
    # demo_drop_file()
    # demo_file()
    # demo_dir()
    # drop_display()
    demo_graphicsview()


"""
    Author:Hemanth Kumar Veeranki
    Nick:Harry7

    This File is one of modules written for the game Donkey Kong

"""

import pygame
from random import randint as rand

"""

Map values for
1. Coins -   2
2. Fireball- 5
3. Ladders - 3
4. Walls and Floors - 1

"""

__author__="Hemanth Kumar Veeranki"
__version__ = "1.0.1"
__maintainer__ = "Hemanth Kumar Veeranki"
__email__ = "hemanth.veeranki@students.iiit.ac.in"
__status__ = "Development"

class Fireball:

    """ This Class basically deals with all tasks of Fireballs """

    def __init__(self):

        """
        This is default constructor. It initialises all variable
        1.Xpos contains x co-ordinates of fireballs similarly the Ypos has heights
        2.side determines which side the fireball has to move
        """

        self.Xpos=[]
        self.Ypos=[]
        self.side=[]
        self.infall=[]
        self.image=pygame.image.load('fireball.jpg')
        self.image=pygame.transform.scale(self.image,(15,20))
        self.rect=self.image.get_rect()
    def checkWall(self,Map,x,y):
        return Map[y][x]==1
    def Makefireballs(self,Map,xpos,ypos):

        """

        This Functions generates a fireball from monkey
        It takes the Map,Xpos,Ypos variables of Board class's instance created

        """

        if(Map[ypos][xpos]==0):
            Map[ypos][xpos]=5
            self.Xpos.append(xpos)
            self.Ypos.append(ypos)
            self.side.append(1)
            self.infall.append(0)

    def DrawFireball(self,Map,display):

        """

        This Functions Draws Fireballs to the display
        It takes Map variable of Board class instance created and display surface as variables

        """

        x=15
        y=20
        for k in xrange(len(self.Xpos)):
            j=self.Xpos[k]
            i=self.Ypos[k]
            if Map[i][j]>=5 and Map[i][j]!=100:
                    rect=self.rect
                    rect=rect.move((j*x,i*y))
                    display.blit(self.image,rect)

    def move(self,game):

        """

         This function takes care of moving fireballs and eliminating them if they go to the end
         It takes instance of Board class created in main_game file

        """

        # We store indices of fireballs came to the end in this variable
        marked=[]
        for i in range(len(self.Xpos)):

            x=self.Xpos[i]
            y=self.Ypos[i]
            s=self.side[i]
            #Instead of making its value as 5 we add 5 and when removing we subtract 5 so as to  take care of fireball coming onto other objects
            game.Map[y][x]-=5

            #This decides the probability of going down the ladder or getting down through end of floor

            p=rand(0,1)

            # Taking care of Ladders and getting down through a ladder
            if self.infall[i]==1:
                y+=1
                if game.Map[y+1][x]!=0:
                    self.infall[i]=0
            elif p==1 and  game.Map[y+1][x]==3:
                y+=1
                if self.checkWall(game.Map,x,y):
                    y-=1
            elif game.Map[y][x]==3 and game.Map[y+1][x]!=1:
                y+=1
                if self.checkWall(game.Map,x,y):
                    y-=1

            elif game.Map[y-1][x]==3 and game.Map[y+1][x]==3:
                y+=1
                if self.checkWall(game.Map,x,y):
                    y-=1
            elif y==28:
                    x-=1
                    if x==1:
                        game.Map[y][x]-=5
                        marked.append(i)
            elif self.side[i]==1:

                # Dealing with normal moovment on floor
                x+=1
                if self.checkWall(game.Map,x,y):
                    self.side[i]=0
                    x-=2
            else:

                # Dealing with normal moovment on floor

                x-=1
                if self.checkWall(game.Map,x,y):
                    x+=2
                    self.side[i]=1

            if self.infall[i]!=1 and game.Map[y][x]==0 and game.Map[y+1][x]==0:
                self.infall[i]=1
            game.Map[y][x]+=5

            self.Xpos[i]=x
            self.Ypos[i]=y

            marked.sort()
            j=0
        # Eliminating the ones which reached the end

        for i in marked:
                self.Xpos.pop(i-j)
                self.Ypos.pop(i-j)
                self.side.pop(i-j)
                j+=1

        #Same as above


"""

This module contains functions needed to evaluate post selection
p-values for non polyhedral selection procedures through a variety of means.

These p-values appear for the group LASSO global null test as well as the nuclear norm
p-value test.

They are described in the `Kac Rice`_ paper.

.. _Kac Rice: http://arxiv.org/abs/1308.3020
.. _Spacings: http://arxiv.org/abs/1401.3889
.. _post selection LASSO: http://arxiv.org/abs/1311.6238

"""

import numpy as np
from scipy.stats import chi

from scipy.stats import norm as ndist, truncnorm
from scipy.integrate import quad

from mpmath import mp
mp.dps = 80

def norm_q(prob):
    r"""
    A multi-precision calculation of the
    standard normal quantile function:

    .. math::

       \int_{-\infty}^{q(p)} \frac{e^{-z^2/2}}{\sqrt{2\pi}} \; dz = p

    where $p$ is `prob`.

    Parameters
    ----------

    prob : float

    Returns
    -------

    quantile : float

    """
    return np.array(mp.erfinv(2*prob-1)*mp.sqrt(2))

def norm_pdf(observed):
    r"""
    A multi-precision calculation of the
    standard normal density function:

    .. math::

       \frac{e^{-T^2/2}}{\sqrt{2\pi}}

    where `T` is observed.

    Parameters
    ----------

    observed : float

    Returns
    -------

    density : float

    """
    return np.array(mp.npdf(observed))

def norm_interval(lower, upper):
    r"""
    A multiprecision evaluation of

    .. math::

        \Phi(U) - \Phi(L)

    Parameters
    ----------

    lower : float
        The lower limit $L$

    upper : float
        The upper limit $U$

    """
    if lower > 0 and upper > 0:
        return mp.ncdf(-lower) - mp.ncdf(-upper)
    else:
        return mp.ncdf(upper) - mp.ncdf(lower)

def truncnorm_cdf(observed, lower, upper):
    r"""
    Compute the truncated normal
    distribution function.

    .. math::

        \frac{\Phi(U) - \Phi(T)}{\Phi(U) - \Phi(L)}

    where $T$ is `observed`, $L$ is `lower_bound` and $U$ is `upper_bound`.

    Parameters
    ----------

    observed : float

    lower : float

    upper : float

    Returns
    -------

    P : float

    """
    x, a, b = observed, lower, upper

    x = max(x, a)
    x = min(x, b)

    if a > 0 and b > 0:
        Fx, Fa, Fb = mp.ncdf(-x), mp.ncdf(-a), mp.ncdf(-b)
        return float( ( Fa - Fx ) / ( Fa - Fb ) )
    else:
        Fx, Fa, Fb = mp.ncdf(x), mp.ncdf(a), mp.ncdf(b)
        return float( ( Fx - Fa ) / ( Fb - Fa ) )

def chi_pvalue(observed, lower_bound, upper_bound, sd, df, method='MC', nsim=1000):
    r"""

    Compute a truncated $\chi$ p-value based on the
    conditional survival function.

    Parameters
    ----------

    observed : float

    lower_bound : float

    upper_bound : float

    sd : float
        Standard deviation.

    df : float
        Degrees of freedom.

    method: string
        One of ['MC', 'cdf', 'sf']

    Returns
    -------

    pvalue : float

    Notes
    -----

    Let $T$ be `observed`, $L$ be `lower_bound` and $U$ be `upper_bound`,
    and $\sigma$ be `sd`.
    The p-value, for $L \leq T \leq U$ is

    .. math::

         \frac{P(\chi^2_k / \sigma^2 \geq T^2) - P(\chi^2_k / \sigma^2 \geq U^2)}
         {P(\chi^2_k / \sigma^2 \geq L^2) - P(\chi^2_k / \sigma^2 \geq U^2)}

    It can be computed using `scipy.stats.chi` either its `cdf` (distribution
    function) or `sf` (survival function) or evaluated
    by Monte Carlo if method is `MC`.

    """

    L, T, U = lower_bound, observed, upper_bound # shorthand

    if method == 'cdf':
        pval = ((chi.cdf(U / sd, df) - chi.cdf(T / sd, df)) /
                (chi.cdf(U / sd, df) - chi.cdf(L / sd, df)))
    elif method == 'sf':
        pval = ((chi.sf(U / sd, df) - chi.sf(T / sd, df)) /
                (chi.sf(U / sd, df) - chi.sf(L / sd, df)))
    elif method == 'MC':
        if df == 1:
            H = []
        else:
            H = [0]*(df-1)
        pval = general_pvalue(T / sd, L / sd, U / sd, H, nsim=nsim)
    else:
        raise ValueError('method should be one of ["cdf", "sf", "MC"]')
    if pval == 1: # the distribution functions may have failed -- use MC
        pval = general_pvalue(T / sd, L / sd, U / sd, H, nsim=50000)
    if pval > 1:
        pval = 1
    return pval

def gauss_poly(lower_bound, upper_bound, curvature, nsim=100):
    r"""
    Computes the integral of a polynomial times the
    standard Gaussian density over an interval.

    Introduced in `Kac Rice`_, display (33) of v2.

    Parameters
    ----------

    lower_bound : float

    upper_bound : float

    curvature : np.array
        A diagonal matrix related to curvature.
        It is assumed that `curvature + lower_bound I` is non-negative definite.

    nsim : int
        How many draws from $N(0,1)$ should we use?

    Returns
    -------

    integral : float

    Notes
    -----

    The return value is a Monte Carlo estimate of

    .. math::

        \int_{L}^{U} \det(\Lambda + z I)
        \frac{e^{-z^2/2\sigma^2}}{\sqrt{2\pi\sigma^2}} \, dz

    where $L$ is `lower_bound`, $U$ is `upper_bound` and $\Lambda$ is the
    diagonal matrix `curvature`.

    """

    T, H = lower_bound, curvature
    Z = np.fabs(np.random.standard_normal(nsim))
    keep = Z < upper_bound - T
    proportion = keep.sum() * 1. / nsim
    Z = Z[keep]
    if H != []:
        HT = H + T
        exponent = np.log(np.fabs(np.add.outer(Z, HT))).sum(1) - T*Z - T**2/2.
    else:
        exponent = - T*Z - T**2/2.
    C = exponent.max()

    return np.exp(exponent - C).mean() * proportion, C

def general_pvalue(observed, lower_bound, upper_bound, curvature, nsim=100):

    r"""
    Computes the integral of a polynomial times the
    standard Gaussian density over an interval.

    Introduced in `Kac Rice`_, display (35) of v2.

    Parameters
    ----------

    observed : float

    lower_bound : float

    upper_bound : float

    curvature : np.array
        A diagonal matrix related to curvature.
        It is assumed that `curvature + lower_bound I` is non-negative definite.

    nsim : int
        How many draws from $N(0,1)$ should we use?

    Returns
    -------

    integral : float

    Notes
    -----

    The return value is a Monte Carlo estimate of

    .. math::

        \frac{\int_{T}^{U} \det(\Lambda + z I)
        \frac{e^{-z^2/2\sigma^2}}{\sqrt{2\pi\sigma^2}} \, dz}
        {\int_{L}^{U} \det(\Lambda + z I)
        \frac{e^{-z^2/2\sigma^2}}{\sqrt{2\pi\sigma^2}} \, dz}

    where $T$ is `observed`, $L$ is `lower_bound`,
    $U$ is `upper_bound` and $\Lambda$ is the
    diagonal matrix `curvature`.

    """

    exponent_1, C1 = gauss_poly(observed, upper_bound, curvature, nsim=nsim)
    exponent_2, C2 = gauss_poly(lower_bound, upper_bound, curvature, nsim=nsim)

    return np.exp(C1-C2) * exponent_1 / exponent_2

class SelectionInterval(object):
    """
    Compute a selection interval for
    a Gaussian truncated to an interval.
    """

    def __init__(self, lower_bound, observed, upper_bound, sigma):
        self.lower_bound, self.observed, self.upper_bound, self.sigma = lower_bound, observed, upper_bound, sigma

    def pivot(self, exp):
        L, obs, U, sd = self.lower_bound, self.observed, self.upper_bound, self.sigma
        return truncnorm_cdf((obs-exp)/sd, (L-exp)/sd, (U-exp)/sd)

    def conf_int(self, lb, ub, alpha=0.05):
        F = lambda exp: self.pivot(exp)
        L = _find_root(F, 1.0 - 0.5 * alpha, lb, ub)
        U = _find_root(F, 0.5 * alpha, L, ub)
        return L, U

def _find_root(f, y, lb, ub, tol=1e-6):
    """
    searches for solution to f(x) = y in (lb, ub), where
    f is a monotone decreasing function
    """

    # make sure solution is in range
    a, b   = lb, ub
    fa, fb = f(a), f(b)

    # assume a < b
    if fa > y and fb > y:
        while fb > y :
            b, fb = b + (b-a), f(b + (b-a))
    elif fa < y and fb < y:
        while fa < y :
            a, fa = a - (b-a), f(a - (b-a))

    # determine the necessary number of iterations
    max_iter = int( np.ceil( ( np.log(tol) - np.log(b-a) ) / np.log(0.5) ) )

    # bisect (slow but sure) until solution is obtained
    for _ in xrange(max_iter):
        c, fc  = (a+b)/2, f((a+b)/2)
        if fc > y: a = c
        elif fc < y: b = c

    return c