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

import glob
import os
from pathlib import Path
import re
from setuptools import setup, Extension
import sys

from Cython.Build import cythonize

PACKAGE = "mint"

def getCondaVTK():
    """get the VTK installed by conda"""

    vtk_libs = [
        "vtkCommonComputationalGeometry",
        "vtkIOCore",
        "vtkIOLegacy",
        "vtkCommonExecutionModel",
        "vtkCommonDataModel",
        "vtkCommonTransforms",
        "vtkCommonMisc",
        "vtkCommonMath",
        "vtkCommonSystem",
        "vtkCommonCore",
        "vtksys",
    ]

    include_dir = Path(sys.exec_prefix) / Path("include")

    try:
        version = list(include_dir.glob("vtk-*"))[-1].name
    except IndexError:
        raise RuntimeError('ERROR: you need to "conda install vtk"')

    version = re.sub(r"vtk-", "", version)
    include_dir = str(include_dir / Path(f"vtk-{version}"))
    libraries_dir = str(Path(sys.exec_prefix) / Path("lib"))
    libraries = [f"{lib}-{version}" for lib in vtk_libs]
    result = {
        "VTK_VERSION": version,
        "VTK_INCLUDE_DIR": include_dir,
        "VTK_LIBRARIES_DIR": libraries_dir,
        "VTK_LIBRARIES": libraries,
    }
    return result

def getCondaNetCDF():
    """Get the NetCDF installed by conda."""

    include_dir = str(Path(sys.exec_prefix) / Path("include"))
    libraries_dir = str(Path(sys.exec_prefix) / Path("lib"))
    libraries = ["netcdf", "hdf5"]

    if not (include_dir / Path("netcdf.h")).exists():
        raise RuntimeError('ERROR: you need to "conda install libnetcdf"')

    result = {
        "NETCDF_INCLUDE_DIR": include_dir,
        "NETCDF_LIBRARIES_DIR": libraries_dir,
        "NETCDF_LIBRARIES": libraries,
    }
    return result

# extract the MINT version from file version.txt
with open("version.txt") as f:
    VERSION = f.read().strip()

# generate mint/__init__.py from mint/__init__.py.in
init_file = ""
with open(f"{PACKAGE}/__init__.py.in") as fi:
    init_file = re.sub(r"@VERSION@", VERSION, fi.read())
    with open(f"{PACKAGE}/__init__.py", "w") as fo:
        fo.write(init_file)

vtklib = getCondaVTK()
nclib = getCondaNetCDF()

cpp_flags = os.getenv("CPPFLAGS")
cxx_flags = os.getenv("CXXFLAGS")
if cxx_flags is not None:
    extra_compile_args = cxx_flags.split()
elif cpp_flags is not None:
    extra_compile_args = cpp_flags.split()
else:
    extra_compile_args = ["-std=c++11"]

print(f'VTK_VERSION          = {vtklib["VTK_VERSION"]}')
print(f'VTK_INCLUDE_DIR      = {vtklib["VTK_INCLUDE_DIR"]}')
print(f'VTK_LIBRARIES_DIR    = {vtklib["VTK_LIBRARIES_DIR"]}')
print(f'VTK_LIBRARIES        = {vtklib["VTK_LIBRARIES"]}')
print(f'NETCDF_INCLUDE_DIR   = {nclib["NETCDF_INCLUDE_DIR"]}')
print(f'NETCDF_LIBRARIES_DIR = {nclib["NETCDF_LIBRARIES_DIR"]}')
print(f'NETCDF_LIBRARIES     = {nclib["NETCDF_LIBRARIES"]}')
print(f"extra_compile_args   = {extra_compile_args}")

extensions = [
    Extension(
        f"lib{PACKAGE}",
        sources=glob.glob("src/*.cpp"),
        define_macros=[],
        include_dirs=["src/", vtklib["VTK_INCLUDE_DIR"], nclib["NETCDF_INCLUDE_DIR"]],
        libraries=vtklib["VTK_LIBRARIES"] + nclib["NETCDF_LIBRARIES"],
        library_dirs=[vtklib["VTK_INCLUDE_DIR"], nclib["NETCDF_LIBRARIES_DIR"]],
        extra_compile_args=extra_compile_args,
        language="c++",
    )
]

setup(
    ext_modules=cythonize(extensions, compiler_directives=dict(language_level=3)),
)


import numpy as np
import pandas as pd
from scipy import stats
from scipy import integrate
from scipy.optimize import curve_fit
from scipy.interpolate import interp1d
from scipy.special import erf

import matplotlib.pyplot as plt
import sys
from IPython.display import Markdown, display
from pprint import pprint
from itertools import combinations
from copy import deepcopy
import logging

from prototype_update.helper_func import *

# logger
# log levels: NOTSET, DEBUG, INFO, WARNING, ERROR, and CRITICAL
LOG_FORMAT = "%(levelname)s %(asctime)s - %(message)s"
logging.basicConfig(filename='mylog.log',
                    # level=logging.DEBUG,
                    format=LOG_FORMAT)

logger = logging.getLogger(__name__)
logger.setLevel(
    logging.CRITICAL)  # set logging level here to work in jupyter notebook where maybe a default setting was there

# model functions
def Carb_depth(t, pars):
    """ Master model function, calculate carbonation depth and the k constant of sqrt of time from all the
    parameters. The derived parameters is also calculated within this funcion. Caution: The pars instance is mutable,
    so a deepcopy of the original instance should be used if the calculation is not intended for "inplace".

    Parameters
    ----------
    t      : time [year]
    pars   : object/instance of wrapper class(empty class)
               a wrapper of all material and environmental parameters deep-copied from the raw data

    Returns
    -------
    out : carbionation depth at the time t [mm]

    Notes ----- intermediate parameters calcualted and attached to pars k_e    : environmental function [-] k_c    :
    execution transfer parameter [-] ,account for curing measures k_t    : regression parameter [-] R_ACC_0_inv:
    inverse effective carbonation resistance of concrete(accelerated) [(mm^2/year)/(kg/m^3)] eps_t  : error term [-]
    C_S    : CO2 concentration [kg/m^3] W_t    : weather function [-] k      : constant before the sqrt of time(time[
    year], carbonation depth[mm]) [mm/year^0.5] typical value of k =3~4 for unit mm,
    year [https://www.researchgate.net/publication/272174090_Carbonation_Coefficient_of_Concrete_in_Dhaka_City]
    """
    pars.t = t
    pars.k_e = k_e(pars)
    pars.k_c = k_c(pars)
    pars.k_t = k_t()
    pars.R_ACC_0_inv = R_ACC_0_inv(pars)
    pars.eps_t = eps_t()
    pars.C_S = C_S()
    pars.W_t = W_t(t, pars)

    pars.k = (2 * pars.k_e * pars.k_c * (pars.k_t * pars.R_ACC_0_inv + pars.eps_t) * pars.C_S) ** 0.5 * pars.W_t
    xc_t = pars.k * t ** 0.5
    return xc_t

# data import function
def load_df_R_ACC():
    """load the data table of the accelerated carbonation test
    for R_ACC interpolation.

    Parameters
    ----------

    Returns
    -------
    Pandas Dataframe

    Notes
    -----
    w/c 0.45 cemI is comparable to ACC of 3 mm.
    """
    wc_eqv = np.arange(0.35, 0.60 + (0.05 / 2), 0.05)
    df = pd.DataFrame(columns=['wc_eqv',  # water/cement ratio (equivalent)
                               'CEM_I_42.5_R',  # k=0
                               'CEM_I_42.5_R+FA',  # k=0.5
                               'CEM_I_42.5_R+SF',  # k=2.0
                               'CEM_III/B_42.5'])  # k=0
    df['wc_eqv'] = wc_eqv
    df['CEM_I_42.5_R'] = np.array([np.nan, 3.1, 5.2, 6.8, 9.8, 13.4])
    df['CEM_I_42.5_R+FA'] = np.array([np.nan, 0.3, 1.9, 2.4, 6.5, 8.3])
    df['CEM_I_42.5_R+SF'] = np.array([3.5, 5.5, np.nan, np.nan, 16.5, np.nan])
    df['CEM_III/B_42.5'] = np.array([np.nan, 8.3, 16.9, 26.6, 44.3, 80.0])
    df = df.set_index('wc_eqv')
    return df

def k_e(pars):
    """ Calcualte k_e[-], envrionmental factor, effect of relative humidity

    Parameters
    ----------
    pars.RH_ref : 65 [%]
    g_e    : 2.5 [-]
    f_e    : 5.0 [-]
    """
    RH_real = pars.RH_real
    RH_ref = 65.
    g_e = 2.5
    f_e = 5.0
    k_e = ((1 - (RH_real / 100) ** f_e) / (1 - (RH_ref / 100) ** f_e)) ** g_e
    return k_e

def k_c(pars):
    """ calculate k_c: execution transfer parameter [-], effect of period of curing for the accelerated carbonation test

    Parameters
    ----------
    pars.t_c: period of curing [d]
         constant
    b_c: exponent of regression [-]
         normal distribution, m: -0.567
                              s: 0.024
    """
    t_c = pars.t_c
    b_c = Normal_custom(m=-0.567, s=0.024)
    k_c = (t_c / 7.0) ** b_c
    return k_c

def R_ACC_0_inv(pars):
    """ Calculate R_ACC_0_inv[(mm^2/year)/(kg/m^3)], the inverse effective carbonation resistance of concrete(accelerated)
        From ACC test or from existion empirical data interpolation for orientation purpose
        test condition: duration time = 56 days CO2 = 2.0 vol%, T =25 degC RH_ref =65

    Parameters
    ----------
    pars.x_c : float
                measured carbonation depth in the accelerated test[m]
    pars.option.choose : bool
                if true -> choose to use interpolation method
    pars.option.df_R_ACC : pd.dataframe
                data table for interpolate, loaded by function load_df_R_ACC, interpolated by function interp_extrap_f

    Returns
    -------
    out: numpy arrays
        parameter value with sample number = N_SAMPLE(defined globally)

    Notes
    -----
    Pay special attention to the units in the source code
    """
    x_c = pars.x_c
    if (isinstance(x_c, int) or isinstance(x_c, float)):
        # though acc-test
        tau = 420.  # tau: 'time constant' in [(s/kg/m^3)^0.5], for described test conditions tau = 420
        R_ACC_0_inv_mean = (x_c / tau) ** 2  # [(m^2/s)/(kg/m^3)]

        # R_ACC_0_inv[10^-11*(m^2/s)/(kg/m^3)] ND(s = 0.69*m**0.78)
        R_ACC_0_inv_stdev = 1e-11 * 0.69 * (R_ACC_0_inv_mean * 1e11) ** 0.78  # [(m^2/s)/(kg/m^3)]

        R_ACC_0_inv_temp = Normal_custom(R_ACC_0_inv_mean, R_ACC_0_inv_stdev)  # [(m^2/s)/(kg/m^3)]

    elif pars.option.choose:
        #  'No test data, interpolate: orientation purpose'
        logger.warning('No test data, interpolate: orientation purpose')
        df = pars.option.df_R_ACC
        fit_df = df[pars.option.cement_type].dropna()

        # Curve fit
        x = fit_df.index.astype(float).values
        y = fit_df.values
        R_ACC_0_inv_mean = interp_extrap_f(x, y, pars.option.wc_eqv,
                                           plot=False) * 1e-11  # [(m^2/s)/(kg/m^3)] #interp_extrap_f: defined function

        # R_ACC_0_inv[10^-11*(m^2/s)/(kg/m^3)] ND(s = 0.69*m**0.78)
        R_ACC_0_inv_stdev = 1e-11 * 0.69 * (R_ACC_0_inv_mean * 1e11) ** 0.78  # [(m^2/s)/(kg/m^3)]

        R_ACC_0_inv_temp = Normal_custom(R_ACC_0_inv_mean, R_ACC_0_inv_stdev)  # [(m^2/s)/(kg/m^3)]

    else:
        logger.error('R_ACC_0_inv calculation failed; application interupted')

        sys.exit("Error message")
    # unit change [(m^2/s)/(kg/m^3)] -> [(mm^2/year)/(kg/m^3)]  final model input
    R_ACC_0_inv_final = 365 * 24 * 3600 * 1e6 * R_ACC_0_inv_temp
    return R_ACC_0_inv_final

# Test method factors
def k_t():
    """Calculate test method regression parameter k_t[-]

    Notes
    -----
    for R_ACC_0_inv[(mm^2/years)/(kg/m^3)]"""
    k_t = Normal_custom(1.25, 0.35)
    return k_t

def eps_t():
    """Calculate error term, eps_t[(mm^2/years)/(kg/m^3)] ,considering inaccuracies which occur conditionally when using the ACC test method  k_t[-]

    Notes
    -----
    for R_ACC_0_inv[(mm^2/years)/(kg/m^3)]"""
    eps_t = Normal_custom(315.5, 48)
    return eps_t

# Evnironmental impact C_S
def C_S(C_S_emi=0):
    """Calculate CO2 density[kg/m^3] in the environment, it is about 350-380 ppm in the atm plus other source or sink

    Parameters
    ----------
    C_S_emi : additional emission, positive or negative(sink), default is 0
    """
    C_S_atm = Normal_custom(0.00082, 0.0001)
    C_S = C_S_atm + C_S_emi
    return C_S

# weather function
def W_t(t, pars):
    """ Calcuate weather function W_t, a parameter considering the meso-climatic conditions due to wetting events of concrete surface

    Parameters
    ----------
    pars.ToW : time of wetness [-]
               ToW = (days with rainfall h_Nd >= 2.5 mm per day)/365

    pars.p_SR : probability of driving rain [-]
                Vertical -> weather station
                Horizontal 1.0
                Interior 0.0

    pars.b_w; exponent of regression [-] ND(0.446, 0.163)
    built-in param t_0 : time of reference [years]

    Returns
    -------
    out : numpy array
    """
    ToW = pars.ToW
    p_SR = pars.p_SR

    t_0 = 0.0767  # [year]
    b_w = Normal_custom(0.446, 0.163)

    W = (t_0 / t) ** ((p_SR * ToW) ** b_w / 2.0)
    return W

# helper function: calibration fucntion
def calibrate_f(model_raw, t, carb_depth_field, tol=1e-6, max_count=50, print_out=True):
    """carb_depth_field[mm]-> find corresponding x_c(accelerated test carb depth[m])
    Calibrate the carbonation model with field carbonation test data and return the new calibrated model object/instance
    Optimization metheod: searching for the best accelerated test carbonation depth x_c[m] so the model matches field data on the mean value of the carbonation depth)

    Parameters
    ----------
    model_raw : object/instance of Carbonation_Model class, mutable, so a deepcopy will be used in this function
    t         : float or int
                survey time, age of the concrete[year]
    carb_depth_field : numpy array
                       at time t, field carbonation depths[mm]
    tol : float
        accelerated carbonation depth x_c optimization tolerance, default is 1e-5 [mm]
    max_count : int
                maximun number of searching iteration, default is 50

    Returns
    -------
    out : object/instance of Carbonation_Model class
         new calibrated model
    """
    model = model_raw.copy()
    # accelrated test
    # cap
    x_c_min = 0.
    x_c_max = 0.1  # [m] unrealisticall large safe ceiling

    # optimization
    count = 0
    while x_c_max - x_c_min > tol:
        # update guess
        x_c_guess = 0.5 * (x_c_min + x_c_max)
        model.pars.x_c = x_c_guess
        model.run(t)
        carb_depth_mean = Get_mean(model.xc_t)

        # compare
        if carb_depth_mean < carb_depth_field.mean():
            # narrow the cap
            x_c_min = max(x_c_guess, x_c_min)
        else:
            x_c_max = min(x_c_guess, x_c_max)

        logger.info('carb_depth_mean:{}'.format(carb_depth_mean))
        logger.info('x_c:{}'.format(x_c_guess))
        logger.debug('cap:[{}{}]'.format(x_c_min, x_c_max))

        count += 1
        if count > max_count:
            logger.warning('iteration exceeded max {}'.format(count))
            break

    text_to_report = (
        "carb_depth:",
        '    model:
        mean:{}
        std:{}'.format(Get_mean(model.xc_t), Get_std(model.xc_t)),
        '    field:
        mean:{}
        std:{}'.format(carb_depth_field.mean(), carb_depth_field.std())
    )

    def fake_plot():
        x = np.random.randint(low=1, high=11, size=50)
        y = x + np.random.randint(1, 5, size=x.size)
        fig, ax1 = plt.subplots()
        ax1.scatter(x=x, y=y, marker='o', c='r', edgecolor='b')
        ax1.set_title('Scatter: $x$ versus $y$')
        ax1.set_xlabel('$x$')
        ax1.set_ylabel('$y$')
        buf = io.BytesIO()
        plt.savefig(buf, format='png')
        buf.seek(0)
        plt.show()
        return buf

    if print_out:
        print('carb_depth:')
        print('model: \nmean:{}\nstd:{}'.format(Get_mean(model.xc_t), Get_std(model.xc_t)))
        print('field: \nmean:{}\nstd:{}'.format(carb_depth_field.mean(), carb_depth_field.std()))

    return model, fake_plot(), text_to_report

# reprot generation function
def report_gen_f(M):
    """ M : model obj"""
    t_lis = np.arange(0, 100, 1)
    M_lis = []
    for t in t_lis:
        M.run(t)
        M_lis.append(M.copy())

    fig, [ax1, ax2, ax3] = plt.subplots(nrows=3, figsize=(8, 8), sharex=True, gridspec_kw={'height_ratios': [1, 1, 3]})
    # plot a few distrubtion
    t_plot = np.array([10, 30, 50, 70, 90]).astype('float')
    indx = [i for i, val in enumerate(t_lis) if val in set(t_plot)]
    M_sel = [M_lis[i] for i in indx]  # selected model to draw distribution

    # postproc
    for this_M in M_sel:
        this_M.postproc()
    ax1.plot([this_M.t for this_M in M_sel], [this_M.pf for this_M in M_sel], 'k--o')
    ax1.set_ylabel('Probability of failure $P_f$')
    ax2.plot([this_M.t for this_M in M_sel], [this_M.beta_factor for this_M in M_sel], 'k--o')
    ax2.set_ylabel(r'Reliability factor $\beta$')

    # plot mean results
    ax3.plot(t_lis, [M.pars.cover_mean for M in M_lis], '--C0')
    ax3.plot(t_lis, [Get_mean(M.xc_t) for M in M_lis], '--C1')
    # plot distribution
    for this_M in M_sel:
        RS_plot(this_M, ax=ax3, t_offset=this_M.t, amplify=80)

    import matplotlib.patches as mpatches
    R_patch = mpatches.Patch(color='C0', label='R: cover', alpha=0.8)
    S_patch = mpatches.Patch(color='C1', label='S: carbonation', alpha=0.8)

    ax3.set_xlabel('Time[year]')
    ax3.set_ylabel('cover/carbonation depth [mm]')
    ax3.legend(handles=[R_patch, S_patch], loc='upper left')

    plt.tight_layout()

    plot_image_buf = io.BytesIO()
    plt.savefig(plot_image_buf, format='png')
    plot_image_buf.seek(0)

    plt.show()
    # fig.savefig('RS_time_carbonation.pdf',dpi=600)

    return plot_image_buf

class Carbonation_Model:
    def __init__(self, pars):
        self.pars = pars  # pars with user-input, then updated with derived parameters
        logger.debug('\nRaw pars are {}\n'.format(vars(pars)))

    def run(self, t):
        """t[year]"""
        self.xc_t = Carb_depth(t, self.pars)
        self.t = t
        logger.info('Carbonation depth, xc_t{} mm'.format(self.xc_t))

    def postproc(self, plot=False):
        sol, report_data = Pf_RS((self.pars.cover_mean, self.pars.cover_std), self.xc_t, plot=plot)
        self.pf = sol[0]
        self.beta_factor = sol[1]
        self.R_distrib = sol[2]
        self.S_kde_fit = sol[3]
        self.S = self.xc_t
        logger.info('pf{}\n beta_factor{}'.format(self.pf, self.beta_factor))

        return report_data

    def calibrate(self, t, carb_depth_field, print_out=False):
        """return a new model instance with calibrated param"""
        model, plot, text_to_report = calibrate_f(self, t, carb_depth_field, print_out=print_out)
        return model, plot, text_to_report

    def copy(self):
        return deepcopy(self)

    def report(self):
        return report_gen_f(self)

    def load_from_session(self, session, model_key):
        model = session[model_key]

    def save_to_session(self, session, model_key):
        model_structure = {
            "xc_t": self.xc_t,
            "t": self.t,
            "pf": self.pf,
            "beta_factor": self.beta_factor,
            "R_distrib": self.R_distrib,
            "S_kde_fit": self.S_kde_fit,
            "S": self.S,
            "pars": {

            }
        }
        session[model_key] = model_structure


from scipy import misc
import numpy as np

# ************ MAIN FUNCTIONS *******************************************************************************************
# -draw(): output numpy array of pixel as image file.
# -map_sub_blobs(): given a blob and a traversing path, map all sub blobs of a specific branch belongs to that blob
# into a numpy array.
# -map_blobs(): map all blobs in blob_ into a numpy array
# -map_blob(): map all segments in blob.seg_ into a numpy array
# -map_segment(): map all Ps of a segment into a numpy array
# -over_draw(): used to draw sub-structure's map onto to current level structure
# -empty_map(): create a numpy array representing blobs' map
# ***********************************************************************************************************************

transparent_val = 127   # a pixel at this value is considered transparent

def draw(path, image, extension='.bmp'):
    ''' Output into an image file.
        Arguments:
        - path: path for saving image file.
        - image: input as numpy array.
        - extension: determine file-type of output image.
        Return: None '''

    misc.imsave(path + extension, image)
    # ---------- draw() end ---------------------------------------------------------------------------------------------

def map_sub_blobs(blob, traverse_path):
    ''' Given a blob and a traversing path, map image of all sub-blobs of a specific branch
        belonging to that blob into a numpy array.
        Arguments:
        - blob: contain all mapped sub-blobs.
        - traverse_path: list of values determine the derivation sequence of target sub-blobs.
        Return: numpy array of image's pixel '''

    image = empty_map(blob.box)

    return image
    # ---------- map_sub_blobs() end ------------------------------------------------------------------------------------

def map_frame(frame):
    ''' Map the whole frame of original image as computed blobs.
        Argument:
        - frame: frame object input (as a list).
        Return: numpy array of image's pixel '''

    blob_, (height, width) = frame[-2:]
    box = (0, height, 0, width)
    image = empty_map(box)

    for i, blob in enumerate(blob_):
        blob_map = map_blob(blob, original)

        over_draw(image, blob_map, blob.box, box)

    return image
    # ---------- map_frame() end ----------------------------------------------------------------------------------------

def map_blob(blob, original=False):
    ''' Map a single blob into an image.
        Argument:
        - blob: the input blob.
        - original: each pixel is the original image's pixel instead of just black or white to separate blobs.
        Return: numpy array of image's pixel '''

    blob_img = empty_map(blob.box)

    for seg in blob.seg_:

        y0s = seg[0]
        yns = y0s + seg[1][-1]
        x0s = min([P[1] for P in seg[2]])
        xns = max([P[1] + P[-2] for P in seg[2]])

        sub_box = (y0s, yns, x0s, xns)

        seg_map = map_segment(seg, sub_box, original)

        over_draw(blob_img, seg_map, sub_box, blob.box)

    return blob_img
    # ---------- map_blob() end -----------------------------------------------------------------------------------------

def map_segment(seg, box, original=False):
    ''' Map a single segment of a blob into an image.
        Argument:
        - seg: the input segment.
        - box: the input segment's bounding box.
        - original: each pixel is the original image's pixel instead of just black or white to separate blobs.
        Return: numpy array of image's pixel '''

    seg_img = empty_map(box)

    y0, yn, x0, xn = box

    for y, P in enumerate(seg[2], start= seg[0] - y0):
        x0P= P[1]
        x0P -= x0
        derts_ = P[-1]
        for x, derts in enumerate(derts_, start=x0P):
            if original:
                seg_img[y, x] = derts[0][0]
            else:
                seg_img[y, x] = 255 if P[0] else 0

    return seg_img

    # ---------- map_segment() end --------------------------------------------------------------------------------------

def over_draw(map, sub_map, sub_box, box = (0, 0, 0, 0)):
    ''' Over-write map of sub-structure onto map of parent-structure.
        Argument:
        - map: map of parent-structure.
        - sub_map: map of sub-structure.
        - sub_box: bounding box of sub-structure.
        - box: bounding box of parent-structure, for computing local coordinate of sub-structure.
        Return: over-written map of parent-structure '''

    y0, yn, x0, xn = box
    y0s, yns, x0s, xns = sub_box
    y0, yn, x0, xn = y0s - y0, yns - y0, x0s - x0, xns - x0
    map[y0:yn, x0:xn][sub_map != transparent_val] = sub_map[sub_map != transparent_val]
    return map
    # ---------- over_draw() end ----------------------------------------------------------------------------------------

def empty_map(shape):
    ''' Create an empty numpy array of desired shape.
        Argument:
        - shape: desired shape of the output.
        Return: over-written map of parent-structure '''

    if len(shape) == 2:
        height, width = shape
    else:
        y0, yn, x0, xn = shape
        height = yn - y0
        width = xn - x0

    return np.array([[transparent_val] * width] * height)


# Contract Bridge in python

# An information set is the record of tricks and my current hand.
# An action is the card that I am able to play given what I have.
# Observation is the card played up to now.

# a hand is an array of strings with maximum length 13, with information regarding which card is at hand
# make sure the hand is always sorted by value, with SortedSuite applied (c = 0, d = 1, h = 2, s = 3)

import numpy as np
import itertools
from collections import defaultdict

# ----------------------------------- Game Materials ----------------------------------- #
# This section is for initialzing the game rules.
# HEnce, even as epochs or tricks change, these functions should NOT be called.
# -------------------------------------------------------------------------------------- #

# Game materials are only called once and is not called again, even if the episode changes!!!
num_players = 4
# num_cards = 52 # Number of cards in the deck
# hand_size = int(num_cards / num_players)

# Number followed by corresponding suite
# cards = ['2h','3h','4h','5h','6h','7h','8h','9h','10h','Jh','Qh','Kh','Ah', # Hearts
# 		'2d','3d','4d','5d','6d','7d','8d','9d','10d','Jd','Qd','Kd','Ad', # Diamond
# 		'2c','3c','4c','5c','6c','7c','8c','9c','10c','Jc','Qc','Kc','Ac', # Clover
# 		'2s','3s','4s','5s','6s','7s','8s','9s','10s','Js','Qs','Ks','As'] # Spades

# This is to use a small case
num_cards = 20
cards = ['2h','3h','4h'
		'2d','3d','4d',
		'2c','3c','4c',
		'2s','3s','4s']
hand_size = int(num_cards / num_players)

# Given the string value of a card, return the number (2, 3, ..., 11)
def CardStrength(card):
	v = card[0]
	if v == 'A':
		ret =  11
	elif (v == 'J') or (v == 'Q') or (v == 'K'):
		ret = 10
	else:
		ret =  int(v)
	return ret

# Deck is a dictionary with values the strength of the card. (2h = 2, 2d = 2, Jh = 10, etc.)
def CreateDeck():
	deck = {}
	for card in cards:
		deck[card] = CardStrength(card)
	return deck

deck = CreateDeck()
# -------------------------------------------------------------------------------------- #
# ---------------------------------- Game Functions ------------------------------------ #
# This section is for functions that are repeatedly called for each game.
# -------------------------------------------------------------------------------------- #

# Shuffles <cards>
def Shuffle():
	global cards
	cards = np.random.shuffle(cards)

# Assign Hands randomly chosen from <cards>.
def Deal():
	return np.random.choice(cards, size = (num_players, int(num_cards / num_players)), replace = False)

# If this is the first "trick" (new epoch), initialize random player.
# If an epoch did not end but is a new trick, then winner is the next initial player
def ResetPlayer():
	global player,done
	if done is True:
		player = np.random.randint(num_players)
	else:
		player = winner
	done = False

# action is the car
def NextPlayer(action):
	global player
	player += 1
	player = player % num_players

# Return available actions of player, given by the string.
# string because value is not unique in the dict
def AvailableActions(hand):
	return deck[hand]

# Initialize random initial player AND hands
def reset():
	ResetPlayer()
	return Deal()

# Given behavioral strategy, sample pure strategy
def SampleAction(sigma):
	return np.random.choice(AvailableActions(),size = 1, p = sigma)

# Incomplete
def step():
	a = SampleAction()
	sigma = strategies

# Input: array of cards (string). assume .size > 1
# return: number corresponding to suite: (c = 0, d = 1, h = 2, s = 3)
def CompareSuites(card):
	suites = np.zeros(card.size, dtype = np.int32)
	for i in range(card.size):
		if card[i] == 'c':
			suites[i] = 0
		elif card[i] == 'd':
			suites[i] = 1
		elif card[i] == 'h':
			suites[i] = 2
		elif card[i] == 's':
			suites[i] = 3
		else:
			print('Error\n')
	return suites

# Sort a hand by number and suite. This is to keep a hand in a consistent context so that
# an information set doesn't consider two different permutations of same hand as different sets
def SortHand(hand):
	hand_vals = np.array([deck[card] for card in hand])
	sorted_args = np.argsort([deck[card] for card in hand])
	sorted_vals = hand_vals[sorted_args]
	sorted_counts = np.bincount(sorted_vals)

	# If there are no same numbers
	if np.sum(sorted_counts) == sorted_vals.size:
		return hand[sorted_args]

	for i in range(hand.size):
		sorted_counts[i] = c
		if c > 1:
			subarr = sorted_vals[i:i+c] # The subarray with repeated vals
			vs = CompareSuites(subarr)
			args = np.argsort(vs)
			sorted_args = i+args
		i += c # Skip to next suites
	return hand[sorted_args]

# -------------------------------------------------------------------------------------- #
# ------------------------------- Game Properties -------------------------------------- #
# Game Properties such as infomration sets and expected return.
# This section contains anything that is required for analysis of the game
# -------------------------------------------------------------------------------------- #

# an information set, which is an element of infsets, is a tuple (player, sorted_hand, history of what had been played)
# if the order of tricks should not affect information set, remove hist in iter/perm to iter/comb
infsets = []
for hand in itertools.combinations(cards,hand_size):
	v = list(cards) # This will hold possible histories
	for trick in range(hand_size): # number of tricks
		for hist in itertools.permutations(v, trick * num_players):
			for p in range(num_players):
				infsets.append( (p, hand, hist) )
num_infsets = len(infset)
print(num_infsets)

# Given player <player> is playing according to sigma_i and the others are the same as <strategies>
# compute the expected reward.
# This could be analytical or by simulation to estimate the expected reward
def ExpectedReward(player, sigma_i):
	pass

# Given an information set, return the hand of player i
def GetHandFromInfSet(infset):
	return infset[0]

# -------------------------------------------------------------------------------------- #
# ------------------------------------- Algorithms ------------------------------------- #
# -------------------------------------------------------------------------------------- #
# T is the number of epochs payed so far (T \geq 1)
def UpdateCFR(T):
	for i in range(num_players):
		for inf in infsets:
			my_strat = strategies[i,:]
			u2 = ExpectedReward(i,my_strat)

			hand = GetHandFromInfSet(inf)
			for a in AvailableActions(hand):
				my_strat = strategies[i,:]
				# my_strat = # Change the strategy at a given information set to a one hot vector
				# u1 = ExpectedReward(i,)

		# if T == 1:

# CFR
# def CFR():
# 	strategies =

# -------------------------------------------------------------------------------------- #
# ------------------------------------- Game Play -------------------------------------- #
# -------------------------------------------------------------------------------------- #

# Initializations
done = True
epochs = 2

# Initialize completely mixed behavioral strategies
# strategies is of shape (players, infsets)
strategies = np.random.uniform(size = (num_players,num_infsets))

# one epoch corresponds to thirteen tricks
for epoch in range(epochs):
	hands = reset()

	# for trick in range(hand_size):


from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtWidgets import QPushButton, QGraphicsSceneMouseEvent, QGraphicsTextItem, QLabel
from PyQt5.QtGui import QBrush, QColor, QFont
from PyQt5.QtCore import QTimer

from enemy_graphics_item import EnemyGraphicsItem
from tower_graphics_item import TowerGraphicsItem
from missile_graphics_item import MissileGraphicsItem
from explosion_graphics_item import ExplosionGraphicsItem
from board_graphics_item import BoardGraphicsItem
from menu_graphics_item import MenuGraphicsItem
from text_item import TextItem
from player_name import PlayerName
from load_high_scores import LoadHighScores
from build_tower_graphics_item import BuildTowerGraphicsItem
from building_slot_graphics_item import BuildingSlotGraphicsItem

from add_board_graphics import add_board_graphics
from add_high_score import add_high_score

from PyQt5.QtWidgets import QWidget, QLineEdit, QApplication

class GUI(QtWidgets.QMainWindow):

	def __init__(self, game, high_scores, high_scores_data):
		super().__init__()
		self.scene = QtWidgets.QGraphicsScene()
		self.window_size = [1900, 1200]

		self.scene.setSceneRect(0, 0, self.window_size[0], self.window_size[1])

		self.view = QtWidgets.QGraphicsView(self.scene, self)
		self.view.setBackgroundBrush(QBrush(QColor("Black")))	# Set background to black
		self.view.adjustSize()
		#self.view.show()

		self.setCentralWidget(self.view)

		#self.setCentralWidget(QtWidgets.QWidget()) 			# QMainWindown must have a centralWidget to be able to add layouts

		self.showFullScreen()
		self.showMaximized()
		self.setWindowTitle("Defence")
		#self.show()

		self.play_text_items			=	[]
		self.high_scores_text_items 	=	[]
		self.board_graphics_items 		=	[]
		self.enemy_graphics_items 		=	[]
		self.tower_base_graphics_items 	= 	[]
		self.tower_graphics_items 		=	[]
		self.missile_graphics_items 	=	[]
		self.explosion_graphics_items 	= 	[]
		self.menu_graphics_items 		=	[]
		self.buildable_graphics_items 	= 	[]
		self.building_slots 			= 	[]

		self.game = game
		self.high_scores = high_scores
		self.high_scores_data = high_scores_data
		self.square_size = game.get_board().get_square_size()
		self.main_menu_item = MenuGraphicsItem(self, "images/main_menu.png", self.window_size[0] / 10 * 9, self.window_size[1] / 10 * 9, "Main Menu")

		self.next_wave_timer = QTimer()

		self.main_menu()

		#self.init_buttons()

		#self.play()

	def get_game(self):
		return self.game

	def add_all_graphics(self):
		squares = self.game.get_board().get_squares()
		self.board_graphics_items = add_board_graphics(self.game.get_board().get_difficulty(), squares, self.square_size, self.scene)

		self.add_text_graphics_items()
		self.add_buildable_tower_graphics_items()

	def add_enemies(self):
		self.enemies_to_be_added = self.game.next_wave()

		if self.game.get_board().get_current_wave() % 10 == 0:
			current_interval = self.game.get_enemy_spawn_interval()
			new_interval = int(current_interval / 2)
			self.game.set_enemy_spawn_interval(new_interval)

	def add_enemy_graphics_item(self):
		enemy = self.enemies_to_be_added[0]
		self.enemies_to_be_added.remove(enemy)
		if self.enemies_to_be_added == []:					# If all enemies have been added, indicate that new ones can be added
			self.game.get_board().set_enemies_added()

		enemy = self.game.get_board().add_enemy(enemy, self.game.get_board().get_enemy_start_location())
		enemy_graphics_item = EnemyGraphicsItem(enemy, self.square_size)
		if enemy_graphics_item.has_shadow():
			self.scene.addItem(enemy_graphics_item.get_shadow())
		self.enemy_graphics_items.append(enemy_graphics_item)
		self.scene.addItem(enemy_graphics_item)
		self.new_enemy_timer.setSingleShot(True)
		self.new_enemy_timer.start(self.game.get_enemy_spawn_interval())

	def add_tower_base_graphics_item(self, tower):
		for item in self.buildable_graphics_items:
			item.set_building(False)

		tower_base_graphics_item = TowerGraphicsItem(tower, self.square_size)
		self.tower_base_graphics_items.append(tower_base_graphics_item)
		self.scene.addItem(tower_base_graphics_item)

		for item in self.building_slots:
			self.scene.removeItem(item)
		self.building_slots = []

	def add_explosion_graphics_item(self, location, explosion_type, time):
		explosion_graphics_item = ExplosionGraphicsItem(location, explosion_type, time, self.square_size)
		self.explosion_graphics_items.append(explosion_graphics_item)
		self.scene.addItem(explosion_graphics_item)

	def add_text_graphics_items(self):
		self.qLabel = QLabel(self)
		self.qLabel.setStyleSheet("QLabel {color : white; }")
		self.qLabel.setText("Hover over an object to receive information about it")
		self.qLabel.move(1600, 1150)
		self.qLabel.setFixedWidth(1000)
		self.qLabel.show()

		font_size = 15
		level = TextItem("Level: " + str(self.game.get_board().get_current_wave()), font_size, 20, 800)
		#time = TextItem("Time until next wave: 0", font_size, 20, 900)
		points = TextItem("Points: \n" + str(self.game.get_points()), font_size, 20, 1000)
		money = TextItem("Money: \n" + str(self.game.get_money()), font_size, 200, 1000)
		lives = TextItem("Lives: \n" + str(self.game.get_lives()), font_size, 380, 1000)
		tower_building_information = TextItem("Build a tower:", font_size, 700, 800)

		text_items = [level, points, money, lives, tower_building_information]

		for item in text_items:
			self.scene.addItem(item)
			self.play_text_items.append(item)

	def add_buildable_tower_graphics_items(self):
		cannon = BuildTowerGraphicsItem(self.game.get_tower_types()["Cannon"], 700, 900, self.square_size, self)
		machine_gun = BuildTowerGraphicsItem(self.game.get_tower_types()["MachineGun"], 900, 900, self.square_size, self)
		rocket_launcher = BuildTowerGraphicsItem(self.game.get_tower_types()["RocketLauncher"], 1100, 900, self.square_size, self)
		double_rocket_launcher = BuildTowerGraphicsItem(self.game.get_tower_types()["DoubleRocketLauncher"], 700, 1000, self.square_size, self)
		tank = BuildTowerGraphicsItem(self.game.get_tower_types()["Tank"], 900, 1000, self.square_size, self)
		leopard = BuildTowerGraphicsItem(self.game.get_tower_types()["Leopard"], 1100, 1000, self.square_size, self)

		tower_graphics_items = [cannon, machine_gun, rocket_launcher, double_rocket_launcher, tank, leopard]

		for item in tower_graphics_items:
			self.scene.addItem(item)
			self.buildable_graphics_items.append(item)

	def add_building_slots(self, tower_type):
		for item in self.buildable_graphics_items:
			item.set_building(True)

		squares = self.game.get_board().get_squares()
		for squares_list in squares:
			i = squares.index(squares_list)
			for square in squares_list:
				j = squares_list.index(square)
				if square.contains() == 0:
					slot = BuildingSlotGraphicsItem(tower_type, i, j, self.square_size, "Building_slot.png", self)
					self.scene.addItem(slot)
					self.building_slots.append(slot)

	def update_all(self):
		self.is_game_over()
		self.update_enemies()										# Firstly the enemies move
		self.update_towers(self.game.get_board().get_towers())		# Then  the towers shoot according to their targets
		self.update_missiles(self.game.get_board().get_missiles())	# Lastly the missiles that were created as well as the previously created ones move
		self.update_explosions()									# Update explosion effects
		self.update_text_graphics_items()							# Update text's that indicate game information

	def update_enemies(self):
		if self.enemies_to_be_added != []:
			if self.new_enemy_timer.remainingTime() < 0:
				self.add_enemy_graphics_item()

		enemies = self.game.get_board().get_enemies()

		if enemies == []:
			if not self.game.get_board().is_adding_enemies():		# Do not add new enemies if enemies are currently being added
				self.game.get_board().set_adding_enemies()
				self.next_wave_timer.singleShot(self.game.get_time_between_waves(), self.add_enemies)
		else:
			enemies[:] = [enemy for enemy in enemies if not enemy.is_dead()] 	# Check which enemies are dead
			enemies[:] = [enemy for enemy in enemies if not enemy.move()]		# Move the enemies

			enemy_graphics_items_to_be_removed = []

			for enemy_graphics_item in self.enemy_graphics_items:
				if enemy_graphics_item.get_enemy() in enemies:
					enemy_graphics_item.update_graphics()
				else:
					self.scene.removeItem(enemy_graphics_item)
					if enemy_graphics_item.has_shadow():
						self.scene.removeItem(enemy_graphics_item.get_shadow())
					enemy_graphics_items_to_be_removed.append(enemy_graphics_item)

			for item in enemy_graphics_items_to_be_removed:
				self.enemy_graphics_items.remove(item)

	def update_towers(self, towers):
		for tower in towers:							# Iterate through towers
			missile = tower.shoot()						# Tower shoots and creates a missile
			if missile != None:
				missile_graphics_item = MissileGraphicsItem(missile, self.square_size)			# Create graphics item for missile
				self.missile_graphics_items.append(missile_graphics_item)
				self.scene.addItem(missile_graphics_item)

		for tower_base_graphics_item in self.tower_base_graphics_items:
			tower_base_graphics_item.update_graphics()
			if tower_base_graphics_item.build():
				tower_graphics_item = TowerGraphicsItem(tower_base_graphics_item.get_tower(), self.square_size)
				self.tower_graphics_items.append(tower_graphics_item)
				self.scene.addItem(tower_graphics_item)

		for tower_graphics_item in self.tower_graphics_items:
			tower_graphics_item.update_graphics()

	def update_missiles(self, missiles):
		# Move missiles and remove those, which have reached their target or whose target has reached goal
		missiles[:] = [missile for missile in missiles if not missile.move(self.game.get_board().get_enemies(), self)]

		new_missile_graphics_items = []

		for missile_graphics_item in self.missile_graphics_items:
			if missile_graphics_item.get_missile() in missiles:
				missile_graphics_item.update_graphics()
				new_missile_graphics_items.append(missile_graphics_item)
			else:
				self.scene.removeItem(missile_graphics_item)

		self.missile_graphics_items = new_missile_graphics_items

	def update_explosions(self):
		items_to_be_removed = []
		for item in self.explosion_graphics_items:
			if item.time_passed() <= 0:
				items_to_be_removed.append(item)

		for item in items_to_be_removed:
			self.scene.removeItem(item)
			self.explosion_graphics_items.remove(item)

	def update_text_graphics_items(self):
		for item in self.buildable_graphics_items:
			if item.isUnderMouse():
				tower = item.get_tower()
				information = "Costs: " + str(tower[5]) + ", Range: " + str(tower[2]) + ", Damage: " + str(tower[1]) \
					+ ", Builds in: " + str(tower[4] / 1000) + " s" + ", Reloads in: " + str(tower[3] / 1000) + " s"
				self.qLabel.setText(information)

		for item in self.enemy_graphics_items:
			if item.isUnderMouse():
				enemy = item.get_enemy()
				information = "Type: " + str(enemy.get_type()) + ", Hitpoints: " + str(enemy.get_hitpoints()) + ", Speed: " \
					+ str(enemy.get_speed()) + ", Worth: " + str(enemy.get_worth())
				self.qLabel.setText(information)

		for item in self.tower_graphics_items:
			if item.isUnderMouse():
				target_type = item.get_tower().get_target_type()
				if target_type == 0:
					target = "first"
				elif target_type == 1:
					target = "closest"
				elif target_type == 2:
					target = "strongest"
				else:
					target = "weakest"
				information = "Tower has been set to shoot the " + target + " enemy"
				self.qLabel.setText(information)

		self.qLabel.show()

		updated_texts = ["Level: " + str(self.game.get_board().get_current_wave()), "Points: \n" + str(self.game.get_points()),
		"Money: \n" + str(self.game.get_money()), "Lives: \n" + str(self.game.get_lives()), "Build a tower:"]

		for item in self.play_text_items:
			item.set_text(updated_texts[self.play_text_items.index(item)])

	def is_game_over(self):
		if self.game.get_lives() <= 0:
			self.timer.stop()

			self.qLabel.setText("")

			for item in self.play_text_items:
				self.scene.removeItem(item)
			self.play_text_items = []
			for item in self.board_graphics_items:
				self.scene.removeItem(item)
			self.board_graphics_items = []
			for item in self.enemy_graphics_items:
				self.scene.removeItem(item)
			self.enemy_graphics_items = []
			for item in self.tower_graphics_items:
				self.scene.removeItem(item)
			self.tower_graphics_items = []
			for item in self.missile_graphics_items:
				self.scene.removeItem(item)
			self.missile_graphics_items = []
			for item in self.tower_base_graphics_items:
				self.scene.removeItem(item)
			self.tower_base_graphics_items = []
			for item in self.explosion_graphics_items:
				self.scene.removeItem(item)
			self.explosion_graphics_items = []
			for item in self.menu_graphics_items:
				self.scene.removeItem(item)
			self.menu_graphics_items = []
			for item in self.buildable_graphics_items:
				self.scene.removeItem(item)
			self.buildable_graphics_items = []
			for item in self.building_slots:
				self.scene.removeItem(item)
			self.building_slots = []

			self.level = self.game.get_board().get_current_wave()
			self.points = self.game.get_points()

			self.qLineEdit = PlayerName(self)
			text = "Game over, enter username and hit Enter. Maximum 15 charactes, whitespace not allowed"
			text_item = TextItem(text, 40, 200, 200)
			self.scene.addItem(text_item)
			self.menu_graphics_items.append(text_item)

	def check_points(self):
		name = self.qLineEdit.get_text()
		name = "".join(name.split())
		if len(name) < 1:
			name = "Nameless"
		add_high_score(self.high_scores_data, "#" + self.game.get_board().get_difficulty(), name, self.level, self.points)
		self.qLineEdit.setParent(None)
		self.game.initialize()

		self.show_high_scores()

	def main_menu(self):
		# If high scores have been viewed, remove them from the scene
		for item in self.high_scores_text_items:
			self.scene.removeItem(item)
		self.high_scores_items = []
		if self.scene.items() != []:
			self.scene.removeItem(self.main_menu_item)

		font = QFont("Comic Sans", 40)					# Set font for menu instructions
		color = QColor("White")							# Set font color
		text = "Click one of the icons to proceed"		# Set the instruction text
		menu_text = QGraphicsTextItem(text)				# Create the actual text item
		menu_text.setFont(font)
		menu_text.setDefaultTextColor(color)
		menu_text.setPos(200, 900)
		self.scene.addItem(menu_text)

		play_item = MenuGraphicsItem(self, "images/play.png", self.window_size[0] / 4, self.window_size[1] / 2, "Play")
		high_scores_item = MenuGraphicsItem(self, "images/high_scores.png", self.window_size[0] / 4 * 3, self.window_size[1] / 2, "High Scores")
		self.scene.addItem(play_item)
		self.scene.addItem(high_scores_item)

		self.menu_graphics_items.append(menu_text)
		self.menu_graphics_items.append(play_item)
		self.menu_graphics_items.append(high_scores_item)

	def choose_difficulty(self):
		# Remove menu items from scene
		for item in self.menu_graphics_items:
			self.scene.removeItem(item)
		self.menu_graphics_items = []

		easy = MenuGraphicsItem(self, "images/Easy.png", self.window_size[0] / 10, self.window_size[1] / 2, "Easy")
		medium = MenuGraphicsItem(self, "images/Medium.png", self.window_size[0] / 10 * 5, self.window_size[1] / 2, "Medium")
		hard = MenuGraphicsItem(self, "images/Hard.png", self.window_size[0] / 10 * 9, self.window_size[1] / 2, "Hard")
		self.menu_graphics_items.append(easy)
		self.menu_graphics_items.append(medium)
		self.menu_graphics_items.append(hard)

		size = 30
		instructions = ["Choose difficulty:", 50, 400, 10]
		text_for_easy = ["Easy", size, easy.pos().x(), easy.pos().y() + easy.height()]
		text_for_medium	= ["Medium", size, medium.pos().x(), medium.pos().y() + medium.height()]
		text_for_hard = ["Hard", size, hard.pos().x(), hard.pos().y() + hard.height()]
		texts = [instructions, text_for_easy, text_for_medium, text_for_hard]

		for text in texts:
			text_item = TextItem(text[0], text[1], text[2], text[3])
			self.menu_graphics_items.append(text_item)

		for item in self.menu_graphics_items:
			self.scene.addItem(item)

	def play(self):
		for item in self.menu_graphics_items:
			self.scene.removeItem(item)
		self.menu_graphics_items = []

		self.enemies_to_be_added = []
		self.new_enemy_timer = QTimer()

		self.add_all_graphics()
		self.update_all()

		# Set a timer to call the update function periodically
		self.timer = QTimer()
		self.timer.start(self.game.get_fps()) 				# Milliseconds
		self.timer.timeout.connect(self.update_all)

	def show_high_scores(self):
		for item in self.menu_graphics_items:
			self.scene.removeItem(item)

		headers = ["Easy", "Medium", "Hard"]
		x = 20

		for header in headers:
			text_item = TextItem(header, 30, x, 200)
			self.high_scores_text_items.append(text_item)
			self.scene.addItem(text_item)
			x += 600

		self.high_scores = LoadHighScores().load(self.high_scores_data)

		font_size = 12
		y = 300
		x_increment = 0

		for header in headers:
			for scores in self.high_scores[header]:
				x = 20 + x_increment
				for text in scores:
					text_item = TextItem(text, font_size, x, y)
					self.high_scores_text_items.append(text_item)
					self.scene.addItem(text_item)
					if scores.index(text) == 0:
						x += 225
					elif scores.index(text) == 1:
						x += 120
				y += font_size + 30
			x_increment += 600
			y = 300

		self.scene.addItem(self.main_menu_item)


import time
from enum import Enum

import nltk.data
from nltk.stem import WordNetLemmatizer
from nltk import word_tokenize, pos_tag
from nltk.corpus import wordnet
from nltk.tokenize import word_tokenize
from nltk.corpus import stopwords
import pickle
import os
import re
import matplotlib.pyplot as plt
import os

stop_words = ['doesnt', 'wouldnt', 'dont', 'Ive', 'I', 'Im', 'itll', 'Itll', 'thats', '``', 'X', 'Youd', 'cant', '\'\'', 'arent', 'shant', 'didnt']

# # # TODO: delete 人名
# # # TODO: adv. => adj.

class WordDifficulty(Enum):
    HighSchool = 0
    Cet4 = 1
    Cet6 = 2
    Difficult = 3

class WordList:

    def __init__(self):
        with open('./question2/english-wordlists/highschool.txt', 'r') as file:
            data = file.read().replace('\n', ' ')
        self.hs_words = dict.fromkeys(data.split(' '), True)

        with open('./question2/english-wordlists/cet4.txt', 'r') as file:
            data = file.read().replace('\n', ' ')
        self.cet4_words = dict.fromkeys(data.split(' '), True)

        with open('./question2/english-wordlists/cet6.txt', 'r') as file:
            data = file.read().replace('\n', ' ')
        self.cet6_words = dict.fromkeys(data.split(' '), True)

        print('===Word List Loaded===')

    def find(self, words):
        res = []
        for word in words:
            word = word.lower()
            # print(word)
            if word in self.hs_words:
                res.append(WordDifficulty.HighSchool)
                continue

            if word in self.cet4_words:
                res.append(WordDifficulty.Cet4)
                continue

            if word in self.cet6_words:
                res.append(WordDifficulty.Cet6)
                continue

            res.append(WordDifficulty.Difficult)
        return res

    # def clear

def get_wordnet_pos(tag): # 还原词性
    if tag.startswith('J'):
        return wordnet.ADJ
    elif tag.startswith('V'):
        return wordnet.VERB
    elif tag.startswith('N'):
        return wordnet.NOUN
    elif tag.startswith('R'):
        return wordnet.ADV
    else:
        return None

def liminate_words(sentence):
    r4 = "\\【.*?】+|\\《.*?》+|\\#.*?#+|[.!/_,$&%^*()<>+""'?@|:~{}#]+|[——！\\\，。=？、：“”‘’￥……（）《》【】]"
    cleanr = re.compile('<.*?>')
    sentence = re.sub(cleanr, ' ', sentence)  # 去除html标签
    sentence = re.sub("[0-9\[\]\\-\`\;]", "", sentence)
    sentence = re.sub('(-| +|^)M{0,9}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})( +|$)', "", sentence)
    sentence = re.sub(r4, '', sentence)  # 去除了符号
    # print(sentence)
    return sentence

def read_single_file(path):
    try:
        with open(path, "r", encoding='latin-1')as r:
            passage = ""
            for line in r:
                passage += line.strip() + ' '
    except Exception as e:
        print(path, e)
    return passage

wl = WordList()

highschool_word_set = set()
cet4_word_set = set()
cet6_word_set = set()
difficult_word_set = set()

def calc_one_sentence(sentence, count):
    sentence = liminate_words(sentence)  # 去掉符号
    tokens = word_tokenize(sentence)  # 分词
    tagged_sent = pos_tag(tokens)  # 获取单词词性

    # print(len(tokens))  # 单词数目
    wnl = WordNetLemmatizer()
    lemmas_sent = []
    for tag in tagged_sent:
        wordnet_pos = get_wordnet_pos(tag[1]) or wordnet.NOUN
        good_word = wnl.lemmatize(tag[0], pos=wordnet_pos)  # 去除词根变化

        if good_word not in stopwords.words('english') and good_word not in stop_words:  # 去掉停用词
            lemmas_sent.append(good_word)  # 词形还原

    good_tokens_difficulty = wl.find(lemmas_sent)

    for i in range(0, len(lemmas_sent)):
        d = good_tokens_difficulty[i]
        count[d] += 1
        if d == WordDifficulty.HighSchool:
            highschool_word_set.add(lemmas_sent[i])
        elif d == WordDifficulty.Cet4:
            cet4_word_set.add(lemmas_sent[i])
        elif d == WordDifficulty.Cet6:
            cet6_word_set.add(lemmas_sent[i])
        else:
            difficult_word_set.add(lemmas_sent[i])

    # for d in good_tokens_difficulty:
    #     n = 0
    #     count[d] += 1
    #
    #     if d == WordDifficulty.HighSchool:
    #         highschool_word_set.add(lemmas_sent[n])
    #     elif d == WordDifficulty.Cet4:
    #         cet4_word_set.add(lemmas_sent[n])
    #     elif d == WordDifficulty.Cet6:
    #         cet6_word_set.add(lemmas_sent[n])
    #     else:
    #         difficult_word_set.add(lemmas_sent[n])
    #     n += 1

start_time = time.time()

def print_time():
    print("--- %.2lf seconds ---" % (time.time() - start_time))

highschool = []
cet4 = []
cet6 = []
other = []

GetWordSet = False  # TODO

def calc_one_passage(psgid):  # 计算1篇文章的难度

    count = {WordDifficulty.HighSchool: 0, WordDifficulty.Cet4: 0, WordDifficulty.Cet6: 0, WordDifficulty.Difficult: 0}

    passage = read_single_file('/Users/lxy/Desktop/gg/%s.txt' % psgid)
    # print('字符数量：', len(passage))
    sentences = re.split('[.?!]', passage)
    iter = 1  # 100个句子
    for sentence in sentences:

        if iter <= 40:
            iter += 1
            continue
        # 分句，对每个句子处理
        calc_one_sentence(sentence, count)
        # print(count)
        # print(sentence, count)

        iter += 1
        # if iter > len(sentences):
        if iter > 1000:
            break
        #
        # if iter % 100 == 0:
        #     word_ratio = {WordDifficulty.HighSchool: 0, WordDifficulty.Cet4: 0, WordDifficulty.Cet6: 0,
        #                   WordDifficulty.Difficult: 0}
        #     s = 0
        #     for i in count:
        #         s += count[i]
        #
        #     for i in count:
        #         word_ratio[i] = count[i] / s
        #
        #     highschool.append(word_ratio[WordDifficulty.HighSchool])
        #     cet4.append(word_ratio[WordDifficulty.Cet4])
        #     cet6.append(word_ratio[WordDifficulty.Cet6])
        #     other.append(word_ratio[WordDifficulty.Difficult])

    # print('句子数量：', len(sentences))

    word_ratio = {WordDifficulty.HighSchool: 0, WordDifficulty.Cet4: 0, WordDifficulty.Cet6: 0, WordDifficulty.Difficult: 0}
    s = 0
    for i in count:
        s += count[i]

    for i in count:
        word_ratio[i] = count[i]/s

    # print(word_ratio)
    # print_time()

    return word_ratio

def print_word_set():
    print('highschool_word_set:', highschool_word_set)
    print('cet4_word_set:', cet4_word_set)
    print('cet6_word_set:', cet6_word_set)
    print('difficult_word_set:', difficult_word_set)

def main():
    iter = 1
    res = dict()
    for bookid in range(10, 54419):
        print('===current bookid:%s ===' % bookid)
        print('===search progress:%.4f ===' % (bookid / 54418))
        print_time()

        if not os.path.isfile('/Users/lxy/Desktop/gg/%s.txt' % bookid):
            continue

        ratio = calc_one_passage(bookid)

        print('ratio= ', ratio)

        res[bookid] = ratio

        if iter % 100 == 0:  #写回一次文件
            with open('./question2/model/dataSet.pkl', 'wb')as w:
                pickle.dump(res, w)
                print('===dump on bookid: %s===' %bookid)

        iter += 1

    # # # plot whole difficulty curve
    # ids = [50, 120, 300, 1001, 3001, 10001, 30001, 40001, 50001]
    # for bookid in ids:
    #
    #     calc_one_passage(bookid)
    #
    #
    #     plt.figure(figsize=(12, 9))
    #     ax1 = plt.subplot(2, 2, 1)  # TODO: y_scale
    #     plt.plot(highschool)
    #     ax2 = plt.subplot(2, 2, 2)
    #     plt.plot(cet4)
    #     ax3 = plt.subplot(2, 2, 3)
    #     plt.plot(cet6)
    #     ax4 = plt.subplot(2, 2, 4)
    #     plt.plot(other)
    #
    #     ax1.title.set_text('HighSchool Words Ratio')
    #     ax1.set_ylim(bottom=0, top=1)
    #     ax1.set_xlabel('hundred sentences')
    #     ax1.set_ylabel('ratio')
    #
    #     ax2.title.set_text('Cet4 Words Ratio')
    #     ax2.set_ylim(bottom=0, top=0.2)
    #     ax2.set_xlabel('hundred sentences')
    #     ax2.set_ylabel('ratio')
    #
    #     ax3.title.set_text('Cet6 Words Ratio')
    #     ax3.set_ylim(bottom=0, top=0.05)
    #     ax3.set_xlabel('hundred sentences')
    #     ax3.set_ylabel('ratio')
    #
    #     ax4.title.set_text('Other Words Ratio')
    #     ax4.set_ylim(bottom=0, top=1)
    #     ax4.set_xlabel('hundred sentences')
    #     ax4.set_ylabel('ratio')
    #
    #     plt.suptitle('Word Difficulty Curve of Book No.%d' % bookid)
    #     plt.savefig('./pics/book%d_difficulty_curve.jpg' % bookid)
    #
    #     plt.show()
    #
    #     highschool.clear()
    #     cet4.clear()
    #     cet6.clear()
    #     other.clear()

if __name__ == '__main__':
    main()


# Copyright 2014-2016 F5 Networks 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.
#

from time import time

from oslo_log import log as logging

from neutron.plugins.common import constants as plugin_const

from f5_openstack_agent.lbaasv2.drivers.bigip import listener_service
from f5_openstack_agent.lbaasv2.drivers.bigip import pool_service

LOG = logging.getLogger(__name__)

class LBaaSBuilder(object):
    # F5 LBaaS Driver using iControl for BIG-IP to
    # create objects (vips, pools) - not using an iApp."""

    def __init__(self, conf, driver, l2_service=None):
        self.conf = conf
        self.driver = driver
        self.l2_service = l2_service
        self.service_adapter = driver.service_adapter
        self.listener_builder = listener_service.ListenerServiceBuilder(
            self.service_adapter)
        self.pool_builder = pool_service.PoolServiceBuilder(
            self.service_adapter
        )

    def assure_service(self, service, traffic_group, all_subnet_hints):
        """Assure that a service is configured on the BIGIP."""

        start_time = time()
        LOG.debug("Starting assure_service")

        self._assure_loadbalancer_created(service)

        self._assure_listeners_created(service)

        self._assure_pools_created(service)

        self._assure_monitors(service)

        self._assure_members(service, all_subnet_hints)

        self._assure_pools_deleted(service)

        self._assure_listeners_deleted(service)

        self._assure_loadbalancer_deleted(service)

        LOG.debug("    _assure_service took %.5f secs" %
                  (time() - start_time))
        return all_subnet_hints

    def _assure_loadbalancer_created(self, service):
        if 'loadbalancer' not in service:
            return

        if self.driver.l3_binding:
            loadbalancer = service["loadbalancer"]
            self.driver.l3_binding.bind_address(
                subnet_id=loadbalancer["vip_subnet_id"],
                ip_address=loadbalancer["vip_address"])

    def _assure_listeners_created(self, service):
        if 'listeners' not in service:
            return

        listeners = service["listeners"]
        loadbalancer = service["loadbalancer"]
        bigips = self.driver.get_all_bigips()

        for listener in listeners:
            svc = {"loadbalancer": loadbalancer,
                   "listener": listener}
            if listener['provisioning_status'] != plugin_const.PENDING_DELETE:
                try:
                    self.listener_builder.create_listener(svc, bigips)
                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_listeners_created."
                              "Message: %s" % err.message)
                    continue

    def _assure_pools_created(self, service):
        if "pools" not in service:
            return

        pools = service["pools"]
        loadbalancer = service["loadbalancer"]

        bigips = self.driver.get_all_bigips()

        for pool in pools:
            svc = {"loadbalancer": loadbalancer,
                   "pool": pool}

            if pool['provisioning_status'] != plugin_const.PENDING_DELETE:
                try:
                    self.pool_builder.create_pool(svc, bigips)

                    if "listeners" in pool:
                        pool_name = self.service_adapter.init_pool_name(
                            loadbalancer, pool)["name"]
                        listeners = pool["listeners"]
                        for listener in listeners:
                            self._update_listener_pool(
                                service, listener["id"], pool_name, bigips)

                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_pools_created."
                              "Message: %s" % err.message)
                    continue

    def _update_listener_pool(self, service, listener_id, pool_name, bigips):
        listener = self._get_listener_by_id(service, listener_id)
        if listener is not None:
            listener["pool"] = pool_name
            svc = {"loadbalancer": service["loadbalancer"],
                   "listener": listener}
            self.listener_builder.update_listener(svc, bigips)

    def _assure_monitors(self, service):
        if not (("pools" in service) and ("healthmonitors" in service)):
            return

        monitors = service["healthmonitors"]
        loadbalancer = service["loadbalancer"]
        bigips = self.driver.get_all_bigips()

        for monitor in monitors:
            svc = {"loadbalancer": loadbalancer,
                   "healthmonitor": monitor,
                   "pool": self._get_pool_by_id(service, monitor["pool_id"])}
            if monitor['provisioning_status'] == plugin_const.PENDING_DELETE:
                try:
                    self.pool_builder.delete_healthmonitor(svc, bigips)
                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_monitors (delete)."
                              "Message: %s" % err.message)
                    continue
            else:
                try:
                    self.pool_builder.create_healthmonitor(svc, bigips)
                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_monitors (create)."
                              "Message: %s" % err.message)

    def _assure_members(self, service, all_subnet_hints):
        if not (("pools" in service) and ("members" in service)):
            return

        members = service["members"]
        loadbalancer = service["loadbalancer"]
        bigips = self.driver.get_all_bigips()

        for member in members:
            svc = {"loadbalancer": loadbalancer,
                   "member": member,
                   "pool": self._get_pool_by_id(service, member["pool_id"])}
            if member['provisioning_status'] == plugin_const.PENDING_DELETE:
                try:
                    self.pool_builder.delete_member(svc, bigips)
                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_members (delete)."
                              "Message: %s" % err.message)
                    continue
            else:
                try:
                    self.pool_builder.create_member(svc, bigips)
                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_members (create)."
                              "Message: %s" % err.message)

    def _assure_loadbalancer_deleted(self, service):
        if (service['loadbalancer']['provisioning_status'] !=
                plugin_const.PENDING_DELETE):
            return

        if self.driver.l3_binding:
            loadbalancer = service["loadbalancer"]
            self.driver.l3_binding.unbind_address(
                subnet_id=loadbalancer["vip_subnet_id"],
                ip_address=loadbalancer["vip_address"])

    def _assure_pools_deleted(self, service):
        if 'pools' not in service:
            return

        pools = service["pools"]
        loadbalancer = service["loadbalancer"]
        bigips = self.driver.get_all_bigips()

        for pool in pools:
            # Is the pool being deleted?
            if pool['provisioning_status'] == plugin_const.PENDING_DELETE:
                svc = {"loadbalancer": loadbalancer,
                       "pool": pool}
                try:
                    # remove default pool from virtual
                    if "listeners" in pool:
                        pool_name = ""
                        listeners = pool["listeners"]
                        for listener in listeners:
                            self._update_listener_pool(
                                service, listener["id"], pool_name, bigips)

                    self.pool_builder.delete_pool(svc, bigips)
                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_pools_deleted."
                              "Message: %s" % err.message)

    def _assure_listeners_deleted(self, service):
        if 'listeners' not in service:
            return

        listeners = service["listeners"]
        loadbalancer = service["loadbalancer"]
        bigips = self.driver.get_all_bigips()

        for listener in listeners:
            svc = {"loadbalancer": loadbalancer,
                   "listener": listener}
            if listener['provisioning_status'] == plugin_const.PENDING_DELETE:
                try:
                    self.listener_builder.delete_listener(svc, bigips)
                except Exception as err:
                    LOG.error("Error in "
                              "LBaaSBuilder._assure_listeners_deleted."
                              "Message: %s" % err.message)

    def _check_monitor_delete(self, service):
        # If the pool is being deleted, then delete related objects
        if service['pool']['status'] == plugin_const.PENDING_DELETE:
            # Everything needs to be go with the pool, so overwrite
            # service state to appropriately remove all elements
            service['vip']['status'] = plugin_const.PENDING_DELETE
            for member in service['members']:
                member['status'] = plugin_const.PENDING_DELETE
            for monitor in service['pool']['health_monitors_status']:
                monitor['status'] = plugin_const.PENDING_DELETE

    def _get_pool_by_id(self, service, id):
        if "pools" in service:
            pools = service["pools"]
            for pool in pools:
                if pool["id"] == id:
                    return pool
        return None

    def _get_listener_by_id(self, service, id):
        if "listeners" in service:
            listeners = service["listeners"]
            for listener in listeners:
                if listener["id"] == id:
                    return listener
        return None


# -*- coding: utf-8 -*-
"""
emotion Classifier - svm
MFCC-SVM model with json data

Functions:
loadData - load MFCC data from json file ( No noisy, Light noisy, Heavy noisy )
SVMclassifier - classify emotions by using SVM with 5-fold cross-validation
Acc - calculate the accuracy from MFCC-SVM model
roc - plot ROC curve
main - main function

Created on Sun Apr 19 12:41:09 2020
Author: Qiyang Ma
"""

#import pandas as pd
import numpy as np
import random as rd
from sklearn.svm import SVC
from sklearn.model_selection import KFold
from sklearn.metrics import auc, roc_curve
from sklearn.preprocessing import label_binarize
from scipy import interp
import matplotlib.pyplot as plt
import json

def loadData( filename ):
    # json file
    f = open( filename )
    dic = json.load( f )
    data = dic[ 'mfcc' ]
    labels = dic[ 'labels' ]
    X, y = [], []
    l = list( range( len( data ) ) )
    rd.shuffle( l )
    for i in l:
        ds = data[ i ]
        tmp = []
        for line in ds:
            tmp.extend( line )
        X.append( tmp )
        if labels[ i ] in [ 7, 8, 9, 10, 11, 12, 13 ]:
            labels[ i ] -= 7
        y.append( labels[i] )
    X = np.array( X )
    y = np.array( y )
    return X, y

def SVMclassifier( X, y ):
    # Inputs:
    # X - MFCC feature matrix
    # y - Labels as different emotion
    # Outputs:
    # mean_fpr, mean_tpr, mean_auc - the parameter for drawing roc
    kf = KFold( n_splits = 5 )
    mean_fpr = np.linspace(0, 1, 100)
    tprs = []
    c = list( range( 7 ) )
    for trainIndex, testIndex in kf.split( X ):
        Xtrain, Xtest = X[ trainIndex ], X[ testIndex ]
        ytrain, ytest = y[ trainIndex ], y[ testIndex ]
        clf = SVC( C = 50, kernel = 'rbf', gamma = 'scale' )
        yscore = clf.fit( Xtrain, ytrain ).decision_function( Xtest )
        ytest = label_binarize( ytest, classes = c )
        fpr, tpr, _ = roc_curve( ytest.ravel(), yscore.ravel() )
        interp_tpr = interp( mean_fpr, fpr, tpr )
        interp_tpr[0] = 0.0
        tprs.append( interp_tpr )
    mean_tpr = np.mean( tprs, axis = 0 )
    mean_tpr[ -1 ] = 1.0
    mean_auc = auc( mean_fpr, mean_tpr )
    return mean_fpr, mean_tpr, mean_auc

def Acc( X, y ):
    # Outputs;
    # mean_acc - accuracy of models
    kf = KFold( n_splits = 5 )
    res = []
    for trainIndex, testIndex in kf.split( X ):
        Xtrain, Xtest = X[ trainIndex ], X[ testIndex ]
        ytrain, ytest = y[ trainIndex ], y[ testIndex ]
        clf = SVC( C = 50, kernel = 'rbf', gamma = 'scale' )
        output = clf.fit( Xtrain, ytrain ).predict( Xtest )
        n, Num = 0, len( ytest )
        for i in range( Num ):
            if output[i] == ytest[ i ]:
                n += 1
                accuracy = n/Num
        res.append( accuracy )
    mean_acc = np.mean( res )
    return mean_acc

def roc( fpr, tpr, auc, color = 'darkorange', text = '' ):
    lw = 2
    plt.plot( fpr, tpr, color = color, lw = lw, \
             label = text + ' (area = %0.2f)'% auc )

def main():
    Xn, yn = loadData( 'data-no-noise.json' )
    fprn, tprn, aucn = SVMclassifier( Xn, yn )
    accn = Acc( Xn, yn )
    Xh, yh = loadData( 'data-heavy-noise.json' )
    fprh, tprh, auch = SVMclassifier( Xh, yh )
    acch = Acc( Xh, yh )
    Xl, yl = loadData( 'data-light-noise.json' )
    fprl, tprl, aucl = SVMclassifier( Xl, yl )
    accl = Acc( Xl, yl )
    plt.figure()
    roc( fprn, tprn, aucn, color = 'darkgreen', text = 'No noise' )
    roc( fprh, tprh, auch, color = 'yellow', text = 'heavy noise' )
    roc( fprl, tprl, aucl, color = 'IndianRed', text = 'light noise' )
    plt.plot( [ 0, 1 ], [ 0, 1 ], color = 'navy', lw = 2, linestyle = '--' )
    plt.xlim( [ 0.0, 1.0 ] )
    plt.ylim( [ 0.0, 1.05 ] )
    plt.xlabel( 'False Positive Rate' )
    plt.ylabel( 'True Positive Rate' )
    plt.title( 'ROC of Multi-classes from MFCC' )
    plt.legend( loc = "lower right" )
    plt.show()
    return accn, acch, accl


from __future__ import division
import matplotlib.pyplot as plt

def calc_prob(N):
    product = 1
    for i in range(366 - N + 1, 366):
        product *= i
    return product*(N - 1)/365**N

x = range(2, 367)
y = [calc_prob(N) for N in x]
plt.plot(x, y)
y_max = max(y)
x_max = x[y.index(y_max)]


'''
Plot the velocity of a car whose position is
x(t) = t^3

Let's use loops...
'''

import numpy as np
import matplotlib.pyplot as plt

# Initialise the subplot function using number of rows and columns
figure, axis = plt.subplots(1, 3)

# Generate array from 0 to 4, with step of 0.1
time = np.arange(0, 4, 0.1)

# Evaluate the position as a function of time
position_eq = lambda t: t**3
position = position_eq(time)

# Create tangential lines, evaluated in ta and tb = ta + dt
ta = 2.0
dt_array = [1.0, 0.5, 0.01]

# Position for ta:
xa = position_eq(ta)

for idx,dt in enumerate(dt_array):
    tb = ta + dt
    xb = position_eq(tb)
    v = (xb - xa) / (tb - ta)

    # Another way to use a lambda function: skip the name definition
    velocity = (lambda t: v*(t-ta) + xa)(time)

    # Generate "plt" object using plot() method, and add title.
    axis[idx].plot(time, position,'b-',linewidth=1)
    axis[idx].plot(time, velocity,'r--',linewidth=1)
    axis[idx].plot(ta, xa,'rs',fillstyle='none',markersize=12)
    axis[idx].plot(tb, xb,'ro',fillstyle='none',markersize=10)

    # Set limits for axis. If not using "plt.xlim(...)" notation, use axis[].set_...
    axis[idx].set_xlim(0,max(time))
    axis[idx].set_ylim(0,max(position))
    axis[idx].set_title(f'dt = {tb} - {ta}')

02 What is a derivative/what_is_a_derivative_condensed.py


import streamlit as st
import pandas as pd
import sys
import chone as one
import chtwo as two

def main():
    # Introduction Page
    st.title('Data Analysis Using SQL & Excel By Wiley')
    st.markdown('My Interpretation Using Dash in place of Excel')

    # A Dictionary of Topics
    ch_dict = {"1-SQL Queries & Concepts": "one",
                "2-Data Exploration": "two"}

    # SideBar Options for selecting Topics
    st.sidebar.checkbox("Topics", True, key=1)
    select = st.sidebar.selectbox('Select a Topic',df_topics)

    # Call the spesific chapter code and content
    sel_ch = ch_dict.get(select)
    #st.markdown(sel_ch)
    class_obj = str_to_class(sel_ch)
    class_obj.content()

# To convert the selected topic str to class obj to call it's content
def str_to_class(str):
    return getattr(sys.modules[__name__], str)

@st.cache(persist=True)
def fetch_data():
    df = pd.read_csv('orders.csv')
    return df

if __name__ == '__main__':
    main()


from clarifai.rest import ClarifaiApp
from flask import Flask, request, jsonify

flask_app = Flask(__name__)

app = ClarifaiApp()
model = app.models.get('PiDentify')

@flask_app.route('/')
def index():
    return 'Index Page'

@flask_app.route('/hello')
def hello():
    return 'Hello, World!'

@flask_app.route('/identify_pie')
def identify_pie():
    response = model.predict_by_url(
        'https://www.bbcgoodfood.com/sites/default/files/styles/recipe/public/recipe_images/white-chocolate-cardamom-tart-with-raspberry-dust.jpg?itok=s_QUobYD')
    return jsonify(list(response.values()))

@flask_app.route('/identify_raspi')
def identify_raspi():
    response = model.predict_by_url(
        'https://cdn.shopify.com/s/files/1/0174/1800/products/Raspberry_Pi_Zero_W_1_of_6_large.JPG?v=1539263625'
    )
    return jsonify(list(response.values()))

@flask_app.route('/identify_pi')
def identify_pi():
    response = model.predict_by_url(
        'http://www.lightboxreg.com/eventdata/3875/5aa2d19e353a0.1520619934.1119696475_bigstock--D-Pi-Symbol-10433186.jpg'
    )
    return jsonify(list(response.values()))


#! /usr/bin/python3

import numpy as np
from scipy.special import jv
from scipy.integrate import quad

import matplotlib.pyplot as plt
import sys

def func(p, omega, gamma):
    return np.cos(p*(omega**2-0.5-gamma)) * jv(0, p/2) * jv(0, gamma*p/2)**2

def g1(omega, gamma):
    return 2*omega/np.pi * quad(func, 0, 100, args=(omega, gamma))[0]

def g2(omega, gamma):
    if omega < np.pi * (3*gamma / (4*np.pi))**(1/3):
        return 4 * omega**2 / (np.pi**2 * gamma)
    else:
        return 0

def main(args):
    gamma = 1/float(args[1])
    print(gamma)

    omega_data = np.linspace(0, 2, 1024)
    g1_data = np.zeros(1024)
    g2_data = np.zeros(1024)

    for i, omega in np.ndenumerate(omega_data):
        g1_data[i] = g1(omega, gamma)
        g2_data[i] = g2(omega, gamma)

    plt.plot(omega_data, g1_data, omega_data, g2_data)
    plt.show()

if __name__ == '__main__':
    main(sys.argv)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import unittest

from click.testing import CliRunner

from punica.cli import main
from punica.utils.file_system import ensure_remove_dir_if_exists

class TestCompileCmd(unittest.TestCase):
    def test_compile(self):
        project_path = os.path.join(os.path.dirname(__file__), 'data', 'test_compile_init_box')
        runner = CliRunner()
        try:
            os.mkdir(project_path)
            result = runner.invoke(main, ['-p', project_path, 'init'])
            self.assertEqual(0, result.exit_code)
            init_info = ['Downloading...', 'Unpacking...', 'Unbox successful. Enjoy it!']
            info_list = result.output.split('\n')
            for index, info in enumerate(init_info):
                self.assertEqual(info, info_list[index])
            result = runner.invoke(main, ['-p', project_path, 'compile'])
            self.assertEqual(0, result.exit_code)
            compile_info = ['Compiling...', 'Compile hello_ontology.py', 'Compiled, Thank you',
                            'Generate avm file successful...']
            info_list = result.output.split('\n')
            for index, info in enumerate(compile_info):
                self.assertEqual(info, info_list[index])
        finally:
            ensure_remove_dir_if_exists(project_path)

if __name__ == '__main__':
    unittest.main()


# -*- coding: utf-8 -*-
import random
import string

from django.db import models
# from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy as _

class Trade(models.Model):
    """Model to represent Trade object.

    A Trade has the following fields:
    - id: string with the format 'TR\w{7}'
    - sell_currency: string
    - sell_amount: string
    - buy_currency:
    - buy_amount:
    - rate: decimal
    - date_booked: related to 3 hashtags at most
    """

    # Currencies available in the api.
    CURRENCY_TYPE = (
        ('AUD', _('Australian dollar')),
        ('BGN', _('Bulgarian lev')),
        ('BRL', _('Brazilian real')),
        ('CAD', _('Canadian dollar')),
        ('CHF', _('Swiss franc')),
        ('CNY', _('Chinese yuan')),
        ('CZK', _('Czech koruna')),
        ('DKK', _('Danish krone')),
        ('EUR', _('Euro')),
        ('GBP', _('Pound sterling')),
        ('HKD', _('Hong Kong dollar')),
        ('HRK', _('Croatian kuna')),
        ('HUF', _('Hungarian forint')),
        ('IDR', _('Indonesian rupiah')),
        ('ILS', _('Israeli new shekel')),
        ('INR', _('Indian rupee')),
        ('JPY', _('Japanese yen')),
        ('KRW', _('South Korean won')),
        ('MXN', _('Mexican peso')),
        ('MYR', _('Malaysian ringgit')),
        ('NOK', _('Norwegian krone')),
        ('NZD', _('New Zealand dollar')),
        ('PHP', _('Philippine peso')),
        ('PLN', _('Polish zloty')),
        ('RON', _('Romanian leu')),
        ('RUB', _('Russian ruble')),
        ('SEK', _('Swedish krona')),
        ('SGD', _('Singapore dollar')),
        ('THB', _('Thai baht')),
        ('TRY', _('Turkish lira')),
        ('USD', _('United States dollar')),
        ('ZAR', _('South African rand')),
    )

    ID_PREFIX = "TR"
    ID_MAX_LENGTH = 9

    # Please note that `max_length` has no effect for sqlite database
    id = models.CharField(primary_key=True, max_length=ID_MAX_LENGTH, editable=False)
    sell_currency = models.CharField(_('Sell currency'), choices=CURRENCY_TYPE, blank=False, null=False, max_length=3)
    sell_amount = models.FloatField(_('Sell amount'), blank=False, null=False)
    buy_currency = models.CharField(_('Buy currency'), choices=CURRENCY_TYPE, blank=False, null=False, max_length=3)
    # This value is calculated with sell_amount and rate.
    #  It is stored to not calculate every time the object is requested
    buy_amount = models.FloatField(_('Buy amount'), blank=False, null=False)
    rate = models.FloatField(_('Rate'), blank=False, null=False)
    date_booked = models.DateTimeField(_('Date booked'), blank=False, null=False, auto_now=True)

    def __str__(self):
        return self.id

    def save(self, *args, **kwargs):
        # If not pk, then the instance doesn't exist in database yet. Generate corresponding id then.
        if not self.pk:
            self.id = self._gen_custom_id()

        super(Trade, self).save(*args, **kwargs)

    @classmethod
    def _gen_custom_id(cls):
        """Generates a string with format 'TR\w{7}' for Trade id.

        :return: String with format 'TR\w{7}'
        :rtype: str
        """
        new_id = None
        max_aphnum_len = cls.ID_MAX_LENGTH - len(cls.ID_PREFIX)

        while new_id is None:
            random_aphnum = ''.join(random.choice(string.digits + string.ascii_uppercase)
                                    for _ in range(max_aphnum_len))
            new_id = "{}{}".format(cls.ID_PREFIX, random_aphnum)

            if cls.objects.filter(id=new_id).exists():
                new_id = None

        return new_id


# This script uses the Google-Search-API found at
# https://github.com/abenassi/Google-Search-API
from google import google
import csv
import re
import time
import random

#Opens the csv. Change the csv name each time you want to
#write into a new file for a different conference.

csvv = open('csfwebsites2019.csv','w')

#Opens the csv of names that have been manually gathered
#from the conference page. Can be done for any list of names, however.

with open('csfnames2019.csv', 'r') as csvfile:
    num_page = 1
    spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')

    # For each row in the csv you're reading from, make sure the format
    # is clean and then send it into the google.search() function.
    # search_results[0].link takes the link of only the first result,
    # which is most commonly the prof's personal website.

    for row in spamreader:
        row = " ".join(row)
        row = row.replace('"','')
        print(row)
        ele = str(row)
        if ele == "":
            pass
        else:
            search_results = google.search(ele,num_page)
            print(search_results)
            try:
                i = str(search_results[0].link)
                print(i)
                csvv.write(i)
                csvv.write('\n')
            except:
                print (ele + 'FAILED')

            # This section is crucial, as if you do not put a sleep
            # between runs of your loop Google will detect you
            # and block your script from running.

            timenow = random.randrange(20,80)
            print(timenow)
            time.sleep(timenow)

csvv.close()


""" Custom Indicator Increase In  Volume
"""

import math

import pandas
from talib import abstract

from analyzers.utils import IndicatorUtils

class MACrossover(IndicatorUtils):

    def analyze(self, historical_data, signal=['close'], hot_thresh=None, cold_thresh=None, exponential=True, ma_fast=10, ma_slow=50):
        """Performs an analysis about the increase in volumen on the historical data

        Args:
            historical_data (list): A matrix of historical OHCLV data.
            signal (list, optional): Defaults to close. Unused in this indicator
            exponential (boolean): flag to indicate is EMA is used
            ma_fast (integer): periods to use to calculate the fast MA
            ma_slow (integer): periods to use to calculate the slow MA

        Returns:
            pandas.DataFrame: A dataframe containing the indicator and hot/cold values.
        """

        dataframe = self.convert_to_dataframe(historical_data)

        if exponential == True:
            ma_fast_values = abstract.EMA(dataframe, ma_fast)
            ma_slow_values = abstract.EMA(dataframe, ma_slow)
        else:
            ma_fast_values = abstract.SMA(dataframe, ma_fast)
            ma_slow_values = abstract.SMA(dataframe, ma_slow)

        ma_crossover = pandas.concat(
            [dataframe, ma_fast_values, ma_slow_values], axis=1)
        ma_crossover.rename(
            columns={0: 'fast_values', 1: 'slow_values'}, inplace=True)

        previous_fast, previous_slow = ma_crossover.iloc[-2]['fast_values'], ma_crossover.iloc[-2]['slow_values']
        current_fast, current_slow = ma_crossover.iloc[-1]['fast_values'], ma_crossover.iloc[-1]['slow_values']

        ma_crossover['is_hot'] = False
        ma_crossover['is_cold'] = False

        ma_crossover['is_hot'].iloc[-1] = previous_fast < previous_slow and current_fast > current_slow
        ma_crossover['is_cold'].iloc[-1] = previous_fast > previous_slow and current_fast < current_slow

        return ma_crossover


import cv2
import numpy as np
import datetime
from matplotlib import pyplot as plt
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
#img = cv2.imread('girl2.jpg')
cap = cv2.VideoCapture('test3.mp4')
line_length_prev = 0
line_length_curr = 0
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('covid19.avi',fourcc,20.0,(1280,720))
while True:
    ret,img = cap.read()
    try:
        boxes, weights = hog.detectMultiScale(img,winStride=(8,8))
    except:
        pass
    else:
        for (x, y, w, h) in boxes:
            if w > 110:
                cv2.rectangle(img, (x, y), (x+w, y+h),(0, 255, 0), 2)
                cv2.circle(img,(x+int(w/2),y+int(h/2)),3,(0,0,255),3)
        if len(boxes)>1:
            x1,y1,w1,h1 = boxes[0]
            x2,y2,w2,h2 = boxes[1]

            if w1 > 110 and w2>110:
                line_length_prev = line_length_curr
                line_length_curr = int(((x1+(w1/2)-x2-(w2/2))**2 + (y1+(h1/2)-y2-(h2/2))**2)**0.5)
                if line_length_curr < line_length_prev/2:
                    continue
                cv2.line(img,(x1+int(w1/2),y1+int(h1/2)),(x2+int(w2/2),y2+int(h2/2)),(255,0,0),3)
                min = (h2, h1) [h1 < h2]
                max = (h1, h2) [h1 < h2]
                cv2.putText(img,"current distance between them : "+str(line_length_curr),(10,20),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),3)
                cv2.putText(img,'minor object height : '+str(min),(10,60),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),3)
                cv2.putText(img,'major object height : '+str(max),(10,100),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255),3)
                if line_length_curr < max:
                    cv2.putText(img,'too close!!',(600,300),cv2.FONT_HERSHEY_SIMPLEX,2,(0,0,255),3)
    finally:
        if ret==True:
            cv2.imshow('frame',img)
            out.write(img)
    if cv2.waitKey(1)==27:
        break
cap.release()
out.release()
cv2.destroyAllWindows()